fix translate_anthropic_thinking_to_reasoning_effort

This commit is contained in:
Ishaan Jaffer 2026-01-14 11:25:55 -08:00
parent ae6b79a454
commit aeed4c322f

View file

@ -17,7 +17,6 @@ from openai.types.chat.chat_completion_chunk import Choice as OpenAIStreamingCho
from litellm.litellm_core_utils.prompt_templates.common_utils import (
parse_tool_call_arguments,
)
from litellm.types.llms.anthropic import (
AllAnthropicToolsValues,
AnthopicMessagesAssistantMessageParam,
@ -210,7 +209,7 @@ class LiteLLMAnthropicMessagesAdapter:
# Convert Anthropic image format to OpenAI format
source = content.get("source", {})
openai_image_url = (
self._translate_anthropic_image_to_openai(source)
self._translate_anthropic_image_to_openai(cast(dict, source))
)
if openai_image_url:
@ -240,7 +239,7 @@ class LiteLLMAnthropicMessagesAdapter:
# Combine all content items into a single tool message
# to avoid creating multiple tool_result blocks with the same ID
# (each tool_use must have exactly one tool_result)
content_items = content.get("content", [])
content_items = list(content.get("content", []))
# For single-item content, maintain backward compatibility with string/url format
if len(content_items) == 1:
@ -266,7 +265,7 @@ class LiteLLMAnthropicMessagesAdapter:
source = c.get("source", {})
openai_image_url = (
self._translate_anthropic_image_to_openai(
source
cast(dict, source)
)
or ""
)
@ -306,7 +305,7 @@ class LiteLLMAnthropicMessagesAdapter:
source = c.get("source", {})
openai_image_url = (
self._translate_anthropic_image_to_openai(
source
cast(dict, source)
)
or ""
)
@ -363,7 +362,7 @@ class LiteLLMAnthropicMessagesAdapter:
}
signature = (
self._extract_signature_from_tool_use_content(
content
cast(Dict[str, Any], content)
)
)
@ -424,14 +423,21 @@ class LiteLLMAnthropicMessagesAdapter:
return new_messages
def translate_anthropic_thinking_to_openai(
self, thinking: Dict[str, Any]
@staticmethod
def translate_anthropic_thinking_to_reasoning_effort(
thinking: Dict[str, Any]
) -> Optional[str]:
"""
Translate Anthropic's thinking parameter to OpenAI's reasoning_effort.
Anthropic thinking format: {'type': 'enabled'|'disabled', 'budget_tokens': int}
OpenAI reasoning_effort: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'default'
Mapping:
- budget_tokens >= 10000 -> 'high'
- budget_tokens >= 5000 -> 'medium'
- budget_tokens >= 2000 -> 'low'
- budget_tokens < 2000 -> 'minimal'
"""
if not isinstance(thinking, dict):
return None
@ -453,6 +459,53 @@ class LiteLLMAnthropicMessagesAdapter:
return None
@staticmethod
def is_anthropic_claude_model(model: str) -> bool:
"""
Check if the model is an Anthropic Claude model that supports the thinking parameter.
Returns True for:
- anthropic/* models
- bedrock/*anthropic* models (including converse)
- vertex_ai/*claude* models
"""
model_lower = model.lower()
return (
"anthropic" in model_lower
or "claude" in model_lower
)
@staticmethod
def translate_thinking_for_model(
thinking: Dict[str, Any],
model: str,
) -> Dict[str, Any]:
"""
Translate Anthropic thinking parameter based on the target model.
For Claude/Anthropic models: returns {'thinking': <original_thinking>}
- Preserves exact budget_tokens value
For non-Claude models: returns {'reasoning_effort': <mapped_value>}
- Converts thinking to reasoning_effort to avoid UnsupportedParamsError
Args:
thinking: Anthropic thinking dict with 'type' and 'budget_tokens'
model: The target model name
Returns:
Dict with either 'thinking' or 'reasoning_effort' key
"""
if LiteLLMAnthropicMessagesAdapter.is_anthropic_claude_model(model):
return {"thinking": thinking}
else:
reasoning_effort = LiteLLMAnthropicMessagesAdapter.translate_anthropic_thinking_to_reasoning_effort(
thinking
)
if reasoning_effort:
return {"reasoning_effort": reasoning_effort}
return {}
def translate_anthropic_tool_choice_to_openai(
self, tool_choice: AnthropicMessagesToolChoice
) -> ChatCompletionToolChoiceValues:
@ -566,11 +619,15 @@ class LiteLLMAnthropicMessagesAdapter:
if "thinking" in anthropic_message_request:
thinking = anthropic_message_request["thinking"]
if thinking:
reasoning_effort = self.translate_anthropic_thinking_to_openai(
thinking=cast(Dict[str, Any], thinking)
)
if reasoning_effort:
new_kwargs["reasoning_effort"] = reasoning_effort
model = new_kwargs.get("model", "")
if self.is_anthropic_claude_model(model):
new_kwargs["thinking"] = thinking # type: ignore
else:
reasoning_effort = self.translate_anthropic_thinking_to_reasoning_effort(
cast(Dict[str, Any], thinking)
)
if reasoning_effort:
new_kwargs["reasoning_effort"] = reasoning_effort
translatable_params = self.translatable_anthropic_params()
for k, v in anthropic_message_request.items():