Skip to content

Commit f0953a7

Browse files
committed
Sessions: infer wrapper provider for legacy slash models
1 parent ed2b336 commit f0953a7

4 files changed

Lines changed: 85 additions & 8 deletions

File tree

src/agents/model-selection.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,25 @@ describe("model-selection", () => {
193193
}),
194194
).toBeUndefined();
195195
});
196+
197+
it("infers provider for slash-containing model id when allowlist match is unique", () => {
198+
const cfg = {
199+
agents: {
200+
defaults: {
201+
models: {
202+
"vercel-ai-gateway/anthropic/claude-sonnet-4-6": {},
203+
},
204+
},
205+
},
206+
} as OpenClawConfig;
207+
208+
expect(
209+
inferUniqueProviderFromConfiguredModels({
210+
cfg,
211+
model: "anthropic/claude-sonnet-4-6",
212+
}),
213+
).toBe("vercel-ai-gateway");
214+
});
196215
});
197216

198217
describe("buildModelAliasIndex", () => {

src/agents/model-selection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export function inferUniqueProviderFromConfiguredModels(params: {
176176
model: string;
177177
}): string | undefined {
178178
const model = params.model.trim();
179-
if (!model || model.includes("/")) {
179+
if (!model) {
180180
return undefined;
181181
}
182182
const configuredModels = params.cfg.agents?.defaults?.models;

src/gateway/session-utils.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,31 @@ describe("resolveSessionModelIdentityRef", () => {
468468

469469
expect(resolved).toEqual({ provider: "anthropic", model: "claude-sonnet-4-6" });
470470
});
471+
472+
test("infers wrapper provider for slash-prefixed runtime model when allowlist match is unique", () => {
473+
const cfg = {
474+
agents: {
475+
defaults: {
476+
model: { primary: "google-gemini-cli/gemini-3-pro-preview" },
477+
models: {
478+
"vercel-ai-gateway/anthropic/claude-sonnet-4-6": {},
479+
},
480+
},
481+
},
482+
} as OpenClawConfig;
483+
484+
const resolved = resolveSessionModelIdentityRef(cfg, {
485+
sessionId: "slash-model",
486+
updatedAt: Date.now(),
487+
model: "anthropic/claude-sonnet-4-6",
488+
modelProvider: undefined,
489+
});
490+
491+
expect(resolved).toEqual({
492+
provider: "vercel-ai-gateway",
493+
model: "anthropic/claude-sonnet-4-6",
494+
});
495+
});
471496
});
472497

473498
describe("deriveSessionTitle", () => {
@@ -719,6 +744,38 @@ describe("listSessionsFromStore search", () => {
719744
expect(result.sessions[0]?.model).toBe("claude-sonnet-4-6");
720745
});
721746

747+
test("infers wrapper provider for slash-prefixed legacy runtime model when allowlist match is unique", () => {
748+
const cfg = {
749+
session: { mainKey: "main" },
750+
agents: {
751+
defaults: {
752+
model: { primary: "google-gemini-cli/gemini-3-pro-preview" },
753+
models: {
754+
"vercel-ai-gateway/anthropic/claude-sonnet-4-6": {},
755+
},
756+
},
757+
},
758+
} as OpenClawConfig;
759+
const now = Date.now();
760+
const store: Record<string, SessionEntry> = {
761+
"agent:main:main": {
762+
sessionId: "sess-main",
763+
updatedAt: now,
764+
model: "anthropic/claude-sonnet-4-6",
765+
} as SessionEntry,
766+
};
767+
768+
const result = listSessionsFromStore({
769+
cfg,
770+
storePath: "/tmp/sessions.json",
771+
store,
772+
opts: {},
773+
});
774+
775+
expect(result.sessions[0]?.modelProvider).toBe("vercel-ai-gateway");
776+
expect(result.sessions[0]?.model).toBe("anthropic/claude-sonnet-4-6");
777+
});
778+
722779
test("exposes unknown totals when freshness is stale or missing", () => {
723780
const now = Date.now();
724781
const store: Record<string, SessionEntry> = {

src/gateway/session-utils.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -706,20 +706,21 @@ export function resolveSessionModelIdentityRef(
706706
if (runtimeProvider) {
707707
return { provider: runtimeProvider, model: runtimeModel };
708708
}
709+
const inferredProvider = inferUniqueProviderFromConfiguredModels({
710+
cfg,
711+
model: runtimeModel,
712+
});
713+
if (inferredProvider) {
714+
return { provider: inferredProvider, model: runtimeModel };
715+
}
709716
if (runtimeModel.includes("/")) {
710717
const parsedRuntime = parseModelRef(runtimeModel, DEFAULT_PROVIDER);
711718
if (parsedRuntime) {
712719
return { provider: parsedRuntime.provider, model: parsedRuntime.model };
713720
}
714721
return { model: runtimeModel };
715722
}
716-
const inferredProvider = inferUniqueProviderFromConfiguredModels({
717-
cfg,
718-
model: runtimeModel,
719-
});
720-
return inferredProvider
721-
? { provider: inferredProvider, model: runtimeModel }
722-
: { model: runtimeModel };
723+
return { model: runtimeModel };
723724
}
724725
const resolved = resolveSessionModelRef(cfg, entry, agentId);
725726
return { provider: resolved.provider, model: resolved.model };

0 commit comments

Comments
 (0)