mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:30:43 +00:00
fix(image): resolve custom provider model IDs
This commit is contained in:
@@ -145,5 +145,11 @@ export function resolveProviderVisionModelFromConfig(params: {
|
||||
const models = providerCfg?.models ?? [];
|
||||
const picked = models.find((m) => Boolean((m?.id ?? "").trim()) && m.input?.includes("image"));
|
||||
const id = (picked?.id ?? "").trim();
|
||||
return id ? `${params.provider}/${id}` : null;
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
const slash = id.indexOf("/");
|
||||
const idProvider = slash === -1 ? "" : normalizeLowercaseStringOrEmpty(id.slice(0, slash));
|
||||
const selectedProvider = normalizeLowercaseStringOrEmpty(params.provider);
|
||||
return idProvider && idProvider === selectedProvider ? id : `${params.provider}/${id}`;
|
||||
}
|
||||
|
||||
@@ -708,6 +708,35 @@ describe("image tool implicit imageModel config", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not double-prefix custom provider model IDs that already include the provider", async () => {
|
||||
await withTempAgentDir(async (agentDir) => {
|
||||
await writeAuthProfiles(agentDir, {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"kimchi:default": { type: "api_key", provider: "kimchi", key: "sk-test" },
|
||||
},
|
||||
});
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: { defaults: { model: { primary: "kimchi/text-1" } } },
|
||||
models: {
|
||||
providers: {
|
||||
kimchi: {
|
||||
baseUrl: "https://example.com",
|
||||
models: [
|
||||
makeModelDefinition("kimchi/text-1", ["text"]),
|
||||
makeModelDefinition("kimchi/vision-1", ["text", "image"]),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(resolveImageModelConfigForTool({ cfg, agentDir })).toEqual({
|
||||
primary: "kimchi/vision-1",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("pairs a provider when config uses an alias key", async () => {
|
||||
await withTempAgentDir(async (agentDir) => {
|
||||
await writeAuthProfiles(agentDir, {
|
||||
|
||||
@@ -27,4 +27,21 @@ describe("resolveModelFromRegistry", () => {
|
||||
}),
|
||||
).toThrow("Unknown model: ollama/qwen3.5:397b-cloud");
|
||||
});
|
||||
|
||||
it("falls back to provider-prefixed custom model IDs", () => {
|
||||
const foundModel = { provider: "kimchi", id: "kimchi/claude-opus-4-6" };
|
||||
const find = vi.fn().mockReturnValueOnce(null).mockReturnValueOnce(foundModel);
|
||||
|
||||
const result = resolveModelFromRegistry({
|
||||
modelRegistry: { find },
|
||||
provider: "kimchi",
|
||||
modelId: "claude-opus-4-6",
|
||||
});
|
||||
|
||||
expect(find.mock.calls).toEqual([
|
||||
["kimchi", "claude-opus-4-6"],
|
||||
["kimchi", "kimchi/claude-opus-4-6"],
|
||||
]);
|
||||
expect(result).toBe(foundModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -402,10 +402,16 @@ export function resolveModelFromRegistry(params: {
|
||||
modelId: string;
|
||||
}): Model<Api> {
|
||||
const resolvedRef = normalizeModelRef(params.provider, params.modelId);
|
||||
const model = params.modelRegistry.find(
|
||||
let model = params.modelRegistry.find(
|
||||
resolvedRef.provider,
|
||||
resolvedRef.model,
|
||||
) as Model<Api> | null;
|
||||
if (!model && !resolvedRef.model.includes("/")) {
|
||||
model = params.modelRegistry.find(
|
||||
resolvedRef.provider,
|
||||
`${resolvedRef.provider}/${resolvedRef.model}`,
|
||||
) as Model<Api> | null;
|
||||
}
|
||||
if (!model) {
|
||||
throw new Error(`Unknown model: ${resolvedRef.provider}/${resolvedRef.model}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user