Sessions: infer wrapper provider for legacy slash models

This commit is contained in:
Gustavo Madeira Santana 2026-02-24 22:41:01 -05:00
parent ed2b33681c
commit f0953a7284
4 changed files with 85 additions and 8 deletions

View File

@ -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", () => {

View File

@ -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;

View File

@ -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<string, SessionEntry> = {
"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<string, SessionEntry> = {

View File

@ -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 };