Skip to content

[Bug]: Responses-compatible gateways can return sparse lifecycle snapshots that Codex clients do not commit #893

Closed

Description

@0xWinner98

Client or integration

Codex App and Codex CLI

Area

Streaming

Summary

Some OpenAI Responses-compatible gateways return a successful SSE stream but omit canonical fields from lifecycle snapshots. OpenCodex currently relays those snapshots unchanged, and current Codex clients may reject or fail to render the turn even though the upstream request completed with HTTP 200.

The affected payloads are structurally sparse rather than malformed JSON. Examples include lifecycle response objects without output, parallel_tool_calls, tool_choice, or tools; message items without role or content; output_text parts without annotations; reasoning items without summary; and text delta/done events without logprobs.

Expected: an explicit provider-local compatibility option can backfill only missing or structurally invalid canonical fields on the client-facing SSE branch. Existing upstream values must remain authoritative, and the default passthrough path must remain unchanged.

Reproduction

  1. Configure a custom provider with the openai-responses adapter and a Responses-compatible endpoint.
  2. Have the upstream return a successful stream containing sparse lifecycle events equivalent to:
event: response.created
data: {"type":"response.created","response":{"id":"resp_example","object":"response"}}

event: response.output_item.added
data: {"type":"response.output_item.added","item":{"id":"msg_example","type":"message"}}

event: response.output_text.delta
data: {"type":"response.output_text.delta","delta":"hello"}

event: response.completed
data: {"type":"response.completed","response":{"id":"resp_example","object":"response"}}
  1. Send a short request through /v1/responses from Codex.
  2. Observe that the upstream and proxy complete with HTTP 200, while the Codex client may show no final assistant message or fail to commit the response lifecycle.
  3. Compare with the same semantic events after the missing canonical fields are backfilled; the client completes normally.

The sample above is a synthetic, redacted equivalent of the observed wire shape and contains no provider-specific data.

Version

2.10.0 (f9b9440c)

Operating system

macOS 26.5.2 (arm64)

Provider and model

Custom OpenAI Responses-compatible gateway / GPT-compatible routed model

Logs or error output

Upstream HTTP status: 200
Proxy terminal status: completed
Codex client result: no committed final assistant message for the sparse snapshot stream

Screenshots and supporting files

None. A synthetic SSE fixture and regression tests are included in the accompanying PR.

Redacted configuration

{
  "providers": {
    "example": {
      "adapter": "openai-responses",
      "baseUrl": "https://gateway.example/v1",
      "responsesPath": "/responses"
    }
  }
}

Suggested fix

Add a disabled-by-default provider option such as responsesSnapshotRepair. When enabled, apply a client-facing SSE payload rewrite that:

  • backfills only missing or structurally invalid canonical fields;
  • preserves every valid value supplied by the upstream;
  • covers response lifecycle snapshots, output items, content parts, reasoning summary parts, and output-text logprobs;
  • composes with existing image-call and item-ID rewrites;
  • keeps inspection and persistence on the raw upstream bytes;
  • can run inline on the existing explicit Darwin eager-relay path without reintroducing the tee/JS-pull retention shape.

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. github-actions commented on Aug 2, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: unknown.

  2. added
    bugSomething isn't working
    streamingSSE, WebSocket, terminal stream frames
    on Aug 2, 2026
  3. lidge-jun commented on Aug 3, 2026

    @lidge-jun
    Owner

    Confirmed still real on current dev, and PR #928 is now open against it.

    For the record on what happened in between: PR #894 addressed this and was closed unmerged. None of its four commits is an ancestor of dev, and the #892 stack did not absorb the feature — I checked rather than assumed, because "a PR existed" and "the fix shipped" are easy to conflate. src/server/responses/core.ts:1819-1827 still composes only image-generation and item-ID rewrites; responses-snapshot-repair.ts, its config flag, and its tests do not exist.

    Why #894 did not land: 1,168 additions across 23 files, carrying a rewrite of the Darwin relay design unit alongside the fix. The breadth was the problem, not the idea.

    The shape worth landing, recorded in devlog/_plan/260803_sparse_snapshot_repair/000_plan.md: provider-local and default-off, preserving upstream values rather than overwriting them, bounded reconstruction with the translator budget charged and released, covering both SSE and JSON, and leaving the relay design unit alone.

    Reviewing #928 against that.

  4. added
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    on Aug 3, 2026
  5. added a commit that references this issue on Aug 5, 2026
  6. lidge-jun commented on Aug 5, 2026

    @lidge-jun
    Owner

    Fixed on dev in #1025 (merged as 064686b41).

    The repair is opt-in per provider. A sparse snapshot gets its missing fields backfilled, and — the part that actually resolves the reported symptom — the missing lifecycle events are synthesized, so the Codex-facing consumer commits the message instead of waiting on a stream that never announces it. Field normalization alone was not enough: the client needs the events, not a repaired final snapshot.

    An ambiguous or contradictory terminal fails closed to a canonical empty output rather than inventing content, and an explicit output: [] is treated as authoritative.

    Thanks to @0xWinner98 (#928) — the config shape, field backfills, JSON path, and bounds all come from that PR.

    Not in a release yet. This is on dev, and main is at v2.10.0. It ships in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproviderProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportsstreamingSSE, WebSocket, terminal stream frames

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions