fix(responses): propagate chat bridge stream errors

This commit is contained in:
PriyanJindal 2026-09-01 15:22:35 -07:00
parent 97dbd8efcb
commit 1656e7ea64
2 changed files with 105 additions and 0 deletions

View file

@ -1368,6 +1368,21 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator):
)
]
)
elif event_type in (ResponsesAPIStreamEvents.RESPONSE_FAILED, ResponsesAPIStreamEvents.ERROR):
from litellm.responses.streaming_iterator import _error_event_fields, _status_code_for_error_fields
error_payload: Final = (
parsed_chunk.get("response", {}).get("error")
if event_type == ResponsesAPIStreamEvents.RESPONSE_FAILED
else parsed_chunk.get("error")
)
error_message, error_type, error_code = _error_event_fields(error_payload)
raise litellm.APIError(
status_code=_status_code_for_error_fields(error_type, error_code),
message=error_message,
llm_provider="openai",
model="responses",
)
elif event_type == "response.output_item.added":
# New output item added
output_item = parsed_chunk.get("item", {})
@ -1498,6 +1513,29 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator):
)
else:
raise ValueError(f"Chat provider: Invalid text delta {parsed_chunk}")
elif event_type == ResponsesAPIStreamEvents.REFUSAL_DELTA:
refusal: Final = parsed_chunk.get("delta")
if isinstance(refusal, str):
return ModelResponseStream(
choices=[
StreamingChoices(
index=0,
delta=Delta(refusal=refusal),
finish_reason=None,
)
]
)
raise ValueError(f"Chat provider: Invalid refusal delta {parsed_chunk}")
elif event_type == ResponsesAPIStreamEvents.REFUSAL_DONE:
return ModelResponseStream(
choices=[
StreamingChoices(
index=0,
delta=Delta(),
finish_reason=None,
)
]
)
elif event_type == "response.reasoning_summary_text.delta":
content_part = parsed_chunk.get("delta", None)
if content_part:

View file

@ -3796,6 +3796,73 @@ def test_response_incomplete_stream_event_without_details_defaults_to_length():
assert result.choices[0].finish_reason == "length"
@pytest.mark.parametrize(
("event", "expected_status"),
[
(
{
"type": "response.failed",
"response": {
"error": {
"type": "server_error",
"code": "server_error",
"message": "generation failed",
}
},
},
500,
),
(
{
"type": "error",
"error": {
"type": "invalid_request_error",
"code": "invalid_prompt",
"message": "prompt was rejected",
},
},
400,
),
],
)
def test_response_stream_errors_raise_litellm_api_errors(event, expected_status):
from litellm.completion_extras.litellm_responses_transformation.transformation import (
OpenAiResponsesToChatCompletionStreamIterator,
)
iterator = OpenAiResponsesToChatCompletionStreamIterator(
streaming_response=iter([f"data: {json.dumps(event)}"]), sync_stream=True
)
with pytest.raises(litellm.APIError) as exc_info:
next(iterator)
assert exc_info.value.status_code == expected_status
assert event.get("error", event.get("response", {}).get("error"))["message"] in str(exc_info.value)
def test_response_refusal_stream_events_preserve_refusal_delta_without_duplication():
from litellm.completion_extras.litellm_responses_transformation.transformation import (
OpenAiResponsesToChatCompletionStreamIterator,
)
iterator = OpenAiResponsesToChatCompletionStreamIterator(
streaming_response=iter(
[
'data: {"type":"response.refusal.delta","delta":"I cannot help with that."}',
'data: {"type":"response.refusal.done","refusal":"I cannot help with that."}',
]
),
sync_stream=True,
)
delta = next(iterator)
done = next(iterator)
assert delta.choices[0].delta.get("refusal") == "I cannot help with that."
assert done.choices[0].delta.get("refusal") is None
def test_assistant_message_with_tool_calls_keeps_its_content():
"""Regression for https://github.com/BerriAI/litellm/issues/24985.