fix(anthropic): use token thinking for effort levels on models without adaptive support#3381
Merged
Merged
Conversation
…ls without adaptive support Setting a reasoning level via the TUI Shift+Tab cycle produces an effort-based thinking budget. applyThinkingConfig routed any effort budget into the adaptive-thinking API (thinking.type=adaptive plus output_config.effort) regardless of model, so switching to Haiku 4.5 (or Sonnet 4.5 and earlier) and setting a reasoning level made every request fail with HTTP 400. Add modelinfo.SupportsAdaptiveThinking and resolve the thinking budget against it: effort or adaptive budgets on models that do not support adaptive thinking are converted to a token-based budget (thinking.type=enabled) via effort.BedrockTokens, while models that do support it keep using adaptive thinking. The predicate is a superset of RejectsTokenThinking, so models that reject token budgets still use adaptive. Fixes #3362
dgageot
approved these changes
Jul 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Switching the active model to Haiku 4.5 (or any model without adaptive-thinking support) and setting a reasoning level via Shift+Tab made every subsequent request fail with HTTP 400. The Shift+Tab cycle stores the level as an effort-based
thinking_budget, and the Anthropic provider routed any effort budget into the adaptive-thinking API (thinking.type=adaptivewithoutput_config.effort) regardless of model.Issue expectations
resolveThinkingBudgetconverts effort/adaptive budgets to token budgets on unsupported modelsthinking.type=enabledwithbudget_tokensderived from the effort level (effort.BedrockTokens)Change
pkg/modelinfo: addSupportsAdaptiveThinking(Opus 4.6/4.7/4.8, Sonnet 4.6, the Claude 5 families, Fable, Mythos). It is a superset ofRejectsTokenThinking, so a model that rejects token budgets always reports adaptive support.pkg/model/provider/anthropic: replacecoerceAdaptiveThinkingwithresolveThinkingBudget, which resolves both directions: token to adaptive for Opus 4.6+ (unchanged), and effort/adaptive to a token budget for models without adaptive support (new).adjustMaxTokensForThinkingnow operates on the resolved budget so a converted token budget gets the correctmax_tokensheadroom.Testing
Unit tests (added/updated) cover the effort-to-token fallback, the adaptive path on supported models, the previously untested plain effort level, and the
SupportsAdaptiveThinkingsuperset invariant.lint,vet, andgofmtare clean.Verified against a live gateway (
provider: anthropic, proxied to Bedrock):Notes
The Bedrock provider (
provider: amazon-bedrock) already routes plain effort levels to token thinking for non-Opus-4.6+ models and is not affected by this issue. It retains a narrower edge case (an explicitthinking_budget: adaptiveon a non-adaptive model), which is out of scope here and can be addressed as a follow-up. If a different resolution seems more appropriate, it can always be changed.