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.

Activity

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

    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