mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-24 00:52:24 +00:00
fix(chatgpt): aggregate output items for non-streaming responses
When a non-streaming client calls /v1/responses (or /v1/chat/completions bridged to responses) for the chatgpt provider, the proxy reads the SSE stream from chatgpt.com/backend-api/codex and aggregates it into a single ResponsesAPIResponse. The aggregator currently builds the response only from the final `response.completed` event's `response` field — but the ChatGPT backend leaves `response.output` empty on that final event and emits the actual items in earlier `response.output_item.done` events. The result: HTTP 200, status `completed`, usage populated, but `output: []` — clients see no content even though the call succeeded and tokens were billed. Fix: collect items from `response.output_item.done` events as the SSE stream is parsed, and if the final `response.completed` payload's `output` is empty, fall back to the collected list. No-op when the backend does populate `output` directly (e.g. future API versions). Verified against a ChatGPT Pro subscription via Codex CLI OAuth tokens: both /v1/responses and /v1/chat/completions (bridged) now return the assistant's text content for chatgpt/gpt-5.4 and chatgpt/gpt-5.3-codex. Streaming path is unchanged.
This commit is contained in:
parent
fa81017e12
commit
3c698caf83
1 changed files with 12 additions and 0 deletions
|
|
@ -134,6 +134,7 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig):
|
|||
|
||||
completed_response = None
|
||||
error_message = None
|
||||
collected_output_items: list = []
|
||||
for chunk in body_text.splitlines():
|
||||
stripped_chunk = CustomStreamWrapper._strip_sse_data_from_chunk(chunk)
|
||||
if not stripped_chunk:
|
||||
|
|
@ -150,10 +151,21 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig):
|
|||
if not isinstance(parsed_chunk, dict):
|
||||
continue
|
||||
event_type = parsed_chunk.get("type")
|
||||
if event_type == ResponsesAPIStreamEvents.OUTPUT_ITEM_DONE:
|
||||
item = parsed_chunk.get("item")
|
||||
if isinstance(item, dict):
|
||||
collected_output_items.append(item)
|
||||
continue
|
||||
if event_type == ResponsesAPIStreamEvents.RESPONSE_COMPLETED:
|
||||
response_payload = parsed_chunk.get("response")
|
||||
if isinstance(response_payload, dict):
|
||||
response_payload = dict(response_payload)
|
||||
# ChatGPT backend leaves response.output empty on the final
|
||||
# `response.completed` event and emits items via earlier
|
||||
# `response.output_item.done` events; reassemble here so
|
||||
# non-streaming clients receive a populated output array.
|
||||
if not response_payload.get("output") and collected_output_items:
|
||||
response_payload["output"] = collected_output_items
|
||||
if "created_at" in response_payload:
|
||||
response_payload["created_at"] = _safe_convert_created_field(
|
||||
response_payload["created_at"]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue