Merge pull request #21491 from Chesars/fix/20998-remove-hardcoded-reasoning-summary

fix(anthropic): remove hardcoded reasoning summary in adapter
This commit is contained in:
Cesar Garcia 2026-03-03 15:29:11 -03:00 • committed by GitHub
commit a8b5a876bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 13 deletions

View file

@ -44,8 +44,7 @@ class LiteLLMMessagesToCompletionTransformationHandler:
For OpenAI models, Chat Completions typically does not return reasoning text
(only token accounting). To return a thinking-like content block in the
Anthropic response format, we route the request through OpenAI's Responses API
and request a reasoning summary.
Anthropic response format, we route the request through OpenAI's Responses API.
"""
custom_llm_provider = completion_kwargs.get("custom_llm_provider")
if custom_llm_provider is None:
@ -80,16 +79,7 @@ class LiteLLMMessagesToCompletionTransformationHandler:
if isinstance(reasoning_effort, str) and reasoning_effort:
completion_kwargs["reasoning_effort"] = {
"effort": reasoning_effort,
"summary": "detailed",
}
elif isinstance(reasoning_effort, dict):
if (
"summary" not in reasoning_effort
and "generate_summary" not in reasoning_effort
):
updated_reasoning_effort = dict(reasoning_effort)
updated_reasoning_effort["summary"] = "detailed"
completion_kwargs["reasoning_effort"] = updated_reasoning_effort
@staticmethod
def _prepare_completion_kwargs(

View file

@ -241,7 +241,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
effort = "low"
else:
effort = "minimal"
return {"effort": effort, "summary": "detailed"}
return {"effort": effort}
def translate_request(
self,

View file

@ -180,7 +180,8 @@ def test_openai_model_with_thinking_converts_to_reasoning():
assert "reasoning" in call_kwargs, "reasoning should be passed to litellm.responses"
# budget_tokens=1024 -> effort="minimal" (< 2000 threshold)
expected_reasoning = {"effort": "minimal", "summary": "detailed"}
# summary should NOT be hardcoded — it's opt-in per the OpenAI spec
expected_reasoning = {"effort": "minimal"}
assert call_kwargs["reasoning"] == expected_reasoning, (
f"reasoning should be {expected_reasoning} for budget_tokens=1024, "
f"got {call_kwargs.get('reasoning')}"
@ -222,3 +223,38 @@ class TestThinkingParameterTransformation:
assert result == {"reasoning_effort": "minimal"}
assert "thinking" not in result
class TestNoHardcodedReasoningSummary:
"""Tests for issue #20998: adapter must not hardcode reasoning summary.
Per OpenAI spec, reasoning.summary is opt-in. The adapter should not
inject summary='detailed' when the user didn't request it.
"""
def test_no_summary_added_when_not_requested(self):
"""reasoning_effort dict should only contain 'effort', no 'summary'."""
from litellm.llms.anthropic.experimental_pass_through.adapters.handler import (
LiteLLMMessagesToCompletionTransformationHandler,
)
thinking = {"type": "enabled", "budget_tokens": 5000}
completion_kwargs = {"model": "openai/gpt-5.1", "reasoning_effort": "medium"}
LiteLLMMessagesToCompletionTransformationHandler._route_openai_thinking_to_responses_api_if_needed(
completion_kwargs, thinking=thinking
)
assert completion_kwargs["reasoning_effort"] == {"effort": "medium"}
assert "summary" not in completion_kwargs["reasoning_effort"]
def test_model_prefixed_with_responses(self):
"""Model should be prefixed with 'responses/' for Responses API routing."""
from litellm.llms.anthropic.experimental_pass_through.adapters.handler import (
LiteLLMMessagesToCompletionTransformationHandler,
)
thinking = {"type": "enabled", "budget_tokens": 5000}
completion_kwargs = {"model": "openai/gpt-5.1", "reasoning_effort": "medium"}
LiteLLMMessagesToCompletionTransformationHandler._route_openai_thinking_to_responses_api_if_needed(
completion_kwargs, thinking=thinking
)
assert completion_kwargs["model"] == "responses/openai/gpt-5.1"