fix(openai): Remove automatic summary from reasoning_effort transformation (#16210)

* Fix: Remove automatic summary field from reasoning_effort transformation

Problem:
The _map_reasoning_effort() function was automatically adding
reasoning.summary field when users specified reasoning_effort parameter,
causing 400 errors for users with unverified OpenAI organizations.

Root Cause:
According to OpenAI's official documentation, the summary field is opt-in
and requires organization verification:

"Reasoning summary output [...] will not be included unless you explicitly
opt in to including reasoning summaries."

"Before using summarizers with our latest reasoning models, you may need
to complete organization verification"

Source: https://platform.openai.com/docs/guides/reasoning#reasoning-summaries

Solution:
Remove the automatic inclusion of summary field from all reasoning_effort
levels (high, medium, low, minimal). Users who want reasoning summaries
can explicitly pass reasoning={"effort": "high", "summary": "auto"} in
their requests.

Impact:
- Fixes #16032
- Works for all organizations (verified and unverified)
- Maintains backward compatibility for users passing reasoning object directly
- Follows OpenAI's recommended opt-in approach

Testing:
- All existing tests pass (4/4 tests in transformation suite)
- Manual verification confirms only effort field is included

* test: Fix MockResponse missing headers attribute in test_openai_responses_api

The MockResponse class was missing the 'headers' attribute which caused
APIConnectionError when processing the mock response. Added headers={}
to fix the test.

* feat: Add dict support to reasoning_effort parameter

Allow users to pass reasoning_effort as either:
- String: reasoning_effort="high" (no summary, safe default)
- Dict: reasoning_effort={"effort": "high", "summary": "detailed"} (opt-in)

This preserves backward compatibility while giving users flexibility
to explicitly opt-in to the summary field when needed (for verified
OpenAI organizations).

---------

Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
This commit is contained in:
Cesar Garcia 2025-11-05 00:05:17 -03:00 • committed by GitHub
parent 4e12e3f90d
commit 44a928b631
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -538,16 +538,20 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge):
return cast(List["ALL_RESPONSES_API_TOOL_PARAMS"], responses_tools)
def _map_reasoning_effort(self, reasoning_effort: str) -> Optional[Reasoning]:
def _map_reasoning_effort(self, reasoning_effort: Union[str, Dict[str, Any]]) -> Optional[Reasoning]:
# If dict is passed, convert it directly to Reasoning object
if isinstance(reasoning_effort, dict):
return Reasoning(**reasoning_effort)
# If string is passed, map without summary (default)
if reasoning_effort == "high":
return Reasoning(effort="high", summary="detailed")
return Reasoning(effort="high")
elif reasoning_effort == "medium":
# docs say "summary": "concise" is also an option, but it was rejected in practice, so defaulting "auto"
return Reasoning(effort="medium", summary="auto")
return Reasoning(effort="medium")
elif reasoning_effort == "low":
return Reasoning(effort="low", summary="auto")
return Reasoning(effort="low")
elif reasoning_effort == "minimal":
return Reasoning(effort="minimal", summary="auto")
return Reasoning(effort="minimal")
return None
def _map_responses_status_to_finish_reason(self, status: Optional[str]) -> str: