Skip to content

Feature request: opt-in upstream Responses WebSocket transport for OpenAI-compatible providers #2816

Description

@gulup

Area

Streaming

What are you trying to accomplish?

I want opencodex to dial an OpenAI-compatible upstream over the Responses WebSocket transport, not only the canonical `chatgpt.com/backend-api/codex/responses` URL. Concretely: opencodex fronts a self-hosted aggregator (sub2api) whose `/v1/responses` path speaks the Responses WebSocket protocol, and whose upstream (OpenAI) leg is measurably faster over WS than over HTTP SSE.

What prevents this today?

`shouldUseCodexWsUpstream()` accepts only the canonical ChatGPT backend URL; every other provider always gets plain HTTP SSE. In addition, the aggregator classifies an HTTP-ingress request as `client_protocol_http` and forces its own upstream hop to HTTP SSE too (sub2api does this in `resolveOpenAIWSDecisionByClientTransport`), so the fast WS queue on the upstream leg is unreachable — the same ~1.0s vs ~3.9s TTFT gap opencodex itself measured on the ChatGPT backend.

Old sessions keep working, but new sessions opened after enabling the client-facing `websockets` option can be mis-routed to the default ChatGPT account pool and fail with `The '' model is not supported when using Codex with a ChatGPT account.` — which is exactly the inability to opt a specific provider into upstream WS.

What should OpenCodex do?

Add a provider-level opt-in flag, e.g. `upstreamWebsocket: true` on a provider entry. When set, streaming POST turns whose URL ends in `/responses` should be dialed over ws(s) using the existing bounded WS relay: send the body as a single `response.create` frame, re-encode event frames as SSE, and preserve routing, multi-key failover, usage sniffing, and the client stream shape. HTTP fallback on handshake rejection (401/403/429/5xx), upgrade timeout, oversized create frames, and Bun < 1.4 must remain in place. Canonical ChatGPT backend behaviour should not change.

Example usage or interface

```json
{
"providers": {
"igame": {
"adapter": "openai-responses",
"baseUrl": "https://sub2api.example.com",
"apiKey": "sk-...",
"upstreamWebsocket": true
}
}
}
```

With the flag enabled, the upstream hop becomes `wss://sub2api.example.com/v1/responses` and the aggregator records the request as its WebSocket (`ws_v2`) type instead of `stream`.

Alternatives or workarounds

Connecting Codex directly to the aggregator (skipping opencodex) does reach the WS path, but loses opencodex routing, multi-key pools, and the aggregated request pipeline. Keeping opencodex without the flag leaves every upstream hop on HTTP SSE.

Additional context

I have a working local patch implementing this: new provider field `upstreamWebsocket`, URL-derived wss dial (`wsUpstreamUrlFor`), `/responses` path eligibility check, and unit tests; `bun x tsc --noEmit` clean. Happy to turn it into a PR if this direction is acceptable. Related existing work: #1558 / #1487 (canonical ChatGPT upstream WS), #2426 / #2482 (WS frame sizing). I searched existing issues and found no request for third-party upstream WS.

Checks

  • I searched existing issues and documentation.
  • This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
  • I removed secrets and personal data.

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansenhancementNew feature or requestproviderProvider adapters, OpenAI-compat presets, upstream API quirksstreamingSSE, WebSocket, terminal stream frames

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions