From 21b48b2ff552b42d8df11272b8c7436bcf6e0b7f Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:13:22 -0700 Subject: [PATCH] fix: backfill empty codex output in auxiliary client (#5730) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _CodexCompletionsAdapter (used for compression, vision, web_extract, session_search, and memory flush when on the codex provider) streamed responses but discarded all events with 'for _event in stream: pass'. When get_final_response() returned empty output (the same chatgpt.com backend-api shape change), auxiliary calls silently returned None content. Now collects response.output_item.done and text deltas during streaming and backfills empty output — same pattern as _run_codex_stream(). Tested live against chatgpt.com/backend-api/codex with OAuth. --- agent/auxiliary_client.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 7cb8f9f52e5..8052d020ed2 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -260,11 +260,44 @@ class _CodexCompletionsAdapter: usage = None try: + # Collect output items and text deltas during streaming — + # the Codex backend can return empty response.output from + # get_final_response() even when items were streamed. + collected_output_items: List[Any] = [] + collected_text_deltas: List[str] = [] with self._client.responses.stream(**resp_kwargs) as stream: for _event in stream: - pass + _etype = getattr(_event, "type", "") + if _etype == "response.output_item.done": + _done = getattr(_event, "item", None) + if _done is not None: + collected_output_items.append(_done) + elif "output_text.delta" in _etype: + _delta = getattr(_event, "delta", "") + if _delta: + collected_text_deltas.append(_delta) final = stream.get_final_response() + # Backfill empty output from collected stream events + _output = getattr(final, "output", None) + if isinstance(_output, list) and not _output: + if collected_output_items: + final.output = list(collected_output_items) + logger.debug( + "Codex auxiliary: backfilled %d output items from stream events", + len(collected_output_items), + ) + elif collected_text_deltas: + assembled = "".join(collected_text_deltas) + final.output = [SimpleNamespace( + type="message", role="assistant", status="completed", + content=[SimpleNamespace(type="output_text", text=assembled)], + )] + logger.debug( + "Codex auxiliary: synthesized from %d deltas (%d chars)", + len(collected_text_deltas), len(assembled), + ) + # Extract text and tool calls from the Responses output for item in getattr(final, "output", []): item_type = getattr(item, "type", None)