diff --git a/docs/tools/thinking.md b/docs/tools/thinking.md index 22cced0a5ba..91c3359f552 100644 --- a/docs/tools/thinking.md +++ b/docs/tools/thinking.md @@ -15,13 +15,14 @@ title: "Thinking Levels" - low → “think hard” - medium → “think harder” - high → “ultrathink” (max budget) - - xhigh → “ultrathink+” (GPT-5.2 + Codex models and Anthropic Claude Opus 4.7) - - adaptive → provider-managed adaptive reasoning budget (supported for Anthropic Claude 4.6 and Opus 4.7) + - xhigh → “ultrathink+” (GPT-5.2 + Codex models and Anthropic Claude Opus 4.7 effort) + - adaptive → provider-managed adaptive thinking (supported for Anthropic Claude 4.6 and Opus 4.7) - `x-high`, `x_high`, `extra-high`, `extra high`, and `extra_high` map to `xhigh`. - `highest`, `max` map to `high`. - Provider notes: - - Anthropic Claude 4.6 and Opus 4.7 models default to `adaptive` when no explicit thinking level is set. - - Anthropic Claude Opus 4.7 maps `/think xhigh` to `output_config.effort: "xhigh"`. + - Anthropic Claude 4.6 models default to `adaptive` when no explicit thinking level is set. + - Anthropic Claude Opus 4.7 does not default to adaptive thinking. Its API effort default remains provider-owned unless you explicitly set a thinking level. + - Anthropic Claude Opus 4.7 maps `/think xhigh` to adaptive thinking plus `output_config.effort: "xhigh"`, because `/think` is a thinking directive and `xhigh` is the Opus 4.7 effort setting. - MiniMax (`minimax/*`) on the Anthropic-compatible streaming path defaults to `thinking: { type: "disabled" }` unless you explicitly set thinking in model params or request params. This avoids leaked `reasoning_content` deltas from MiniMax's non-native Anthropic stream format. - Z.AI (`zai/*`) only supports binary thinking (`on`/`off`). Any non-`off` level is treated as `on` (mapped to `low`). - Moonshot (`moonshot/*`) maps `/think off` to `thinking: { type: "disabled" }` and any non-`off` level to `thinking: { type: "enabled" }`. When thinking is enabled, Moonshot only accepts `tool_choice` `auto|none`; OpenClaw normalizes incompatible values to `auto`. @@ -32,7 +33,7 @@ title: "Thinking Levels" 2. Session override (set by sending a directive-only message). 3. Per-agent default (`agents.list[].thinkingDefault` in config). 4. Global default (`agents.defaults.thinkingDefault` in config). -5. Fallback: `adaptive` for Anthropic Claude 4.6 and Opus 4.7 models, `low` for other reasoning-capable models, `off` otherwise. +5. Fallback: `adaptive` for Anthropic Claude 4.6 models, `off` for Anthropic Claude Opus 4.7 unless explicitly configured, `low` for other reasoning-capable models, `off` otherwise. ## Setting a session default @@ -105,7 +106,7 @@ title: "Thinking Levels" - The web chat thinking selector mirrors the session's stored level from the inbound session store/config when the page loads. - Picking another level writes the session override immediately via `sessions.patch`; it does not wait for the next send and it is not a one-shot `thinkingOnce` override. -- The first option is always `Default ()`, where the resolved default comes from the active session model: `adaptive` for Claude 4.6 and Opus 4.7 on Anthropic, `low` for other reasoning-capable models, `off` otherwise. +- The first option is always `Default ()`, where the resolved default comes from the active session model: `adaptive` for Claude 4.6 on Anthropic, `off` for Anthropic Claude Opus 4.7 unless configured, `low` for other reasoning-capable models, `off` otherwise. - The picker stays provider-aware: - most providers show `off | minimal | low | medium | high | adaptive` - Anthropic Claude Opus 4.7 shows `off | minimal | low | medium | high | xhigh | adaptive` diff --git a/extensions/anthropic/index.test.ts b/extensions/anthropic/index.test.ts index c8ec785be1f..daaa429d0de 100644 --- a/extensions/anthropic/index.test.ts +++ b/extensions/anthropic/index.test.ts @@ -199,6 +199,12 @@ describe("anthropic provider replay hooks", () => { provider: "anthropic", modelId: "claude-opus-4-7", } as never), + ).toBe("off"); + expect( + provider.resolveDefaultThinkingLevel?.({ + provider: "anthropic", + modelId: "claude-opus-4-6", + } as never), ).toBe("adaptive"); expect( provider.supportsXHighThinking?.({ diff --git a/extensions/anthropic/register.runtime.ts b/extensions/anthropic/register.runtime.ts index 79e13d96d66..510ffaf2883 100644 --- a/extensions/anthropic/register.runtime.ts +++ b/extensions/anthropic/register.runtime.ts @@ -260,7 +260,6 @@ function resolveAnthropicForwardCompatModel( function shouldUseAnthropicAdaptiveThinkingDefault(modelId: string): boolean { const lowerModelId = normalizeLowercaseStringOrEmpty(modelId); return ( - isAnthropicOpus47Model(lowerModelId) || lowerModelId.startsWith(ANTHROPIC_OPUS_46_MODEL_ID) || lowerModelId.startsWith(ANTHROPIC_OPUS_46_DOT_MODEL_ID) || lowerModelId.startsWith(ANTHROPIC_SONNET_46_MODEL_ID) || @@ -491,9 +490,11 @@ export function registerAnthropicPlugin(api: OpenClawPluginApi): void { supportsXHighThinking: ({ modelId }) => isAnthropicOpus47Model(modelId), wrapStreamFn: wrapAnthropicProviderStream, resolveDefaultThinkingLevel: ({ modelId }) => - matchesAnthropicModernModel(modelId) && shouldUseAnthropicAdaptiveThinkingDefault(modelId) - ? "adaptive" - : undefined, + isAnthropicOpus47Model(modelId) + ? "off" + : matchesAnthropicModernModel(modelId) && shouldUseAnthropicAdaptiveThinkingDefault(modelId) + ? "adaptive" + : undefined, resolveUsageAuth: async (ctx) => await ctx.resolveOAuthToken(), fetchUsageSnapshot: async (ctx) => await fetchClaudeUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn), diff --git a/src/agents/model-selection.test.ts b/src/agents/model-selection.test.ts index 51df92af395..e7e0d350434 100644 --- a/src/agents/model-selection.test.ts +++ b/src/agents/model-selection.test.ts @@ -1176,7 +1176,7 @@ describe("model-selection", () => { expect(resolveAnthropicOpusThinking(cfg)).toBe("adaptive"); }); - it("uses adaptive fallback for explicitly configured Anthropic Opus 4.7", () => { + it("keeps thinking off by default for explicitly configured Anthropic Opus 4.7", () => { const cfg = { agents: { defaults: { @@ -1185,7 +1185,7 @@ describe("model-selection", () => { }, } as OpenClawConfig; - expect(resolveAnthropicOpus47Thinking(cfg)).toBe("adaptive"); + expect(resolveAnthropicOpus47Thinking(cfg)).toBe("off"); }); it("falls back to low when no provider thinking hook is active", () => { diff --git a/src/agents/model-thinking-default.ts b/src/agents/model-thinking-default.ts index 7ea7e0179d7..35db5ca1935 100644 --- a/src/agents/model-thinking-default.ts +++ b/src/agents/model-thinking-default.ts @@ -54,13 +54,18 @@ export function resolveThinkingDefault(params: { if (configured) { return configured; } + if ( + normalizedProvider === "anthropic" && + (normalizedModel.startsWith("claude-opus-4-7") || normalizedModel.startsWith("claude-opus-4.7")) + ) { + return "off"; + } if ( normalizedProvider === "anthropic" && explicitModelConfigured && typeof catalogCandidate?.name === "string" && - /4\.[67]\b/.test(catalogCandidate.name) && - (normalizedModel.startsWith("claude-opus-4-7") || - normalizedModel.startsWith("claude-opus-4-6") || + /4\.6\b/.test(catalogCandidate.name) && + (normalizedModel.startsWith("claude-opus-4-6") || normalizedModel.startsWith("claude-sonnet-4-6")) ) { return "adaptive";