diff --git a/src/gateway/session-utils.test.ts b/src/gateway/session-utils.test.ts index 182250d8b90..3be5494d840 100644 --- a/src/gateway/session-utils.test.ts +++ b/src/gateway/session-utils.test.ts @@ -1450,13 +1450,19 @@ describe("listSessionsFromStore selected model display", () => { test("uses qualified selected defaults for rows without runtime model metadata", () => { const cfg = { agents: { - defaults: { model: { primary: "openai/gpt-5.4" } }, + defaults: { + model: { primary: "openai/gpt-5.4" }, + models: { + "anthropic/claude-sonnet-4-6": { alias: "sonnet" }, + }, + }, list: [ { id: "main", model: { primary: "anthropic/claude-sonnet-4-6" } }, { id: "review", model: { primary: "vercel-ai-gateway/anthropic/claude-haiku-4-5" }, }, + { id: "alias", model: { primary: "anthropic/sonnet-4.6" } }, ], }, } as OpenClawConfig; @@ -1473,6 +1479,10 @@ describe("listSessionsFromStore selected model display", () => { sessionId: "sess-review", updatedAt: 1, } as SessionEntry, + "agent:alias:alias": { + sessionId: "sess-alias", + updatedAt: 0, + } as SessionEntry, }, opts: {}, }); @@ -1482,6 +1492,7 @@ describe("listSessionsFromStore selected model display", () => { ).toEqual([ ["agent:main:main", "anthropic", "claude-sonnet-4-6"], ["agent:review:review", "vercel-ai-gateway", "anthropic/claude-haiku-4-5"], + ["agent:alias:alias", "anthropic", "claude-sonnet-4-6"], ]); }); diff --git a/src/gateway/session-utils.ts b/src/gateway/session-utils.ts index f18e5818677..cc906716362 100644 --- a/src/gateway/session-utils.ts +++ b/src/gateway/session-utils.ts @@ -19,7 +19,6 @@ import { import { inferUniqueProviderFromConfiguredModels, isCliProvider, - normalizeProviderId, normalizeStoredOverrideModel, parseModelRef, resolveConfiguredModelRef, @@ -78,7 +77,6 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalLowercaseString, - resolvePrimaryStringValue, } from "../shared/string-coerce.js"; import { normalizeSessionDeliveryFields } from "../utils/delivery-context.shared.js"; import { estimateUsageCost, resolveModelCostConfig } from "../utils/usage-format.js"; @@ -375,7 +373,7 @@ type SessionListRowContext = { subagentRuns: ReturnType; storeChildSessionsByKey: Map; selectedModelByOverrideRef: Map>; - modelIdentityByEntryKey: Map>; + modelIdentityByResolutionKey: Map>; thinkingLevelsByModelRef: Map>; }; @@ -494,7 +492,7 @@ function buildSessionListRowContext(params: { subagentRuns, storeChildSessionsByKey: buildStoreChildSessionIndex(params.store, params.now, subagentRuns), selectedModelByOverrideRef: new Map(), - modelIdentityByEntryKey: new Map(), + modelIdentityByResolutionKey: new Map(), thinkingLevelsByModelRef: new Map(), }; } @@ -503,27 +501,6 @@ function createSessionRowModelCacheKey(provider: string | undefined, model: stri return `${normalizeLowercaseStringOrEmpty(provider)}\0${normalizeOptionalString(model) ?? ""}`; } -function parseQualifiedModelRefForSessionList( - raw: string | undefined, -): { provider: string; model: string } | undefined { - const trimmed = normalizeOptionalString(raw); - const slash = trimmed?.indexOf("/") ?? -1; - if (!trimmed || slash <= 0 || slash === trimmed.length - 1) { - return undefined; - } - const provider = normalizeProviderId(trimmed.slice(0, slash).trim()); - const model = normalizeOptionalString(trimmed.slice(slash + 1)); - return model ? { provider, model } : undefined; -} - -function createSessionDefaultModelCacheKey(cfg: OpenClawConfig, agentId?: string): string { - const normalizedAgentId = normalizeAgentId(agentId); - const primary = normalizedAgentId - ? resolveAgentEffectiveModelPrimary(cfg, normalizedAgentId) - : resolvePrimaryStringValue(cfg.agents?.defaults?.model); - return normalizeOptionalString(primary) ?? ""; -} - function createSessionEntryModelCacheKey(params: { cfg: OpenClawConfig; agentId?: string; @@ -533,7 +510,7 @@ function createSessionEntryModelCacheKey(params: { fallbackModelRef?: string; }) { return [ - createSessionDefaultModelCacheKey(params.cfg, params.agentId), + normalizeAgentId(params.agentId), normalizeOptionalString(params.entry?.providerOverride) ?? "", normalizeOptionalString(params.entry?.modelOverride) ?? "", normalizeOptionalString(params.entry?.modelProvider) ?? "", @@ -547,11 +524,6 @@ function resolveSessionDefaultModelRefForRow( agentId?: string, ): { provider: string; model: string } { if (agentId) { - const primary = resolveAgentEffectiveModelPrimary(cfg, agentId)?.trim(); - const parsed = parseQualifiedModelRefForSessionList(primary); - if (parsed) { - return parsed; - } return resolveDefaultModelForAgent({ cfg, agentId }); } return resolveConfiguredModelRef({ @@ -581,9 +553,39 @@ function resolveSessionRowModelIdentityRef(params: { const runtimeModel = normalizeOptionalString(params.entry?.model); const runtimeProvider = normalizeOptionalString(params.entry?.modelProvider); const fallbackModelRef = normalizeOptionalString(params.fallbackModelRef); - if (runtimeModel && runtimeProvider && !fallbackModelRef) { + if (runtimeModel && runtimeProvider) { return { provider: runtimeProvider, model: runtimeModel }; } + if (runtimeModel) { + const key = `runtime\0${runtimeModel}`; + const cached = params.rowContext.modelIdentityByResolutionKey.get(key); + if (cached) { + return cached; + } + const resolved = resolveSessionModelIdentityRef( + params.cfg, + params.entry, + params.agentId, + params.fallbackModelRef, + ); + params.rowContext.modelIdentityByResolutionKey.set(key, resolved); + return resolved; + } + if (fallbackModelRef) { + const key = `fallback\0${fallbackModelRef}`; + const cached = params.rowContext.modelIdentityByResolutionKey.get(key); + if (cached) { + return cached; + } + const resolved = resolveSessionModelIdentityRef( + params.cfg, + params.entry, + params.agentId, + params.fallbackModelRef, + ); + params.rowContext.modelIdentityByResolutionKey.set(key, resolved); + return resolved; + } const normalizedOverride = normalizeStoredOverrideModel({ providerOverride: params.entry?.providerOverride, modelOverride: params.entry?.modelOverride, @@ -605,7 +607,7 @@ function resolveSessionRowModelIdentityRef(params: { entry: params.entry, fallbackModelRef: params.fallbackModelRef, }); - const cached = params.rowContext.modelIdentityByEntryKey.get(key); + const cached = params.rowContext.modelIdentityByResolutionKey.get(key); if (cached) { return cached; } @@ -618,7 +620,7 @@ function resolveSessionRowModelIdentityRef(params: { !normalizedOverride.modelOverride ) { const resolved = resolveSessionDefaultModelRefForRow(params.cfg, params.agentId); - params.rowContext.modelIdentityByEntryKey.set(key, resolved); + params.rowContext.modelIdentityByResolutionKey.set(key, resolved); return resolved; } @@ -628,7 +630,7 @@ function resolveSessionRowModelIdentityRef(params: { params.agentId, params.fallbackModelRef, ); - params.rowContext.modelIdentityByEntryKey.set(key, resolved); + params.rowContext.modelIdentityByResolutionKey.set(key, resolved); return resolved; }