Send the least thinking a model accepts for `thinking=False` on models that can't turn thinking off

Merged
DO
8d ago
+3970-808

thinking=False was silently dropped on models that can't turn thinking off, so they kept reasoning at their default effort (medium on Claude Opus 5.5 and GPT-6 Astra, high on Claude Sonnet 5.5). It now reaches the adapter, which sends the least thinking the model accepts. Models with no thinking setting at all (DeepSeek R1, Qwen3-*-Thinking on vLLM, Kimi K2.7 Code, Magistral Small on Bedrock, Claude Mythos Preview) keep their default.

[!WARNING]
Compatibility impact: Existing code that sets thinking=False on a model that always reasons will make the model reason at its lowest effort instead of its default one, so responses may use fewer reasoning tokens and differ in quality. On CohereModel, which ignored the unified thinking setting before, any thinking value now reaches the request: False disables reasoning, True enables it, and an effort level caps it with a token_budget (512 tokens for 'minimal' up to 31,000 for 'xhigh' and 'max').

Why this can ship in a minor release: thinking=False asks for no thinking. Sending the closest the model allows honors that request better than ignoring it, and nothing that worked before now fails.

Migration: To keep a model's default effort, leave thinking unset instead of setting it to False, or on Cohere instead of setting it at all.

Every always-on model was checked against the live API (2026-10-22). Retired models are noted where they now 404. What thinking=False sends:

ProviderModelsSends
Anthropic and BedrockOpus 5.5, Fable, Mythosadaptive thinking with effort='low'
OpenAI (Responses, Chat, GPT-Live)o-series, GPT-6 Astra, GPT-6.1 Sollow
gpt-5 / mini / nanominimal
gpt-5.2/5.4/5.5-promedium
gpt-5-prohigh (the only value it accepts)
GoogleGemini 2.5 Prothinking_budget=128
Gemini 3.x Prothinking_level=LOW (thoughts not requested); see below for Vertex
Groqgpt-ossreasoning_effort='low' with reasoning_format='hidden'
Cerebrasgpt-ossreasoning_effort='low'
Bedrockgpt-ossreasoning_effort='low'
GPT-6 Astra, GPT-6.1 Solreasoning={'effort': 'low'}
xAIGrok 4.5 / 4.6 / 4.7 (also on Bedrock)effort low
Z.AIGLM-5.3reasoning_effort='low'
MetaMuseminimal
MoonshotKimi K3reasoning_effort='low' (from Kimi's docs: no Moonshot key to check it live)
OpenRouteralways-on routeseffort='low'

The mapping happens in each adapter, at the last moment: Model.prepare_request now passes False through on these models instead of stripping it.

Fixing this exposed existing bugs, also fixed here:

  • Unified levels a model rejects now resolve to the closest level it accepts.
    • The o-series rejected minimal with a 400, and the pro models rejected low. gpt-5-pro even rejected thinking=True.
    • Bedrock and Cerebras gpt-oss rejected minimal.
    • The new OpenAIModelProfile.openai_reasoning_efforts field holds each OpenAI model's verified effort set. The Meta profile uses it too.
  • Profiles that marked models always-on although they can turn thinking off now really disable it:
    • Claude Sonnet 5.5 sends thinking={'type': 'between_tools'}, the off switch Anthropic's own error message names. The new AnthropicModelProfile.anthropic_disables_thinking_with_between_tools flag selects it.
    • Grok 3 Mini sends reasoning_effort='none'.
    • magistral-*-latest, now aliases of the adjustable Mistral models, sends reasoning_effort='none'. Before, thinking=True produced no reasoning on it at all.
    • Bedrock Qwen3 sends reasoning_config='none'. Qwen3-Coder never reasons, so it is marked as not supporting thinking.
    • CohereModel gains the unified thinking mapping: False โ†’ disabled, levels โ†’ token_budget.
    • Kimi K2.5 and K2.6 on MoonshotAIProvider send thinking={'type': 'disabled'} (Kimi's documented off switch; reasoning_effort='none' is rejected). The new OpenAIModelProfile.openai_chat_thinking_false_body field, set only by MoonshotAIProvider, holds what thinking=False sends there. Kimi's other levels resolve exactly as on main. Verified with a mocked transport, since no Moonshot key was available.
    • gemini-3.1-pro-preview on Google Cloud sends thinking_budget=0. Vertex accepts it and returns no thoughts (checked live on 8 of 8 reasoning prompts and the -customtools variant; recorded). The Gemini API rejects it, so the Gemini API keeps LOW. The new GoogleModelProfile.google_disables_thinking_with_zero_budget flag is set from the client's transport in GoogleModel.profile, like the gemini-3.1-flash-image case.

The effort maps this PR adds or changes also cover the 'max' level from #10920, following that PR's choices per provider.

Checklist

  • No breaking changes in accordance with the version policy.
  • Any permitted compatibility impact has a label, warning, migration, release note, and exact API-check waiver.
  • PR title is fit for the release changelog.

๐Ÿค– Generated with Claude Code