fix(stream): keep public SSE responses alive#2666
Conversation
d47cfc0 to
f3e3ac7
Compare
|
Fresh live verification (2026-07-20):
No live promotion was performed; the local reliability gate remains in force. |
v0.5.40 refresh
|
|
Extended heartbeat coverage to OpenAI Chat Completions streams after v0.5.40 testing exposed the same client idle timeout outside the Responses route. Chat streams now emit schema-valid empty chat.completion.chunk frames every 25 seconds of output silence, only at SSE event boundaries, with backpressure and cancellation cleanup. A deterministic 130-second isolated canary observed five 25-second heartbeats, one upstream request, one terminal event, and HTTP 200. Focused tests: 19 passed; ESLint, diff check, and Gitleaks passed. Head: 79be8a1. |
|
Post-deploy verification on v0.5.40 (2026-07-21):
No private aliases, pools, deployment code, or environment-specific routing are included in this PR. |
Evidence correction and final route-local updateAn earlier comment inferred that 124-126 second Exact reproduction uses the current Desktop header combination:
Fresh verification:
No private routing, aliases, credentials, pools, or deployment code are included. |
Summary
/v1/responsesrequests as SSE before account routing or provider headers completeCodex/<version>only at the Responses heartbeat gate, without changing shared client detection or native passthroughchat.completion.chunkevents for translated OpenAI Chat streams during output silenceresponse.failedeventscontext_length_exceededin delayed failuresstream:false, omittedstream, invalid JSON, provider routing, and account fallback unchangedRoot cause
Three related timeout/detection layers existed:
/v1/responsesand translated/v1/chat/completionsoutput.User-Agent: Codex/<version>withX-Initiator: user. Shared detection classifies that initiator as GitHub Copilot before Codex CLI UA checks, so the Responses route selected comment keepalives. Adding Desktop to shared detection would also change native-passthrough behavior. The fix therefore checks the lowercased UA only at the route-local heartbeat decision.Responses handling remains route-local. Chat keepalives wrap only translated OpenAI Chat output after usage and terminal processing; native provider pass-through remains unchanged.
Verification
499d4dbUser-Agent: Codex/0.1.0plusX-Initiator: userselects typed event keepalivescontext_length_exceededand rejects malformed codesgit diff --check: passednpm run build: passed, TypeScript checked, 130 routes generatedresponse.completed,[DONE], and clean EOF; no comment-only heartbeat or failed/incomplete terminal[DONE], and HTTP 200X-Initiatorshadowing resolved; no blockersNo private aliases, pools, deployment scripts, credentials, or environment-specific routing are included.