From 6d767c88d54d8b57922d4b67f67ed14f9e84af3e Mon Sep 17 00:00:00 2001 From: willcai1984 Date: Wed, 29 Jul 2026 15:34:49 +0800 Subject: [PATCH 1/2] fix(chatgpt): strip unknown Codex item fields before building ResponsesAPIResponse The ChatGPT/Codex backend includes provider-specific fields in `response.output_item.done` SSE events that are not part of the OpenAI Responses API schema: - `phase` on the output item itself (e.g. `"phase": "final_answer"`) - `logprobs` inside content parts When `_build_completed_response_from_chunk` passes these items verbatim to `ResponsesAPIResponse(**response_payload)`, Pydantic validation fails silently (falls through to `model_construct`) and the `output` list ends up empty. This causes LiteLLM to raise: APIConnectionError: ChatgptException - Unknown items in responses API response: [] Fix: filter out unknown fields from each item and its content parts before constructing the response object, so Pydantic validation succeeds and the assistant reply is returned correctly. Reproduces with models: chatgpt/gpt-5.5, chatgpt/gpt-5.6-sol, chatgpt/gpt-5.6-terra, chatgpt/gpt-5.6-luna. --- .../llms/chatgpt/responses/transformation.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/litellm/llms/chatgpt/responses/transformation.py b/litellm/llms/chatgpt/responses/transformation.py index 9774b762396..3f1e9cf07a8 100644 --- a/litellm/llms/chatgpt/responses/transformation.py +++ b/litellm/llms/chatgpt/responses/transformation.py @@ -208,7 +208,22 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig): return None response_payload = dict(response_payload) if not response_payload.get("output") and streamed_output_items: - response_payload["output"] = [item for _, item in sorted(streamed_output_items.items())] + # The Codex backend includes provider-specific fields (e.g. `phase`, + # `logprobs`) in output items that are not part of the Responses API + # schema. Passing them verbatim to ResponsesAPIResponse causes + # Pydantic validation to fail, which leaves `output` empty and + # raises "Unknown items in responses API response: []". Strip the + # extra fields before building the response object. + _EXTRA_FIELDS = {"phase", "logprobs"} + clean_items = [] + for _, item in sorted(streamed_output_items.items()): + ci = {k: v for k, v in item.items() if k not in _EXTRA_FIELDS} + ci["content"] = [ + {k2: v2 for k2, v2 in c.items() if k2 not in _EXTRA_FIELDS} + for c in ci.get("content", []) + ] + clean_items.append(ci) + response_payload["output"] = clean_items if "created_at" in response_payload: response_payload["created_at"] = _safe_convert_created_field(response_payload["created_at"]) try: From c1cfef7e5ab13035d327df98e1f0d09410fc8a3e Mon Sep 17 00:00:00 2001 From: willcai1984 Date: Wed, 29 Jul 2026 17:36:50 +0800 Subject: [PATCH 2/2] style: ruff format transformation.py --- litellm/llms/chatgpt/responses/transformation.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/litellm/llms/chatgpt/responses/transformation.py b/litellm/llms/chatgpt/responses/transformation.py index 3f1e9cf07a8..2d216f481b5 100644 --- a/litellm/llms/chatgpt/responses/transformation.py +++ b/litellm/llms/chatgpt/responses/transformation.py @@ -218,10 +218,9 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig): clean_items = [] for _, item in sorted(streamed_output_items.items()): ci = {k: v for k, v in item.items() if k not in _EXTRA_FIELDS} - ci["content"] = [ - {k2: v2 for k2, v2 in c.items() if k2 not in _EXTRA_FIELDS} - for c in ci.get("content", []) - ] + content_parts: object = ci.get("content", []) + if isinstance(content_parts, list): + ci["content"] = [{k2: v2 for k2, v2 in c.items() if k2 not in _EXTRA_FIELDS} for c in content_parts] clean_items.append(ci) response_payload["output"] = clean_items if "created_at" in response_payload: