Skip to content

Commit ce7027b

Browse files
committed
fix(model): hint at missing models.providers block in Unknown model error
When a model is registered in agents.defaults.models but the provider has no models.providers[].models[] entry, the 'Unknown model' error now explains that both config blocks are required. Closes #80089
1 parent cb207f9 commit ce7027b

2 files changed

Lines changed: 80 additions & 1 deletion

File tree

src/agents/pi-embedded-runner/model.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,4 +2410,52 @@ describe("resolveModel", () => {
24102410
baseUrl: "https://api.x.ai/v1",
24112411
});
24122412
});
2413+
2414+
it("hints at missing models.providers block when model is in agents.defaults.models only (#80089)", () => {
2415+
const cfg = {
2416+
agents: {
2417+
defaults: {
2418+
models: {
2419+
"microsoft-foundry/Kimi-K2.6-1": {
2420+
contextWindow: 262144,
2421+
maxOutputTokens: 16384,
2422+
},
2423+
},
2424+
},
2425+
},
2426+
models: {
2427+
providers: {},
2428+
},
2429+
} as never;
2430+
2431+
const result = resolveModel("microsoft-foundry", "Kimi-K2.6-1", "/tmp/agent", cfg, {
2432+
authStorage: { mocked: true } as never,
2433+
modelRegistry: discoverModels({ mocked: true } as never, "/tmp/agent"),
2434+
runtimeHooks: {
2435+
applyProviderResolvedModelCompatWithPlugins: () => undefined,
2436+
buildProviderUnknownModelHintWithPlugin: () => undefined,
2437+
prepareProviderDynamicModel: async () => {},
2438+
runProviderDynamicModel: () => undefined,
2439+
applyProviderResolvedTransportWithPlugin: () => undefined,
2440+
normalizeProviderResolvedModelWithPlugin: () => undefined,
2441+
normalizeProviderTransportWithPlugin: () => undefined,
2442+
},
2443+
});
2444+
2445+
expect(result.model).toBeUndefined();
2446+
expect(result.error).toContain("Unknown model: microsoft-foundry/Kimi-K2.6-1");
2447+
expect(result.error).toContain("agents.defaults.models");
2448+
expect(result.error).toContain('models.providers["microsoft-foundry"].models[]');
2449+
});
2450+
2451+
it("does not hint at providers block when model is not in agents.defaults.models", () => {
2452+
const result = resolveModel("mistral", "mistral-medium-3-5", "/tmp/agent", undefined, {
2453+
authStorage: { mocked: true } as never,
2454+
modelRegistry: discoverModels({ mocked: true } as never, "/tmp/agent"),
2455+
runtimeHooks: createRuntimeHooks(),
2456+
});
2457+
2458+
expect(result.model).toBeUndefined();
2459+
expect(result.error).toBe("Unknown model: mistral/mistral-medium-3-5");
2460+
});
24132461
});

src/agents/pi-embedded-runner/model.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,11 @@ function buildUnknownModelError(params: {
12231223
return suppressed;
12241224
}
12251225
const base = `Unknown model: ${params.provider}/${params.modelId}`;
1226+
const configHints = buildUnknownModelConfigHints({
1227+
provider: params.provider,
1228+
modelId: params.modelId,
1229+
cfg: params.cfg,
1230+
});
12261231
const runtimeHooks = params.runtimeHooks ?? DEFAULT_PROVIDER_RUNTIME_HOOKS;
12271232
const hint = runtimeHooks.buildProviderUnknownModelHintWithPlugin({
12281233
provider: params.provider,
@@ -1238,5 +1243,31 @@ function buildUnknownModelError(params: {
12381243
modelId: params.modelId,
12391244
},
12401245
});
1241-
return hint ? `${base}. ${hint}` : base;
1246+
const parts = [base, ...configHints];
1247+
if (hint) {
1248+
parts.push(hint);
1249+
}
1250+
return parts.join(". ");
1251+
}
1252+
1253+
function buildUnknownModelConfigHints(params: {
1254+
provider: string;
1255+
modelId: string;
1256+
cfg?: OpenClawConfig;
1257+
}): string[] {
1258+
const hints: string[] = [];
1259+
const key = `${params.provider}/${params.modelId}`;
1260+
const defaultsModels = params.cfg?.agents?.defaults?.models;
1261+
const inDefaultsModels = defaultsModels && key in defaultsModels;
1262+
const providerConfig = params.cfg?.models?.providers?.[params.provider];
1263+
const providerModels =
1264+
providerConfig && typeof providerConfig === "object" ? providerConfig.models : undefined;
1265+
const hasProviderModels = Array.isArray(providerModels) && providerModels.length > 0;
1266+
if (inDefaultsModels && !hasProviderModels) {
1267+
hints.push(
1268+
`Found in agents.defaults.models but not in models.providers["${params.provider}"].models[]. ` +
1269+
"Both blocks are required to register a model with a provider plugin",
1270+
);
1271+
}
1272+
return hints;
12421273
}

0 commit comments

Comments
 (0)