mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-17 23:51:30 +00:00
feat(anthropic): map reasoning_effort to adaptive thinking with budget_tokens for Claude 4.6 models
- Claude 4.6 models now receive `budget_tokens` in the adaptive thinking param (e.g. reasoning_effort="low" → {"type": "adaptive", "budget_tokens": 1024})
- Add xhigh effort level support: maps to 10000 budget_tokens for all models, and "max" in output_config for Claude 4.6
- Add DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET constant (default 10000, configurable via env)
- Refactor effort-to-budget mapping into a single shared dict to reduce duplication
- Update and expand tests to assert budget_tokens are set correctly for all effort levels
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b518c24ff4
commit
ac98f311e1
4 changed files with 57 additions and 21 deletions
|
|
@ -177,6 +177,9 @@ DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET = int(
|
|||
DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET = int(
|
||||
os.getenv("DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET", 4096)
|
||||
)
|
||||
DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET = int(
|
||||
os.getenv("DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET", 10000)
|
||||
)
|
||||
MAX_TOKEN_TRIMMING_ATTEMPTS = int(
|
||||
os.getenv("MAX_TOKEN_TRIMMING_ATTEMPTS", 10)
|
||||
) # Maximum number of attempts to trim the message
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from litellm.constants import (
|
|||
DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
|
||||
DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
|
||||
DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET,
|
||||
DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET,
|
||||
RESPONSE_FORMAT_TOOL_NAME,
|
||||
)
|
||||
from litellm.litellm_core_utils.core_helpers import map_finish_reason
|
||||
|
|
@ -55,7 +56,10 @@ from litellm.types.utils import (
|
|||
CompletionTokensDetailsWrapper,
|
||||
)
|
||||
from litellm.types.utils import Message as LitellmMessage
|
||||
from litellm.types.utils import PromptTokensDetailsWrapper, ServerToolUse
|
||||
from litellm.types.utils import (
|
||||
PromptTokensDetailsWrapper,
|
||||
ServerToolUse,
|
||||
)
|
||||
from litellm.utils import (
|
||||
ModelResponse,
|
||||
Usage,
|
||||
|
|
@ -729,32 +733,30 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
) -> Optional[AnthropicThinkingParam]:
|
||||
if reasoning_effort is None or reasoning_effort == "none":
|
||||
return None
|
||||
effort_to_budget = {
|
||||
"minimal": DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET,
|
||||
"low": DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
|
||||
"medium": DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
|
||||
"high": DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
|
||||
"xhigh": DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET,
|
||||
}
|
||||
if AnthropicConfig._is_claude_4_6_model(model):
|
||||
budget_tokens = effort_to_budget.get(reasoning_effort)
|
||||
if budget_tokens is not None:
|
||||
return AnthropicThinkingParam(
|
||||
type="adaptive",
|
||||
budget_tokens=budget_tokens,
|
||||
)
|
||||
return AnthropicThinkingParam(
|
||||
type="adaptive",
|
||||
)
|
||||
elif reasoning_effort == "low":
|
||||
budget_tokens = effort_to_budget.get(reasoning_effort)
|
||||
if budget_tokens is not None:
|
||||
return AnthropicThinkingParam(
|
||||
type="enabled",
|
||||
budget_tokens=DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
|
||||
budget_tokens=budget_tokens,
|
||||
)
|
||||
elif reasoning_effort == "medium":
|
||||
return AnthropicThinkingParam(
|
||||
type="enabled",
|
||||
budget_tokens=DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
|
||||
)
|
||||
elif reasoning_effort == "high":
|
||||
return AnthropicThinkingParam(
|
||||
type="enabled",
|
||||
budget_tokens=DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
|
||||
)
|
||||
elif reasoning_effort == "minimal":
|
||||
return AnthropicThinkingParam(
|
||||
type="enabled",
|
||||
budget_tokens=DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET,
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unmapped reasoning effort: {reasoning_effort}")
|
||||
raise ValueError(f"Unmapped reasoning effort: {reasoning_effort}")
|
||||
|
||||
def _extract_json_schema_from_response_format(
|
||||
self, value: Optional[dict]
|
||||
|
|
@ -1014,6 +1016,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
"minimal": "low",
|
||||
"medium": "medium",
|
||||
"high": "high",
|
||||
"xhigh": "max",
|
||||
"max": "max",
|
||||
}
|
||||
mapped_effort = effort_map.get(value, value)
|
||||
|
|
|
|||
|
|
@ -16289,7 +16289,7 @@
|
|||
"cache_read_input_token_cost": 3e-08,
|
||||
"input_cost_per_audio_token": 1e-06,
|
||||
"input_cost_per_token": 3e-07,
|
||||
"litellm_provider": "vertex_ai-language-models",
|
||||
"litellm_provider": "gemini",
|
||||
"max_audio_length_hours": 8.4,
|
||||
"max_audio_per_prompt": 1,
|
||||
"supports_reasoning": false,
|
||||
|
|
|
|||
|
|
@ -28,12 +28,28 @@ class TestMapReasoningEffort:
|
|||
reasoning_effort="low", model="claude-opus-4-6"
|
||||
)
|
||||
assert result["type"] == "adaptive"
|
||||
assert result["budget_tokens"] == 1024
|
||||
|
||||
def test_opus_4_6_returns_adaptive_for_high(self):
|
||||
result = AnthropicConfig._map_reasoning_effort(
|
||||
reasoning_effort="high", model="claude-opus-4-6"
|
||||
)
|
||||
assert result["type"] == "adaptive"
|
||||
assert result["budget_tokens"] == 4096
|
||||
|
||||
def test_opus_4_6_returns_adaptive_for_medium(self):
|
||||
result = AnthropicConfig._map_reasoning_effort(
|
||||
reasoning_effort="medium", model="claude-opus-4-6"
|
||||
)
|
||||
assert result["type"] == "adaptive"
|
||||
assert result["budget_tokens"] == 2048
|
||||
|
||||
def test_opus_4_6_returns_adaptive_for_minimal(self):
|
||||
result = AnthropicConfig._map_reasoning_effort(
|
||||
reasoning_effort="minimal", model="claude-opus-4-6"
|
||||
)
|
||||
assert result["type"] == "adaptive"
|
||||
assert result["budget_tokens"] == 128
|
||||
|
||||
def test_other_model_low_returns_enabled_with_budget(self):
|
||||
result = AnthropicConfig._map_reasoning_effort(
|
||||
|
|
@ -62,3 +78,17 @@ class TestMapReasoningEffort:
|
|||
reasoning_effort="none", model="claude-4-sonnet-20250514"
|
||||
)
|
||||
assert result is None
|
||||
|
||||
def test_opus_4_6_returns_adaptive_with_budget_for_xhigh(self):
|
||||
result = AnthropicConfig._map_reasoning_effort(
|
||||
reasoning_effort="xhigh", model="claude-opus-4-6"
|
||||
)
|
||||
assert result["type"] == "adaptive"
|
||||
assert result["budget_tokens"] == 10000
|
||||
|
||||
def test_other_model_xhigh_returns_enabled_with_budget(self):
|
||||
result = AnthropicConfig._map_reasoning_effort(
|
||||
reasoning_effort="xhigh", model="claude-4-sonnet-20250514"
|
||||
)
|
||||
assert result["type"] == "enabled"
|
||||
assert result["budget_tokens"] == 10000
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue