From cc63cf28ffa1a30e7c7a39c3e59b8a18c50b97b3 Mon Sep 17 00:00:00 2001 From: Alexsander Hamir Date: Thu, 23 Oct 2025 08:41:37 -0700 Subject: [PATCH] fix(responses-api): simplify reasoning item handling for gpt-5-codex (#15815) Simplifies the _handle_reasoning_item method to only filter out None values without attempting to construct ResponseReasoningItem objects. This approach: - Avoids mutation of encrypted_content in reasoning items - Fixes compatibility with gpt-5-codex and Codex CLI - Removes dependency on ResponseReasoningItem import - Simplifies the code by removing complex fallback logic The previous approach was trying to construct ResponseReasoningItem objects with required fields (id, summary), which caused issues with encrypted payloads. The new approach simply filters None values while preserving all other data intact. Issue: https://github.com/BerriAI/litellm/issues/13484 Reported-by: rajpathak (OpenAI) Tested-by: rajpathak (OpenAI Codex CLI) --- .../llms/openai/responses/transformation.py | 45 +++---------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py index c3abd5155d..bb39ce7a82 100644 --- a/litellm/llms/openai/responses/transformation.py +++ b/litellm/llms/openai/responses/transformation.py @@ -1,7 +1,6 @@ from typing import TYPE_CHECKING, Any, Dict, Optional, Union, cast, get_type_hints import httpx -from openai.types.responses import ResponseReasoningItem from pydantic import BaseModel import litellm @@ -94,14 +93,12 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): if isinstance(item, BaseModel): validated_input.append(item.model_dump(exclude_none=True)) elif isinstance(item, dict): - # Handle reasoning items specifically to filter out status=None + # Handle reasoning items specifically to filter out None values without mutating contents verbose_logger.debug(f"Handling reasoning item: {item}") if item.get("type") == "reasoning": - # Type assertion since we know it's a dict at this point dict_item = cast(Dict[str, Any], item) filtered_item = self._handle_reasoning_item(dict_item) else: - # For other dict items, just pass through filtered_item = cast(Dict[str, Any], item) validated_input.append(filtered_item) else: @@ -112,43 +109,15 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): def _handle_reasoning_item(self, item: Dict[str, Any]) -> Dict[str, Any]: """ - Handle reasoning items specifically to filter out status=None using OpenAI's model. + Handle reasoning items specifically to filter out None values. Issue: https://github.com/BerriAI/litellm/issues/13484 - OpenAI API does not accept ReasoningItem(status=None), so we need to: - 1. Check if the item is a reasoning type - 2. Create a ResponseReasoningItem object with the item data - 3. Convert it back to dict with exclude_none=True to filter None values + OpenAI API does not accept ReasoningItem(status=None), so we need to + make sure optional fields with None are stripped while leaving the + encrypted payload untouched. """ if item.get("type") == "reasoning": - try: - # Ensure required fields are present for ResponseReasoningItem - item_data = dict(item) - if "summary" not in item_data: - item_data["summary"] = ( - item_data.get("reasoning_content", "")[:100] + "..." - if len(item_data.get("reasoning_content", "")) > 100 - else item_data.get("reasoning_content", "") - ) - - # Create ResponseReasoningItem object from the item data - reasoning_item = ResponseReasoningItem(**item_data) - - # Convert back to dict with exclude_none=True to exclude None fields - dict_reasoning_item = reasoning_item.model_dump(exclude_none=True) - - return dict_reasoning_item - except Exception as e: - verbose_logger.debug( - f"Failed to create ResponseReasoningItem, falling back to manual filtering: {e}" - ) - # Fallback: manually filter out known None fields - filtered_item = { - k: v - for k, v in item.items() - if v is not None - or k not in {"status", "content", "encrypted_content"} - } - return filtered_item + filtered_item = {k: v for k, v in item.items() if v is not None} + return filtered_item return item def transform_response_api_response(