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
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