From 2f7e6ec196fd0e60c57e57ea64201c650af60180 Mon Sep 17 00:00:00 2001 From: tynamite <35367599+tynamite@users.noreply.github.com> Date: Sun, 31 May 2026 14:01:25 +0100 Subject: [PATCH] fix(auto-reply): honor per-model thinking params Auto-reply now uses the existing per-model model params thinking value before falling back to the global thinkingDefault, matching gateway/shared model selection behavior.\n\nVerified with targeted auto-reply and agents Vitest coverage plus formatting and diff checks.\n\nThanks @tynamite for the fix. --- src/auto-reply/reply/model-selection.test.ts | 37 ++++++++++++++++++++ src/auto-reply/reply/model-selection.ts | 29 +++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/auto-reply/reply/model-selection.test.ts b/src/auto-reply/reply/model-selection.test.ts index 89224947520..7f3ad02c737 100644 --- a/src/auto-reply/reply/model-selection.test.ts +++ b/src/auto-reply/reply/model-selection.test.ts @@ -108,6 +108,43 @@ describe("createModelSelectionState catalog loading", () => { expect(loadModelCatalog).not.toHaveBeenCalled(); }); + it("prefers per-model params.thinking over global thinkingDefault", async () => { + vi.mocked(loadModelCatalog).mockClear(); + const cfg = { + agents: { + defaults: { + thinkingDefault: "low", + models: { + "openai-codex/gpt-5.4": { + params: { thinking: "high" }, + }, + }, + }, + }, + models: { + providers: { + "openai-codex": { + baseUrl: "https://api.openai.com/v1", + models: [makeConfiguredModel()], + }, + }, + }, + } as OpenClawConfig; + + const state = await createModelSelectionState({ + cfg, + agentCfg: cfg.agents?.defaults, + defaultProvider: "openai-codex", + defaultModel: "gpt-5.4", + provider: "openai-codex", + model: "gpt-5.4", + hasModelDirective: false, + }); + + await expect(state.resolveDefaultThinkingLevel()).resolves.toBe("high"); + expect(loadModelCatalog).not.toHaveBeenCalled(); + }); + it("uses the implicit model default when no global thinking default is configured", async () => { vi.mocked(loadModelCatalog).mockClear(); const cfg = { diff --git a/src/auto-reply/reply/model-selection.ts b/src/auto-reply/reply/model-selection.ts index 618bbee23c7..1631d010187 100644 --- a/src/auto-reply/reply/model-selection.ts +++ b/src/auto-reply/reply/model-selection.ts @@ -7,6 +7,7 @@ import type { ModelCatalogEntry } from "../../agents/model-catalog.js"; import { parseConfiguredModelVisibilityEntries } from "../../agents/model-selection-shared.js"; import { buildConfiguredModelCatalog, + legacyModelKey, modelKey, normalizeModelRef, normalizeProviderId, @@ -458,10 +459,32 @@ export async function createModelSelectionState(params: { return defaultThinkingLevel; } const agentThinkingDefault = agentEntry?.thinkingDefault as ThinkLevel | undefined; + if (agentThinkingDefault) { + defaultThinkingLevel = agentThinkingDefault; + return defaultThinkingLevel; + } + const configuredModels = cfg.agents?.defaults?.models; + const canonicalKey = modelKey(provider, model); + const legacyKey = legacyModelKey(provider, model); + const configuredModelThinkingDefault = + configuredModels?.[canonicalKey]?.params?.thinking ?? + (legacyKey ? configuredModels?.[legacyKey]?.params?.thinking : undefined); + if ( + configuredModelThinkingDefault === "off" || + configuredModelThinkingDefault === "minimal" || + configuredModelThinkingDefault === "low" || + configuredModelThinkingDefault === "medium" || + configuredModelThinkingDefault === "high" || + configuredModelThinkingDefault === "xhigh" || + configuredModelThinkingDefault === "adaptive" || + configuredModelThinkingDefault === "max" + ) { + defaultThinkingLevel = configuredModelThinkingDefault; + return defaultThinkingLevel; + } const configuredThinkingDefault = agentCfg?.thinkingDefault as ThinkLevel | undefined; - const explicitThinkingDefault = agentThinkingDefault ?? configuredThinkingDefault; - if (explicitThinkingDefault) { - defaultThinkingLevel = explicitThinkingDefault; + if (configuredThinkingDefault) { + defaultThinkingLevel = configuredThinkingDefault; return defaultThinkingLevel; } const catalogForThinking = await resolveThinkingCatalog();