mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-29 06:33:28 +00:00
fix(responses-guardrails): keep a lone system message an input item when the rebuild empties input
When a guardrail's rewrite cannot be patched in place, the handler rebuilds the request through the chat-to-Responses converter. A rebuild left holding only the system message folded it into `instructions` over an empty `input`, which the Responses API rejects. That already happened for string content; folding list content made it happen for list content too, where main kept the item. The rebuild now sends that message as a system item, as the chat bridge already does for a system-only request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b118d8b22e
commit
10d23a60dd
2 changed files with 30 additions and 0 deletions
|
|
@ -505,6 +505,15 @@ def _patch_or_convert_request_fields(
|
|||
input_items, converted_instructions = (
|
||||
LiteLLMResponsesTransformationHandler().convert_chat_completion_messages_to_responses_api(structured_messages)
|
||||
)
|
||||
if not input_items and converted_instructions is not None:
|
||||
# The Responses API rejects an empty input, so a lone system message stays a system item, as the chat
|
||||
# bridge sends a system-only request.
|
||||
system_item: Final = {
|
||||
"type": "message",
|
||||
"role": "system",
|
||||
"content": [{"type": "input_text", "text": converted_instructions}],
|
||||
}
|
||||
return _RequestFields(input=(system_item,), instructions=None)
|
||||
return _RequestFields(input=tuple(input_items), instructions=converted_instructions)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3128,6 +3128,27 @@ class TestPatchEdgeBranches:
|
|||
*trailing,
|
||||
]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"system_content",
|
||||
["Answer from the memo only.", [{"type": "input_text", "text": "Answer from the memo only."}]],
|
||||
)
|
||||
async def test_fallback_leaving_only_the_system_message_keeps_it_an_input_item(self, system_content):
|
||||
"""The Responses API rejects an empty input, so a rebuild left holding only the system
|
||||
message sends it as a system item rather than as instructions over an empty input."""
|
||||
handler = OpenAIResponsesHandler()
|
||||
data = {
|
||||
"model": "gpt-5.6",
|
||||
"input": [{"role": "system", "content": system_content}, {"role": "user", "content": "memo " * 400}],
|
||||
}
|
||||
|
||||
result = await handler.process_input_messages(data, DroppingRewriteGuardrail())
|
||||
|
||||
assert "instructions" not in result
|
||||
assert result["input"] == [
|
||||
{"type": "message", "role": "system", "content": [{"type": "input_text", "text": "Answer from the memo only."}]}
|
||||
]
|
||||
|
||||
def test_item_rewrite_field_ignores_non_string_type(self):
|
||||
from litellm.llms.openai.responses.guardrail_translation.handler import _item_rewrite_field
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue