Skip to content

feat: map reasoning_effort=xhigh/max to budget_tokens on pre-4.6 Anthropic models - #27051

Closed
mateo-berri wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_add_xhigh_max_budget_map
Closed

feat: map reasoning_effort=xhigh/max to budget_tokens on pre-4.6 Anthropic models#27051
mateo-berri wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_add_xhigh_max_budget_map

Conversation

@mateo-berri

Copy link
Copy Markdown
Contributor

Linear: LIT-2758 (follow-up)

What this PR does

Extends AnthropicConfig._map_reasoning_effort so reasoning_effort='xhigh' and reasoning_effort='max' produce thinking={type:'enabled', budget_tokens:N} on pre-4.6 Anthropic models, instead of raising ValueError("Unmapped reasoning effort: ...") and surfacing as a 500 APIConnectionError.

Adds two env-overridable defaults to litellm/constants.py:

effort budget_tokens
minimal 128 (existing)
low 1024 (existing)
medium 2048 (existing)
high 4096 (existing)
xhigh 8192 (new)
max 16384 (new)

4.6/4.7 behavior is unchanged: those models still short-circuit to thinking={type:'adaptive'} at the top of _map_reasoning_effort, and _apply_output_config separately applies output_config.effort=<value> with the existing per-model gating (opus-4-7 supports xhigh+max; opus-4-6 supports max only; sonnet-4-6 supports neither).

Why

Surfaced during the QA sweep on #27039 — every pre-4.6 model 500'd on reasoning_effort=xhigh|max because _map_reasoning_effort had no branch for them. After this PR, the 4.5 path emits a valid thinking shape and providers accept it (manually verified — see Manual QA section below).

Checklist

…ropic models

Adds DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET=8192 and
DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET=16384 (env-overridable) and
extends AnthropicConfig._map_reasoning_effort so reasoning_effort='xhigh'
and 'max' produce thinking={type:'enabled', budget_tokens:N} on pre-4.6
models. 4.6/4.7 behavior is unchanged: those still short-circuit to
adaptive thinking and have output_config.effort applied separately by
_apply_output_config (with per-model gating).
@mateo-berri

Copy link
Copy Markdown
Contributor Author

Manual QA

