mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 16:44:45 +00:00
fix(models): explain missing provider model registration
This commit is contained in:
@@ -66,6 +66,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/Anthropic: report 1M session context for Claude Opus/Sonnet 4 models even when local model config still advertises 200k, matching model discovery and preventing premature status/UI overflow. Fixes #66766.
|
||||
- Models/OpenRouter: hide missing-auth direct provider rows in `/model status` when they are only duplicated by a nested OpenRouter model id such as `openrouter/google/...`, while preserving explicitly configured direct providers. Fixes #62317.
|
||||
- Models: preserve an explicitly selected provider/model such as `opencode-go/deepseek-v4-pro` when another provider owns the same bare model alias. Fixes #79325.
|
||||
- Models/config: explain missing `models.providers.<provider>.models[]` registration when a model exists only in `agents.defaults.models`, instead of returning a bare unknown-model error. Fixes #80089.
|
||||
- Kimi Code: use Kimi's stable `kimi-for-coding` API model id in bundled catalog, onboarding, and docs while normalizing legacy `kimi-code` and `k2p5` refs. Fixes #79965.
|
||||
- Volcengine/Kimi: strip provider-unsupported tool schema length and item constraint keywords for direct and coding-plan models so hosted Kimi runs do not reject message tools with `minLength`. Fixes #38817.
|
||||
- DeepSeek: backfill V4 `reasoning_content` replay fields for unowned OpenAI-compatible proxy providers, preventing follow-up request failures outside the bundled DeepSeek and OpenRouter routes. Fixes #79608.
|
||||
|
||||
@@ -348,6 +348,8 @@ Many of the bundled provider plugins below already publish a default catalog. Us
|
||||
|
||||
Gateway model capability checks also read explicit `models.providers.<id>.models[]` metadata. If a custom or proxy model accepts images, set `input: ["text", "image"]` on that model so WebChat and node-origin attachment paths pass images as native model inputs instead of text-only media refs.
|
||||
|
||||
`agents.defaults.models["provider/model"]` only controls model visibility, aliases, and per-model metadata for agents. It does not register a new runtime model by itself. For custom provider models, also add `models.providers.<provider>.models[]` with at least the matching `id`.
|
||||
|
||||
### Moonshot AI (Kimi)
|
||||
|
||||
Moonshot ships as a bundled provider plugin. Use the built-in provider by default, and add an explicit `models.providers.moonshot` entry only when you need to override the base URL or model metadata:
|
||||
|
||||
@@ -1146,6 +1146,30 @@ describe("resolveModel", () => {
|
||||
expect(result.model?.input).toEqual(["text"]);
|
||||
});
|
||||
|
||||
it("explains when an agent model entry is missing provider model registration", async () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"microsoft-foundry/Kimi-K2.6-1": {
|
||||
contextWindow: 262144,
|
||||
maxOutputTokens: 16384,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as OpenClawConfig;
|
||||
|
||||
const result = await resolveModelAsync("microsoft-foundry", "Kimi-K2.6-1", "/tmp/agent", cfg, {
|
||||
runtimeHooks: createRuntimeHooks(),
|
||||
skipPiDiscovery: true,
|
||||
});
|
||||
|
||||
expect(result.error).toBe(
|
||||
'Unknown model: microsoft-foundry/Kimi-K2.6-1. Found agents.defaults.models["microsoft-foundry/Kimi-K2.6-1"], but no matching models.providers["microsoft-foundry"].models[] entry. Add { "id": "Kimi-K2.6-1" } to models.providers["microsoft-foundry"].models[] to register this provider model.',
|
||||
);
|
||||
});
|
||||
|
||||
it("repairs stale text-only Foundry fallback rows for GPT-family models", () => {
|
||||
const cfg = {
|
||||
models: {
|
||||
|
||||
@@ -1223,6 +1223,14 @@ function buildUnknownModelError(params: {
|
||||
return suppressed;
|
||||
}
|
||||
const base = `Unknown model: ${params.provider}/${params.modelId}`;
|
||||
const registrationHint = buildMissingProviderModelRegistrationHint({
|
||||
provider: params.provider,
|
||||
modelId: params.modelId,
|
||||
cfg: params.cfg,
|
||||
});
|
||||
if (registrationHint) {
|
||||
return `${base}. ${registrationHint}`;
|
||||
}
|
||||
const runtimeHooks = params.runtimeHooks ?? DEFAULT_PROVIDER_RUNTIME_HOOKS;
|
||||
const hint = runtimeHooks.buildProviderUnknownModelHintWithPlugin({
|
||||
provider: params.provider,
|
||||
@@ -1240,3 +1248,37 @@ function buildUnknownModelError(params: {
|
||||
});
|
||||
return hint ? `${base}. ${hint}` : base;
|
||||
}
|
||||
|
||||
function buildMissingProviderModelRegistrationHint(params: {
|
||||
provider: string;
|
||||
modelId: string;
|
||||
cfg?: OpenClawConfig;
|
||||
}): string | undefined {
|
||||
const configuredModels = params.cfg?.agents?.defaults?.models;
|
||||
if (!configuredModels) {
|
||||
return undefined;
|
||||
}
|
||||
const agentModelKey = modelKey(params.provider, params.modelId);
|
||||
if (
|
||||
!configuredModels[agentModelKey] &&
|
||||
!configuredModels[`${params.provider}/${params.modelId}`]
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const providerConfig = findNormalizedProviderValue(
|
||||
params.cfg?.models?.providers,
|
||||
params.provider,
|
||||
) as { models?: unknown } | undefined;
|
||||
const providerModels = Array.isArray(providerConfig?.models) ? providerConfig.models : [];
|
||||
const hasProviderModel = providerModels.some((entry) => {
|
||||
if (!entry || typeof entry !== "object" || !("id" in entry)) {
|
||||
return false;
|
||||
}
|
||||
const id = (entry as { id?: unknown }).id;
|
||||
return typeof id === "string" && id === params.modelId;
|
||||
});
|
||||
if (hasProviderModel) {
|
||||
return undefined;
|
||||
}
|
||||
return `Found agents.defaults.models["${agentModelKey}"], but no matching models.providers["${params.provider}"].models[] entry. Add { "id": "${params.modelId}" } to models.providers["${params.provider}"].models[] to register this provider model.`;
|
||||
}
|
||||
|
||||
@@ -515,7 +515,7 @@ describe("/model chat UX", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
} as unknown as OpenClawConfig,
|
||||
allowedModelCatalog: [
|
||||
{ provider: "anthropic", id: "claude-opus-4-6", name: "Claude Opus 4.5" },
|
||||
{ provider: "openai", id: "gpt-4.1-mini", name: "GPT-4.1 mini" },
|
||||
@@ -546,7 +546,7 @@ describe("/model chat UX", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
} as unknown as OpenClawConfig,
|
||||
allowedModelCatalog: [
|
||||
{ provider: "google", id: "gemini-3-flash-preview", name: "Gemini 3 Flash" },
|
||||
{
|
||||
@@ -584,7 +584,7 @@ describe("/model chat UX", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
} as unknown as OpenClawConfig,
|
||||
allowedModelCatalog: [
|
||||
{ provider: "google", id: "gemini-3-flash-preview", name: "Gemini 3 Flash" },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user