Skip to content

fix(codex): harden Responses streaming against terminal-shape drift - #33755

Closed
alexpartisan wants to merge 1 commit into
NousResearch:mainfrom
alexpartisan:fix/codex-stream-event-consumer
Closed

fix(codex): harden Responses streaming against terminal-shape drift#33755
alexpartisan wants to merge 1 commit into
NousResearch:mainfrom
alexpartisan:fix/codex-stream-event-consumer

Conversation

@alexpartisan

Copy link
Copy Markdown

Summary

This PR hardens Hermes' Codex Responses streaming path against provider/SDK payload-shape drift that was producing user-visible failures in Weixin and CLI flows.

Problem

In production, we observed these recurring error patterns:

  • TypeError: 'NoneType' object is not iterable
  • Non-retryable error (HTTP None)
  • Responses create(stream=True) fallback did not emit a terminal response

These failures were intermittent and often surfaced as misleading non-retryable client errors, despite being upstream stream-shape compatibility issues.

Root Cause

The previous Codex path depended on high-level typed reconstruction behavior that could break when terminal response payloads had shape drift (e.g. null/empty output structures). In some paths, tools handling could also trigger pre-request iterable errors when effectively empty.

Changes

1) Event-driven Codex stream consumption

  • Switched Codex runtime stream handling to responses.create(stream=True) event consumption.
  • Added _consume_codex_event_stream to assemble final response from streamed events (response.output_item.done, deltas, terminal events) rather than relying on fragile terminal payload reconstruction.

2) Auxiliary path alignment

  • Updated Codex auxiliary client path to use the same event-driven stream consumer logic.

3) Safer tools serialization

  • In Codex transport, omit tools entirely when no tools are available (instead of passing an empty/null-like shape).

4) Error classification resilience

  • In conversation loop, avoid hard non-retryable classification for the known provider-shape NoneType not iterable pattern so normal retry/fallback can proceed.

Files Changed

  • agent/codex_runtime.py
  • agent/auxiliary_client.py
  • agent/transports/codex.py
  • agent/conversation_loop.py

Validation

  • Local compile check passed for all changed Python files.
  • Real oneshot validation passed (including tool call roundtrip) after patching.
  • Gateway runtime revalidated with gateway_state=running and weixin=connected.

Risk / Compatibility

  • Scope is limited to Codex stream handling and related error-path hardening.
  • Non-Codex model paths are untouched.
  • Behavior change is intentionally conservative: prefer robust event consumption and retry/fallback over premature non-retryable termination.

- switch codex stream consumption to responses.create(stream=True) event-driven assembly

- align auxiliary codex path with the same event consumer

- omit tools field when no tools are available (avoid None iterable path)

- classify NoneType/not-iterable provider shape failures as retryable in conversation loop
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint codex P3 Low — cosmetic, nice to have labels May 28, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for this — closing as already fixed on main.

The Codex null-output crash (response.completed with output: null from the chatgpt.com backend → TypeError: 'NoneType' object is not iterable → surfaced as "non-retryable HTTP None") is resolved by commits already on main:

  • cb38ce28c — drop the SDK responses.stream() helper and consume events directly, rebuilding output from response.output_item.done events so the null terminal-event output is never iterated (refactor(codex): drop SDK responses.stream() helper; consume events directly #33042).
  • 43a3f119f — recover Codex streams with null output.
  • dc9d677d5 — classify TypeError('NoneType … not iterable') as a retryable provider-shape error so retry/fallback runs instead of killing the turn.

Your fix targets the same path that's now hardened upstream, so there's nothing left to merge here. Your authorship is preserved in your branch; I'm crediting your report in the umbrella issue #33932 (now closed). Appreciate the contribution.

@teknium1 teknium1 closed this Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants