-
-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Description
What happened?
Bug: Chat-to-Responses API Bridge Doesn't Transform Tool Output Content Types
Summary
When using models that route through the Responses API (e.g., gpt-5.1-codex, o1-pro, o3-pro, o4-*), multimodal tool results fail with a 400 Bad Request because tool output content is passed without type transformation.
Error Message
{
"message": {
"content": "Error occurred: LiteLLM API error: BadRequestError: litellm.BadRequestError: {\"error\":{\"message\":\"litellm.BadRequestError: OpenAIException - {\\n \\\"error\\\": {\\n \\\"message\\\": \\\"Invalid value: 'text'. Supported values are: 'input_text', 'input_image', 'output_text', 'refusal', 'input_file', 'computer_screenshot', and 'summary_text'.\\\",\\n \\\"type\\\": \\\"invalid_request_error\\\",\\n \\\"param\\\": \\\"input[25].output[0].type\\\",\\n \\\"code\\\": \\\"invalid_value\\\"\\n }\\n}. Received Model Group=gpt-5.1-codex\\nAvailable Model Group Fallbacks=None\",\"type\":null,\"param\":null,\"code\":\"400\"}}",
"role": "assistant"
}
}
Parsed error:
- Param:
input[25].output[0].type— 26th message (tool output), first content item - Invalid value:
'text'(Chat Completions format) - Expected:
'output_text','input_image', etc. (Responses API format)
Root Cause & Bug Location
File: litellm/completion_extras/litellm_responses_transformation/transformation.py
Method: convert_chat_completion_messages_to_responses_api
Lines: 162-170
elif role == "tool":
# Convert tool message to function call output format
input_items.append(
{
"type": "function_call_output",
"call_id": tool_call_id,
"output": content, # ❌ BUG: content passed without transformation
}
)
The content is passed directly without calling the existing _convert_content_to_responses_format() method.
Contrast with user/assistant messages (lines 186-196) which correctly transform content:
elif content is not None:
input_items.append(
{
"type": "message",
"role": role,
"content": self._convert_content_to_responses_format( # ✅ Correct
content, cast(str, role)
),
}
)
Content Type Mapping Required
| Chat Completions API | Responses API |
|---|---|
| {"type": "text", "text": "..."} | {"type": "output_text", "text": "..."} |
| {"type": "image_url", "image_url": {"url": "..."}} | {"type": "input_image", "image_url": "..."} |
Note: The image_url value must also be flattened from {"url": "..."} object to just the URL string.
Reproduction
import litellmmessages = [
{"role": "user", "content": "Take a screenshot"},
{
"role": "assistant",
"tool_calls": [{
"id": "call_abc123",
"type": "function",
"function": {"name": "screenshot", "arguments": "{}"}
}]
},
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": [
{"type": "text", "text": "Screenshot captured"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}
]
}
]This fails with 400 Bad Request
response = await litellm.acompletion(
model="openai/gpt-5.1-codex", # Or any Responses API model
messages=messages
)
Suggested Fix
Transform tool output content when it's a list:
elif role == "tool":
# Convert tool message to function call output format
output = content
if isinstance(content, list):
output = self._convert_tool_output_to_responses_format(content)
input_items.append(
{
"type": "function_call_output",
"call_id": tool_call_id,
"output": output,
}
)
With a new helper method:
def _convert_tool_output_to_responses_format( self, content: List[Dict[str, Any]] ) -> List[Dict[str, Any]]: """Convert tool output content types from Chat Completions to Responses API format.""" result = [] for item in content: if not isinstance(item, dict): result.append(item) continueitem_type = item.get("type") if item_type == "text": result.append({"type": "output_text", "text": item.get("text", "")}) elif item_type == "image_url": image_url = item.get("image_url") url = image_url.get("url") if isinstance(image_url, dict) else image_url result.append({"type": "input_image", "image_url": url}) else: result.append(item) return result
Alternatively, the existing _convert_content_to_responses_format method could be extended to handle tool outputs, though note that tool text outputs should use output_text (not input_text).
Affected Models
Models using OpenAI's Responses API internally:
gpt-5.1-codex,gpt-5.1-codex-max,codex-mini-latesto1-pro,o3-proo4-*series
Related Issues
- [Bug]: [bridge for /chat/completion -> /responses API] Images Sent via URL Not Working in /chat/completions for OpenAI o1-pro, o3-pro, codex-mini-latest #11820 - Similar issue for image URLs in user messages (fixed in Completion-To-Responses Bridge: Support passing image url's #11833)
- The fix in Completion-To-Responses Bridge: Support passing image url's #11833 updated user message handling but tool messages were not addressed
Environment
- LiteLLM Version: Latest (Dec 2025)
- Python: 3.11+
- API Endpoint:
/chat/completions→/responsesbridge
Relevant log output
Are you a ML Ops Team?
No
What LiteLLM version are you on ?
1.80.0 proxy server
Twitter / LinkedIn details
No response