Tested live on a proxy built from this branch (litellm_add_xhigh_max_budget_map @ 053f53fa89, off litellm_internal_staging which already has #27039 merged). Captured wire bodies from --detailed_debug POST Request Sent from LiteLLM: log lines.

4.5 path: budget_tokens for xhigh / max (the new behavior)

model / route effort HTTP wire body
Anthropic claude-haiku-4-5 xhigh 200 thinking={type:"enabled", budget_tokens: 8192}
Anthropic claude-haiku-4-5 max 200 thinking={type:"enabled", budget_tokens: 16384}
Bedrock Converse sonnet-4-5 xhigh 200 additionalModelRequestFields.thinking={type:"enabled", budget_tokens: 8192}
Bedrock Converse sonnet-4-5 max 200 additionalModelRequestFields.thinking={type:"enabled", budget_tokens: 16384}
Bedrock Invoke chat opus-4-5 xhigh 200 thinking={type:"enabled", budget_tokens: 8192}, anthropic_version: "bedrock-2023-05-31"
Bedrock Invoke chat opus-4-5 max 200 thinking={type:"enabled", budget_tokens: 16384}, anthropic_version: "bedrock-2023-05-31"
Vertex haiku-4-5 xhigh 200 thinking={type:"enabled", budget_tokens: 8192}, anthropic_version: "vertex-2023-10-16"
Vertex haiku-4-5 max 200 thinking={type:"enabled", budget_tokens: 16384}, anthropic_version: "vertex-2023-10-16"

Before this PR these all 500'd with litellm.APIConnectionError: Unmapped reasoning effort: xhigh / ... max.

4.6/4.7 path: unchanged (regression check)

model effort HTTP wire body
Anthropic opus-4-7 xhigh 200 thinking={type:"adaptive"}, output_config={effort:"xhigh"}
Anthropic opus-4-7 max 200 thinking={type:"adaptive"}, output_config={effort:"max"}
Anthropic opus-4-6 xhigh 500 ValueError (gated, opus-4-6 doesn't support xhigh)
Anthropic opus-4-6 max 200 thinking={type:"adaptive"}, output_config={effort:"max"}
Anthropic sonnet-4-6 xhigh 500 ValueError (gated)
Anthropic sonnet-4-6 max 500 ValueError (gated)

Per-model gating in _apply_output_config (anthropic/chat/transformation.py:1538+) is unchanged: xhigh is data-driven via supports_xhigh_reasoning_effort in model_prices_and_context_window.json; max accepts opus-4-6/4-7 patterns + supports_max_reasoning_effort.

Other regression checks

effort model HTTP notes
low claude-haiku-4-5 200 budget_tokens: 1024 (unchanged)
medium claude-haiku-4-5 200 budget_tokens: 2048 (unchanged)
high claude-haiku-4-5 200 budget_tokens: 4096 (unchanged)
none claude-haiku-4-5 200 no thinking (PR #27039 fix path unchanged)
none claude-opus-4-7 200 no thinking / no output_config

Unit tests

tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py::test_reasoning_effort_maps_to_budget_thinking_for_non_opus_4_6 PASSED
142 passed in 0.87s   # full anthropic chat transformation suite
229 passed in 6.91s   # full bedrock chat suite (Converse calls AnthropicConfig._map_reasoning_effort directly)

Note on minimal (out of scope for this PR)

minimal still maps to budget_tokens=128, which is below Anthropic's published minimum of 1024 — so reasoning_effort=minimal continues to 400 on Anthropic / Azure / Vertex / Bedrock Invoke (with exact error "thinking.enabled.budget_tokens: Input should be greater than or equal to 1024"); only Bedrock Converse silently clamps to 1024 in converse_transformation.py:457. This PR intentionally preserves the existing minimal=128 value to keep the diff minimal; bumping to ≥1024 is a separate decision tracked in PR #27039's QA comment.

@greptile-apps

greptile-apps Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extends _map_reasoning_effort to handle xhigh and max effort levels for pre-4.6 Anthropic models, mapping them to thinking={type:'enabled', budget_tokens:N} instead of raising a ValueError. Two env-overridable constants are added and a test case covers both new branches.

  • The budget_tokens for max (16384) exceeds the maximum output tokens of every pre-4.6 model (claude-3-5-sonnet caps at 8192; claude-3-opus at 4096). Anthropic rejects any request where budget_tokens >= max_tokens, so reasoning_effort='max' on a pre-4.6 model will always fail at the API level unless the caller explicitly sets a high max_tokens. xhigh (8192) has the same issue for models with ≤ 8192 output tokens.

Confidence Score: 3/5

Safe to merge only if callers ensure max_tokens exceeds the thinking budget; without that guard the new effort levels will fail at the provider layer.

One P1 issue: the new effort mappings produce a thinking budget larger than the output limit of all pre-4.6 models in the default configuration, causing systematic provider rejections.

litellm/llms/anthropic/chat/transformation.py — the new effort branches need a guard or documentation around the budget vs output token relationship

Important Files Changed

Filename Overview
litellm/constants.py Adds two env-overridable constants for xhigh and max thinking budgets; clean and consistent with existing pattern.
litellm/llms/anthropic/chat/transformation.py Adds xhigh and max branches to _map_reasoning_effort for pre-4.6 models; logic is correct and the adaptive path for 4.6+ models is unaffected.
tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py Extends existing test parametrization with xhigh/max cases; mock-only, consistent with existing test style.

Reviews (1): Last reviewed commit: "feat: map reasoning_effort=xhigh/max to ..." | Re-trigger Greptile

Comment on lines +828 to +837
elif reasoning_effort == "xhigh":
return AnthropicThinkingParam(
type="enabled",
budget_tokens=DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET,
)
elif reasoning_effort == "max":
return AnthropicThinkingParam(
type="enabled",
budget_tokens=DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Anthropic requires budget_tokens to be strictly less than max_tokens. Most pre-4.6 models have a max output of 4096–8192 tokens. With xhigh=8192, the budget equals the output limit for claude-3-5-sonnet models, and with max=16384 it exceeds the limit for virtually every pre-4.6 model. Without a compensating increase to max_tokens, these requests will fail at the API layer. Consider adding a guard that bumps max_tokens to at least budget_tokens + 1 when the user has not explicitly set it.

Suggested change
elif reasoning_effort == "xhigh":
return AnthropicThinkingParam(
type="enabled",
budget_tokens=DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET,
)
elif reasoning_effort == "max":
return AnthropicThinkingParam(
type="enabled",
budget_tokens=DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET,
)
elif reasoning_effort == "xhigh":
return AnthropicThinkingParam(
type="enabled",
budget_tokens=DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET,
)
elif reasoning_effort == "max":
return AnthropicThinkingParam(
type="enabled",
budget_tokens=DEFAULT_REASONING_EFFORT_MAX_THINKING_BUDGET,
)
# NOTE: callers should ensure max_tokens > budget_tokens; Anthropic rejects
# requests where budget_tokens >= max_tokens.

@codecov

codecov Bot commented May 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mateo-berri

Copy link
Copy Markdown
Contributor Author

Superceded by #27074

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant