mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix(anthropic): upgrade legacy thinking for adaptive models
This commit is contained in:
parent
a5b0f32a84
commit
fecec625e4
5 changed files with 98 additions and 47 deletions
|
|
@ -1241,6 +1241,35 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
return thinking
|
||||
return AnthropicThinkingParam(type=thinking.get("type", "enabled"), budget_tokens=max_tokens - 1)
|
||||
|
||||
@staticmethod
|
||||
def _translate_legacy_thinking_for_adaptive_model(
|
||||
model: str, optional_params: Dict, custom_llm_provider: str
|
||||
) -> None:
|
||||
if not AnthropicConfig._is_adaptive_thinking_model(model, custom_llm_provider):
|
||||
return
|
||||
thinking = optional_params.get("thinking")
|
||||
if not isinstance(thinking, dict) or thinking.get("type") != "enabled":
|
||||
return
|
||||
|
||||
budget = int(thinking.get("budget_tokens") or 0)
|
||||
if budget >= DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET and AnthropicConfig._supports_effort_level(
|
||||
model, "xhigh", custom_llm_provider
|
||||
):
|
||||
effort = "xhigh"
|
||||
elif budget >= DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET:
|
||||
effort = "high"
|
||||
elif budget >= DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET:
|
||||
effort = "medium"
|
||||
else:
|
||||
effort = "low"
|
||||
|
||||
optional_params["thinking"] = {"type": "adaptive"}
|
||||
output_config = optional_params.get("output_config")
|
||||
if not isinstance(output_config, dict):
|
||||
output_config = {}
|
||||
output_config.setdefault("effort", effort)
|
||||
optional_params["output_config"] = output_config
|
||||
|
||||
def _extract_json_schema_from_response_format(self, value: Optional[dict]) -> Optional[dict]:
|
||||
if value is None:
|
||||
return None
|
||||
|
|
@ -1484,6 +1513,12 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
):
|
||||
optional_params["metadata"] = {"user_id": value}
|
||||
elif param == "thinking":
|
||||
optional_params["thinking"] = value
|
||||
AnthropicConfig._translate_legacy_thinking_for_adaptive_model(
|
||||
model=model,
|
||||
optional_params=optional_params,
|
||||
custom_llm_provider=self._resolved_provider,
|
||||
)
|
||||
if (
|
||||
isinstance(value, dict)
|
||||
and value.get("type") == "adaptive"
|
||||
|
|
@ -1514,8 +1549,6 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
model,
|
||||
)
|
||||
optional_params.pop("thinking", None)
|
||||
else:
|
||||
optional_params["thinking"] = value
|
||||
elif param == "reasoning_effort":
|
||||
# Accept both string ("low") and dict ({"effort": "low",
|
||||
# "summary": "concise"}). The Responses->Chat parser keeps the
|
||||
|
|
|
|||
|
|
@ -2,13 +2,9 @@ from typing import Any, AsyncIterator, Dict, List, Optional, Tuple
|
|||
|
||||
import httpx
|
||||
|
||||
from litellm.constants import (
|
||||
DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
|
||||
DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
|
||||
DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET,
|
||||
)
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
from litellm.litellm_core_utils.litellm_logging import verbose_logger
|
||||
from litellm.llms.anthropic.chat.transformation import AnthropicConfig
|
||||
from litellm.llms.base_llm.anthropic_messages.transformation import (
|
||||
BaseAnthropicMessagesConfig,
|
||||
)
|
||||
|
|
@ -239,40 +235,6 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
existing_output_config.setdefault("effort", mapped_effort)
|
||||
optional_params["output_config"] = existing_output_config
|
||||
|
||||
@staticmethod
|
||||
def _translate_legacy_thinking_for_adaptive_model(
|
||||
model: str, optional_params: Dict, custom_llm_provider: str
|
||||
) -> None:
|
||||
"""Translate legacy ``thinking.type=enabled`` to adaptive for 4.6/4.7.
|
||||
Caller-provided ``output_config.effort`` is never overridden.
|
||||
"""
|
||||
from litellm.llms.anthropic.chat.transformation import AnthropicConfig
|
||||
|
||||
if not AnthropicModelInfo._is_adaptive_thinking_model(model, custom_llm_provider):
|
||||
return
|
||||
thinking = optional_params.get("thinking")
|
||||
if not isinstance(thinking, dict) or thinking.get("type") != "enabled":
|
||||
return
|
||||
|
||||
budget = int(thinking.get("budget_tokens") or 0)
|
||||
if budget >= DEFAULT_REASONING_EFFORT_XHIGH_THINKING_BUDGET and (
|
||||
AnthropicConfig._supports_effort_level(model, "xhigh", custom_llm_provider)
|
||||
):
|
||||
effort = "xhigh"
|
||||
elif budget >= DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET:
|
||||
effort = "high"
|
||||
elif budget >= DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET:
|
||||
effort = "medium"
|
||||
else:
|
||||
effort = "low"
|
||||
|
||||
optional_params["thinking"] = {"type": "adaptive"}
|
||||
existing_output_config = optional_params.get("output_config")
|
||||
if not isinstance(existing_output_config, dict):
|
||||
existing_output_config = {}
|
||||
existing_output_config.setdefault("effort", effort)
|
||||
optional_params["output_config"] = existing_output_config
|
||||
|
||||
@staticmethod
|
||||
def _translate_adaptive_effort_for_non_adaptive_model(
|
||||
model: str, optional_params: Dict, max_tokens: Optional[int], custom_llm_provider: str
|
||||
|
|
@ -316,7 +278,6 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
subclasses to handle.
|
||||
"""
|
||||
from litellm.exceptions import BadRequestError as _BadRequestError
|
||||
from litellm.llms.anthropic.chat.transformation import AnthropicConfig
|
||||
|
||||
if AnthropicConfig._is_adaptive_thinking_model(model, custom_llm_provider):
|
||||
return
|
||||
|
|
@ -397,7 +358,7 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
custom_llm_provider=self._resolved_provider,
|
||||
)
|
||||
|
||||
self._translate_legacy_thinking_for_adaptive_model(
|
||||
AnthropicConfig._translate_legacy_thinking_for_adaptive_model(
|
||||
model=model,
|
||||
optional_params=anthropic_messages_optional_request_params,
|
||||
custom_llm_provider=self._resolved_provider,
|
||||
|
|
@ -421,8 +382,6 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
# Transform context_management from OpenAI format to Anthropic format if needed
|
||||
context_management_param = anthropic_messages_optional_request_params.get("context_management")
|
||||
if context_management_param is not None:
|
||||
from litellm.llms.anthropic.chat.transformation import AnthropicConfig
|
||||
|
||||
transformed_context_management = AnthropicConfig.map_openai_context_management_to_anthropic(
|
||||
context_management_param
|
||||
)
|
||||
|
|
|
|||
|
|
@ -900,6 +900,12 @@ class AmazonConverseConfig(BaseConfig):
|
|||
"tool_choice": {"disable_parallel_tool_use": disable_parallel}
|
||||
}
|
||||
if param == "thinking":
|
||||
optional_params["thinking"] = value
|
||||
AnthropicConfig._translate_legacy_thinking_for_adaptive_model(
|
||||
model=model,
|
||||
optional_params=optional_params,
|
||||
custom_llm_provider="bedrock",
|
||||
)
|
||||
if (
|
||||
isinstance(value, dict)
|
||||
and value.get("type") == "adaptive"
|
||||
|
|
@ -920,8 +926,7 @@ class AmazonConverseConfig(BaseConfig):
|
|||
optional_params["thinking"] = capped
|
||||
else:
|
||||
litellm.verbose_logger.warning(DROP_UNSUPPORTED_ADAPTIVE_THINKING_WARNING, model)
|
||||
else:
|
||||
optional_params["thinking"] = value
|
||||
optional_params.pop("thinking", None)
|
||||
elif param == "reasoning_effort" and isinstance(value, str):
|
||||
self._handle_reasoning_effort_parameter(
|
||||
model=model, reasoning_effort=value, optional_params=optional_params
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ from litellm.llms.anthropic.chat.transformation import AnthropicConfig
|
|||
from litellm.llms.anthropic.experimental_pass_through.messages.transformation import (
|
||||
AnthropicMessagesConfig,
|
||||
)
|
||||
from litellm.llms.bedrock.chat.invoke_transformations.anthropic_claude3_transformation import (
|
||||
AmazonAnthropicClaudeConfig,
|
||||
)
|
||||
from litellm.llms.vertex_ai.vertex_ai_partner_models.anthropic.transformation import (
|
||||
VertexAIAnthropicConfig,
|
||||
)
|
||||
from litellm.types.llms.anthropic import ANTHROPIC_BETA_HEADER_VALUES
|
||||
from litellm.types.utils import ServerToolUse
|
||||
|
||||
|
|
@ -2516,6 +2522,35 @@ def test_raw_adaptive_thinking_untouched_for_46_plus_model():
|
|||
assert result["thinking"] == {"type": "adaptive"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"config,model",
|
||||
[
|
||||
(AnthropicConfig(), "claude-opus-4-8"),
|
||||
(
|
||||
AmazonAnthropicClaudeConfig(),
|
||||
"global.anthropic.claude-opus-4-8",
|
||||
),
|
||||
(VertexAIAnthropicConfig(), "claude-opus-4-8"),
|
||||
],
|
||||
ids=["anthropic", "bedrock-invoke", "vertex"],
|
||||
)
|
||||
def test_legacy_thinking_maps_to_adaptive_thinking_for_chat_routes(config, model):
|
||||
result = config.map_openai_params(
|
||||
non_default_params={
|
||||
"thinking": {
|
||||
"type": "enabled",
|
||||
"budget_tokens": DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
|
||||
}
|
||||
},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert result["thinking"] == {"type": "adaptive"}
|
||||
assert result["output_config"] == {"effort": "high"}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def local_model_cost_map(monkeypatch):
|
||||
original_model_cost = litellm.model_cost
|
||||
|
|
|
|||
|
|
@ -341,6 +341,25 @@ def test_reasoning_effort_sets_output_config_for_adaptive_models_converse(
|
|||
assert optional_params["output_config"] == {"effort": expected_effort}
|
||||
|
||||
|
||||
def test_legacy_thinking_maps_to_adaptive_thinking_for_converse():
|
||||
config = AmazonConverseConfig()
|
||||
|
||||
optional_params = config.map_openai_params(
|
||||
non_default_params={
|
||||
"thinking": {
|
||||
"type": "enabled",
|
||||
"budget_tokens": 4096,
|
||||
}
|
||||
},
|
||||
optional_params={"output_config": {"effort": "low"}},
|
||||
model="bedrock/converse/global.anthropic.claude-opus-4-8",
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert optional_params["thinking"] == {"type": "adaptive"}
|
||||
assert optional_params["output_config"] == {"effort": "low"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model",
|
||||
[
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue