From 8bca9fd828d7a120cc0262a56d9f147aa6a42e23 Mon Sep 17 00:00:00 2001 From: manikv12 Date: Fri, 30 Jan 2026 01:23:54 -0600 Subject: [PATCH 1/2] fix: enable image input for Kimi K2.5 and refresh stale config model definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kimi K2.5 supports vision but was declared text-only in both the synthetic catalog and the moonshot provider. More importantly, onboarding bakes the full model catalog into openclaw.json, and the old merge logic let stale config definitions shadow code updates — so even after fixing the catalog, existing users would never see the change. Fix mergeProviderModels so code-defined capability fields (input, reasoning, contextWindow, maxTokens) override stale config entries while preserving user-specific fields (cost, headers, compat, apiKey). Follow-up to 5e635c9 (#4407). --- src/agents/models-config.providers.ts | 2 +- src/agents/models-config.ts | 37 +++++++++++++++++++-------- src/agents/synthetic-models.ts | 2 +- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index 0cd034c82..05dd12556 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -288,7 +288,7 @@ function buildMoonshotProvider(): ProviderConfig { id: MOONSHOT_DEFAULT_MODEL_ID, name: "Kimi K2.5", reasoning: false, - input: ["text"], + input: ["text", "image"], cost: MOONSHOT_DEFAULT_COST, contextWindow: MOONSHOT_DEFAULT_CONTEXT_WINDOW, maxTokens: MOONSHOT_DEFAULT_MAX_TOKENS, diff --git a/src/agents/models-config.ts b/src/agents/models-config.ts index 22c21af94..384699b51 100644 --- a/src/agents/models-config.ts +++ b/src/agents/models-config.ts @@ -29,18 +29,33 @@ function mergeProviderModels(implicit: ProviderConfig, explicit: ProviderConfig) const id = (model as { id?: unknown }).id; return typeof id === "string" ? id.trim() : ""; }; - const seen = new Set(explicitModels.map(getId).filter(Boolean)); - const mergedModels = [ - ...explicitModels, - ...implicitModels.filter((model) => { - const id = getId(model); - if (!id) return false; - if (seen.has(id)) return false; - seen.add(id); - return true; - }), - ]; + // Build a lookup of implicit (code-defined) models by ID so we can + // refresh stale config-written definitions with up-to-date capability + // fields (input, reasoning, contextWindow, maxTokens) while preserving + // any user-specific overrides (cost, headers, compat). + const implicitById = new Map( + implicitModels.map((m) => [getId(m), m] as const).filter(([id]) => id), + ); + + const seen = new Set(); + const mergedModels = explicitModels.map((explicitModel) => { + const id = getId(explicitModel); + if (id) seen.add(id); + const implicitModel = id ? implicitById.get(id) : undefined; + if (!implicitModel) return explicitModel; + // Merge: code-defined capability fields override stale config values, + // while config-only fields (cost, headers, compat) are preserved. + return { ...explicitModel, ...implicitModel }; + }); + + // Append implicit models whose IDs are not present in the explicit list. + for (const model of implicitModels) { + const id = getId(model); + if (!id || seen.has(id)) continue; + seen.add(id); + mergedModels.push(model); + } return { ...implicit, diff --git a/src/agents/synthetic-models.ts b/src/agents/synthetic-models.ts index 9b9247805..1cc7051a6 100644 --- a/src/agents/synthetic-models.ts +++ b/src/agents/synthetic-models.ts @@ -103,7 +103,7 @@ export const SYNTHETIC_MODEL_CATALOG = [ id: "hf:moonshotai/Kimi-K2.5", name: "Kimi K2.5", reasoning: true, - input: ["text"], + input: ["text", "image"], contextWindow: 256000, maxTokens: 8192, }, From 8cfd73718678d71447a3fb2732fa2cfceb2d0f9c Mon Sep 17 00:00:00 2001 From: manikv12 Date: Fri, 30 Jan 2026 01:29:41 -0600 Subject: [PATCH 2/2] fix: preserve user overrides (cost, headers, compat) during model merge Only override capability fields (input, reasoning, contextWindow, maxTokens) from code; spread explicitModel first so user-specific fields like cost, headers, and compat are preserved. --- src/agents/models-config.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/agents/models-config.ts b/src/agents/models-config.ts index 384699b51..6f9cb3a49 100644 --- a/src/agents/models-config.ts +++ b/src/agents/models-config.ts @@ -45,8 +45,14 @@ function mergeProviderModels(implicit: ProviderConfig, explicit: ProviderConfig) const implicitModel = id ? implicitById.get(id) : undefined; if (!implicitModel) return explicitModel; // Merge: code-defined capability fields override stale config values, - // while config-only fields (cost, headers, compat) are preserved. - return { ...explicitModel, ...implicitModel }; + // while user-specific fields (cost, headers, compat) are preserved. + return { + ...explicitModel, + input: implicitModel.input, + reasoning: implicitModel.reasoning, + contextWindow: implicitModel.contextWindow, + maxTokens: implicitModel.maxTokens, + }; }); // Append implicit models whose IDs are not present in the explicit list.