fix(responses-bridge): map system-only chat request to system input item (#29817)

System-only chat requests mapped the system message to instructions and left
input=[], which OpenAI's Responses API rejects (it also rejects input=""). When
no other messages are present, carry the system message as a role:"system" input
item (single copy, correct role) instead of leaving input empty. Mirrors the
existing handling of non-string system content. Fixes Open WebUI new-conversation
failures on mode:responses Codex models.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
milan-berri 2026-06-07 02:11:54 +03:00 committed by GitHub
parent 68d67212cd
commit 273855b4e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 0 deletions

View File

@ -402,6 +402,20 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge):
instructions,
) = self.convert_chat_completion_messages_to_responses_api(messages)
# OpenAI's Responses API rejects an empty input. For a system-only
# request, carry the system message as a system-role input item instead
# of instructions, mirroring how non-string system content is already
# handled in convert_chat_completion_messages_to_responses_api.
if not input_items and instructions is not None:
input_items = [
{
"type": "message",
"role": "system",
"content": [{"type": "input_text", "text": instructions}],
}
]
instructions = None
optional_params = self._extract_extra_body_params(optional_params)
# Build responses API request using the reverse transformation logic

View File

@ -13,6 +13,9 @@ sys.path.insert(
0, os.path.abspath("../../..")
) # Adds the parent directory to the system-path
import litellm
from litellm.completion_extras.litellm_responses_transformation.transformation import (
LiteLLMResponsesTransformationHandler,
)
def test_convert_chat_completion_messages_to_responses_api_image_input():
@ -860,6 +863,39 @@ def test_extract_extra_body_params_reasoning_effort_override():
assert "extra_body" not in result
def test_transform_request_system_only_message_maps_to_system_input_item():
"""System-only requests must not send input=[] to the Responses API.
OpenAI rejects both input=[] and input="". When the only message is a
system message, carry it as a system-role input item (single copy, correct
role) rather than leaving input empty or duplicating it into instructions.
"""
handler = LiteLLMResponsesTransformationHandler()
logging_obj = Mock()
messages = [{"role": "system", "content": "You are a helpful assistant."}]
result = handler.transform_request(
model="gpt-5.3-codex",
messages=messages,
optional_params={},
litellm_params={},
headers={},
litellm_logging_obj=logging_obj,
)
assert result["input"] == [
{
"type": "message",
"role": "system",
"content": [
{"type": "input_text", "text": "You are a helpful assistant."}
],
}
]
# System content lives in input only; not duplicated into instructions.
assert not result.get("instructions")
def test_transform_request_single_char_keys_not_matched():
"""Test that single-character keys are not incorrectly matched to 'metadata' or 'previous_response_id'