From f0953a72845fb3f9e8745cb6ab476cea7a5cd98b Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Tue, 24 Feb 2026 22:41:01 -0500 Subject: [PATCH] Sessions: infer wrapper provider for legacy slash models --- src/agents/model-selection.test.ts | 19 ++++++++++ src/agents/model-selection.ts | 2 +- src/gateway/session-utils.test.ts | 57 ++++++++++++++++++++++++++++++ src/gateway/session-utils.ts | 15 ++++---- 4 files changed, 85 insertions(+), 8 deletions(-) diff --git a/src/agents/model-selection.test.ts b/src/agents/model-selection.test.ts index f657764f313..8a80768c0db 100644 --- a/src/agents/model-selection.test.ts +++ b/src/agents/model-selection.test.ts @@ -193,6 +193,25 @@ describe("model-selection", () => { }), ).toBeUndefined(); }); + + it("infers provider for slash-containing model id when allowlist match is unique", () => { + const cfg = { + agents: { + defaults: { + models: { + "vercel-ai-gateway/anthropic/claude-sonnet-4-6": {}, + }, + }, + }, + } as OpenClawConfig; + + expect( + inferUniqueProviderFromConfiguredModels({ + cfg, + model: "anthropic/claude-sonnet-4-6", + }), + ).toBe("vercel-ai-gateway"); + }); }); describe("buildModelAliasIndex", () => { diff --git a/src/agents/model-selection.ts b/src/agents/model-selection.ts index cf66d1d1c68..ac45200039f 100644 --- a/src/agents/model-selection.ts +++ b/src/agents/model-selection.ts @@ -176,7 +176,7 @@ export function inferUniqueProviderFromConfiguredModels(params: { model: string; }): string | undefined { const model = params.model.trim(); - if (!model || model.includes("/")) { + if (!model) { return undefined; } const configuredModels = params.cfg.agents?.defaults?.models; diff --git a/src/gateway/session-utils.test.ts b/src/gateway/session-utils.test.ts index 1af536850b2..b86e3be142e 100644 --- a/src/gateway/session-utils.test.ts +++ b/src/gateway/session-utils.test.ts @@ -468,6 +468,31 @@ describe("resolveSessionModelIdentityRef", () => { expect(resolved).toEqual({ provider: "anthropic", model: "claude-sonnet-4-6" }); }); + + test("infers wrapper provider for slash-prefixed runtime model when allowlist match is unique", () => { + const cfg = { + agents: { + defaults: { + model: { primary: "google-gemini-cli/gemini-3-pro-preview" }, + models: { + "vercel-ai-gateway/anthropic/claude-sonnet-4-6": {}, + }, + }, + }, + } as OpenClawConfig; + + const resolved = resolveSessionModelIdentityRef(cfg, { + sessionId: "slash-model", + updatedAt: Date.now(), + model: "anthropic/claude-sonnet-4-6", + modelProvider: undefined, + }); + + expect(resolved).toEqual({ + provider: "vercel-ai-gateway", + model: "anthropic/claude-sonnet-4-6", + }); + }); }); describe("deriveSessionTitle", () => { @@ -719,6 +744,38 @@ describe("listSessionsFromStore search", () => { expect(result.sessions[0]?.model).toBe("claude-sonnet-4-6"); }); + test("infers wrapper provider for slash-prefixed legacy runtime model when allowlist match is unique", () => { + const cfg = { + session: { mainKey: "main" }, + agents: { + defaults: { + model: { primary: "google-gemini-cli/gemini-3-pro-preview" }, + models: { + "vercel-ai-gateway/anthropic/claude-sonnet-4-6": {}, + }, + }, + }, + } as OpenClawConfig; + const now = Date.now(); + const store: Record = { + "agent:main:main": { + sessionId: "sess-main", + updatedAt: now, + model: "anthropic/claude-sonnet-4-6", + } as SessionEntry, + }; + + const result = listSessionsFromStore({ + cfg, + storePath: "/tmp/sessions.json", + store, + opts: {}, + }); + + expect(result.sessions[0]?.modelProvider).toBe("vercel-ai-gateway"); + expect(result.sessions[0]?.model).toBe("anthropic/claude-sonnet-4-6"); + }); + test("exposes unknown totals when freshness is stale or missing", () => { const now = Date.now(); const store: Record = { diff --git a/src/gateway/session-utils.ts b/src/gateway/session-utils.ts index c1505642742..14165ab2875 100644 --- a/src/gateway/session-utils.ts +++ b/src/gateway/session-utils.ts @@ -706,6 +706,13 @@ export function resolveSessionModelIdentityRef( if (runtimeProvider) { return { provider: runtimeProvider, model: runtimeModel }; } + const inferredProvider = inferUniqueProviderFromConfiguredModels({ + cfg, + model: runtimeModel, + }); + if (inferredProvider) { + return { provider: inferredProvider, model: runtimeModel }; + } if (runtimeModel.includes("/")) { const parsedRuntime = parseModelRef(runtimeModel, DEFAULT_PROVIDER); if (parsedRuntime) { @@ -713,13 +720,7 @@ export function resolveSessionModelIdentityRef( } return { model: runtimeModel }; } - const inferredProvider = inferUniqueProviderFromConfiguredModels({ - cfg, - model: runtimeModel, - }); - return inferredProvider - ? { provider: inferredProvider, model: runtimeModel } - : { model: runtimeModel }; + return { model: runtimeModel }; } const resolved = resolveSessionModelRef(cfg, entry, agentId); return { provider: resolved.provider, model: resolved.model };