mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
fix(anthropic-adapter): dedupe reasoning_effort wrapping to close sibling gap
translate_thinking_for_model duplicated the same summary/auto_summary
wrapping logic as _translate_thinking_to_openai without the
disabled-thinking guard, so it could still wrap "none" into an
{effort, summary} dict when reasoning_auto_summary is enabled (caught
by Cursor Bugbot). Extract the wrapping rule into one shared
_apply_reasoning_summary_wrapping helper used by both call sites so
this invariant can't drift apart again.
This commit is contained in:
parent
fed03a41d1
commit
5072590c27
2 changed files with 52 additions and 41 deletions
|
|
@ -684,25 +684,37 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
thinking
|
||||
)
|
||||
if reasoning_effort:
|
||||
summary = thinking.get("summary") if isinstance(thinking, dict) else None
|
||||
auto_summary = is_reasoning_auto_summary_enabled()
|
||||
if summary:
|
||||
return {
|
||||
"reasoning_effort": {
|
||||
"effort": reasoning_effort,
|
||||
"summary": summary,
|
||||
}
|
||||
}
|
||||
elif auto_summary:
|
||||
return {
|
||||
"reasoning_effort": {
|
||||
"effort": reasoning_effort,
|
||||
"summary": "detailed",
|
||||
}
|
||||
}
|
||||
return {"reasoning_effort": reasoning_effort}
|
||||
return {
|
||||
"reasoning_effort": LiteLLMAnthropicMessagesAdapter._apply_reasoning_summary_wrapping(
|
||||
reasoning_effort, thinking
|
||||
)
|
||||
}
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def _apply_reasoning_summary_wrapping(
|
||||
reasoning_effort: str,
|
||||
thinking: Dict[str, Any],
|
||||
) -> Any:
|
||||
"""
|
||||
Apply the reasoning_effort/summary wrapping rules shared by every
|
||||
thinking->reasoning_effort translation path.
|
||||
|
||||
Disabled thinking always stays a plain string - there's no reasoning
|
||||
trace to summarize, and non-Claude providers (e.g. Fireworks) expect
|
||||
reasoning_effort as a plain string, not a summary dict.
|
||||
"""
|
||||
thinking_type = thinking.get("type") if isinstance(thinking, dict) else None
|
||||
if thinking_type == "disabled":
|
||||
return reasoning_effort
|
||||
|
||||
summary = thinking.get("summary") if isinstance(thinking, dict) else None
|
||||
if summary:
|
||||
return cast(Any, {"effort": reasoning_effort, "summary": summary})
|
||||
if is_reasoning_auto_summary_enabled():
|
||||
return cast(Any, {"effort": reasoning_effort, "summary": "detailed"})
|
||||
return reasoning_effort
|
||||
|
||||
def translate_anthropic_tool_choice_to_openai(
|
||||
self, tool_choice: AnthropicMessagesToolChoice
|
||||
) -> ChatCompletionToolChoiceValues:
|
||||
|
|
@ -997,30 +1009,9 @@ class LiteLLMAnthropicMessagesAdapter:
|
|||
if isinstance(output_config, dict) and output_config.get("effort"):
|
||||
reasoning_effort = output_config["effort"]
|
||||
|
||||
if thinking_type == "disabled":
|
||||
new_kwargs["reasoning_effort"] = reasoning_effort
|
||||
return
|
||||
|
||||
summary = thinking.get("summary") if isinstance(thinking, dict) else None
|
||||
auto_summary = is_reasoning_auto_summary_enabled()
|
||||
if summary:
|
||||
new_kwargs["reasoning_effort"] = cast(
|
||||
Any,
|
||||
{
|
||||
"effort": reasoning_effort,
|
||||
"summary": summary,
|
||||
},
|
||||
)
|
||||
elif auto_summary:
|
||||
new_kwargs["reasoning_effort"] = cast(
|
||||
Any,
|
||||
{
|
||||
"effort": reasoning_effort,
|
||||
"summary": "detailed",
|
||||
},
|
||||
)
|
||||
else:
|
||||
new_kwargs["reasoning_effort"] = reasoning_effort
|
||||
new_kwargs["reasoning_effort"] = self._apply_reasoning_summary_wrapping(
|
||||
reasoning_effort, cast(Dict[str, Any], thinking)
|
||||
)
|
||||
|
||||
def _translate_output_format_to_openai(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -651,6 +651,26 @@ class TestThinkingSummaryPreservation:
|
|||
"reasoning_effort": {"effort": "high", "summary": "concise"}
|
||||
}
|
||||
|
||||
def test_translate_thinking_for_model_disabled_stays_plain_string_when_auto_summary_enabled(self):
|
||||
"""Disabled thinking must stay a plain string even when reasoning_auto_summary is on."""
|
||||
import litellm
|
||||
from litellm.llms.anthropic.experimental_pass_through.adapters.transformation import (
|
||||
LiteLLMAnthropicMessagesAdapter,
|
||||
)
|
||||
|
||||
original = litellm.reasoning_auto_summary
|
||||
try:
|
||||
litellm.reasoning_auto_summary = True
|
||||
thinking = {"type": "disabled"}
|
||||
result = LiteLLMAnthropicMessagesAdapter.translate_thinking_for_model(
|
||||
thinking=thinking,
|
||||
model="openai/gpt-5.2",
|
||||
)
|
||||
finally:
|
||||
litellm.reasoning_auto_summary = original
|
||||
|
||||
assert result == {"reasoning_effort": "none"}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Parity tests: redundant empty-text-block sanitization scan removal.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue