fix(openai): recover stale Responses WebSocket connections - #2104
fix(openai): recover stale Responses WebSocket connections#2104rosetta-livekit-bot[bot] wants to merge 6 commits into
Conversation
🦋 Changeset detectedLatest commit: 9459222 The changes in this PR will be included in the next version bump. This PR includes changesets to release 39 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Preserve connection-pool API compatibility while making eager and foreground WebSocket connection work cancellable and leak-free. Co-authored-by: Cursor <cursoragent@cursor.com>
Only reused Responses sockets qualify for stale recovery, and failed HTTP upgrades now terminate their handshake without leaking listeners or sockets. Co-authored-by: Cursor <cursoragent@cursor.com>
Transfer error handling to the Responses wrapper before connect cleanup so protocol failures remain typed and cannot escape as uncaught events. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Completed Rosetta repair and verification at exact head The branch restores ConnectionPool API compatibility; makes connect/prewarm lifecycle cancellable and shutdown-safe; restricts recovery to stale reused sockets; preserves IDs/metrics/errors; and closes upgrade/post-open socket and listener leaks. Deterministic real local TCP/WebSocket fixtures, focused/full tests, typecheck, 40-task build, independent spec/quality review, and exact-head CI are green. Zero unresolved threads; mergeable. Cue is inapplicable because voice cannot create or observe the stale provider WebSocket condition. |
Summary
ConnectionPoolOptions.connectionErrorsource compatibility and add atomic reuse metadataPython parity
Compared with the Python stale-Responses-WebSocket recovery implementation and current JS behavior. Recovery remains restricted to known stale failures on reused sockets; fresh
websocket_closed, ordinary authentication 401s, and fresh send failures are not hidden or retried. The reconnect happens before resend, retries are bounded, and failures preserve normal provider classification.JS additionally tracks and cancels eager/background connection work through the generic ConnectionPool lifecycle.
Tests
connectionErrorcallbacks and omitted rejection valuespnpm typecheck— 33/33 tasks passedpnpm build— 40/40 tasks passedgit diff --check— cleanSpec compliance: APPROVEDandCode quality: APPROVED, no findingsAPI Extractor remains blocked only by documented base-branch namespace-export/missing-config issues; declaration generation passes.
Deterministic transport verification
Credential-free loopback fixtures prove the actual transport predicates:
[0, 0, 1], showing reuse then reconnect before resendwebsocket_closed, ordinary auth 401, and fresh send failures make one attempt and remain visiblex-request-idCue voice is inapplicable: a voice turn cannot create or observe the stale provider WebSocket/401 condition. The local transport boundaries are the behavior-level evidence for this port.
Ported from livekit/agents#6583