Part of #919. Phase 0 of the provider modernization roadmap. LP-003.
Blocks LP-004 — a thinking budget must fit under a configurable max_tokens.
Summary
Make the Anthropic client honor reasoning_effort, and preserve thinking blocks with their signatures across tool-calling iterations.
Problem
Two distinct gaps in the same conversion layer.
1. reasoning_effort is silently ignored. anthropic.go:106 consults only effectiveThinkingBudget; ReasoningEffort is never read on the Anthropic path. The shipped default config already depends on it:
# config/default.yaml:43-46
light:
provider: minimax # kind: anthropic
model: MiniMax-M2.7
reasoning_effort: minimal # no effect today
A setting that is accepted, validated, displayed in the console, and does nothing is worse than one that is rejected.
2. Thinking blocks are dropped on the return trip. toAnthropicAssistantMessage (anthropic.go:461) reconstructs assistant turns as text + tool_use only. ContentBlock (internal/llm/provider.go:17) has no thinking or signature field, so the parsed reasoning is flattened into ReasoningContent (a string) and lost as a structured block.
Anthropic requires signed thinking blocks to be echoed back on assistant turns that contain tool_use when extended thinking is enabled. So enabling thinking_budget on an Anthropic tier alongside tools is expected to fail from the second loop iteration onward. This is latent today only because no shipped tier sets thinking_budget.
gemini-native already solves the equivalent problem correctly — gemini_native_convert.go:161-170 encodes thoughtSignature on the way out and :286 restores it on the way back in. Mirror that design rather than inventing a new one.
Scope
Acceptance Criteria
Validation
Out of Scope
- Interleaved thinking, which requires a beta header — see LP-004.
- Reasoning support on
kind: anthropic third-party gateways that do not implement thinking; detect and degrade, do not emulate.
Part of #919. Phase 0 of the provider modernization roadmap. LP-003.
Blocks LP-004 — a thinking budget must fit under a configurable
max_tokens.Summary
Make the Anthropic client honor
reasoning_effort, and preserve thinking blocks with their signatures across tool-calling iterations.Problem
Two distinct gaps in the same conversion layer.
1.
reasoning_effortis silently ignored.anthropic.go:106consults onlyeffectiveThinkingBudget;ReasoningEffortis never read on the Anthropic path. The shipped default config already depends on it:A setting that is accepted, validated, displayed in the console, and does nothing is worse than one that is rejected.
2. Thinking blocks are dropped on the return trip.
toAnthropicAssistantMessage(anthropic.go:461) reconstructs assistant turns as text +tool_useonly.ContentBlock(internal/llm/provider.go:17) has no thinking or signature field, so the parsed reasoning is flattened intoReasoningContent(a string) and lost as a structured block.Anthropic requires signed thinking blocks to be echoed back on assistant turns that contain
tool_usewhen extended thinking is enabled. So enablingthinking_budgeton an Anthropic tier alongside tools is expected to fail from the second loop iteration onward. This is latent today only because no shipped tier setsthinking_budget.gemini-nativealready solves the equivalent problem correctly —gemini_native_convert.go:161-170encodesthoughtSignatureon the way out and:286restores it on the way back in. Mirror that design rather than inventing a new one.Scope
ReasoningEffortto the Anthropic request. Where the model exposes a native effort control, use it; otherwise derive athinking.budget_tokensfrom the effort level and document the mapping table in code.ContentBlock(or add an assistant-side equivalent) with a thinking type carrying text plus signature.toAnthropicAssistantMessage, in original order, ahead oftool_useblocks.redacted_thinkingblocks opaquely — they must round-trip without inspection.ReasoningContentconsumers (console reasoning stream,usage) still work.Acceptance Criteria
reasoning_efforton an Anthropic tier changes the request payload; the value is visible in debug logs.thinking_budgetplus tools completes a multi-iteration tool loop without an API error.redacted_thinkingblocks round-trip byte-identically.OnReasoningDelta.Validation
//go:build integrationlive test against the real API with thinking + tools enabled, following theTestAntigravityCLILiveprecedentmake testmake lint-diffOut of Scope
kind: anthropicthird-party gateways that do not implement thinking; detect and degrade, do not emulate.