* fix(release): drain the twelve reds every PR against release/v3.8.51 was born with Measured on the cycle tip: fifteen unit files were red on every PR. Two came from the v3.8.50 sync-back (fixed in #11929); the other thirteen predate it and are the branch's own drift. This sweep clears all of them but the ESLint debt (#11924), each with the smallest change that keeps the guard honest: - .env.example + ENVIRONMENT.md: NEXT_PUBLIC_SW_BUILD_ID / OMNIROUTE_SW_BUILD_ID / SOURCE_VERSION (#11779 service-worker cache busting) documented — the env/docs contract gate was failing on every PR. - stryker.conf.json: the six tests the mutation gate found covering mutated modules (four retirement runtime-block suites, combo connection-aware expansion, tunnel error sanitization) registered in tap.testFiles. - dependency-allowlist: eslint-plugin-react-hooks 7.0.1 approved; its findings are tracked in #11924. - i18n: the six combo.sort.* strings (d5dfcfff58) translated for vi (strict parity) and pt-BR. - docs/providers/CHATGPT_WEB.md: the retirement test is migration-168, not 163. - g4f gateways: authHint now says member key, which the discontinued-providers guard asserts. - tests realigned to the catalog the branch actually ships: qwen-web (#11713) and chatgpt-web (#11720) are retired, so web-session-contract and token-health-check-webcookie use perplexity-web, grok-web and chatgpt-web-codex. - db-core-init: the two minimal legacy fixtures gained the columns migrations 164-168 UPDATE (error_code, last_error*, test_status) — they exist on every real legacy DB (base CREATE TABLE); the fixtures simply never declared them. - no-js-extension guard: a .js specifier whose target is a genuine JavaScript file (open-sse/lib/deepseek-pow-hash.js, shared with a worker) is not the #10674 defect; the test now skips targets that exist as .js. All twelve files pass locally; docs-sync, docs-counts, env-doc-sync, the tap drift gate and the fabricated-docs gates are green on the tree. * test(release): move the deferred-finish translator test into a collected path tests/unit/translator/ is not one of the unit collectors (package.json test:unit, merge-train.sh, build-test-impact-map, check-test-discovery), so the suite thatdd35750e5fadded there never ran — check:test-discovery flagged it as a new orphan on every PR. Relocated next to its sibling openai-to-claude-trailing-usage-11817 under tests/unit/, where the root glob collects it (5/5 pass). * fix(dashboard): type the four sort-method sites #11812 left red on the dashboard typecheck ratchetd5dfcfff58added the combo model sort and raised combos/page.tsx from 23 to 27 scoped TypeScript errors (TS2339 +1, TS2345 +2, TS2322 +1), which fails check:dashboard-typecheck on every PR against release/v3.8.51: - initialSortMethod: sanitizeComboRuntimeConfig() is untyped, so config.modelSort is unknown; narrow it before reading .method (normalizeSortMethod takes unknown anyway). - handleAddModels: the batch path passes ComboBuilderDraftModelStep[] to the ComboStep[] sort helpers without the cast handleSortChange already uses; mirror it. - ComboSortSelect expects a translate-with-fallback (k, f) => string, but received next-intl's Translator whose second argument is a values object. Pass the page's getI18nOrFallback adapter instead of the raw translator — that is also what makes the `has()` check and the fallback text actually work at runtime. Baseline untouched (no widening). Scoped tsc: 0 new/regressed errors.
5.6 KiB
title, version, lastUpdated
| title | version | lastUpdated |
|---|---|---|
| Providers — ChatGPT Web (Codex) | 3.8.50 | 2026-08-26 |
Providers — ChatGPT Web (Codex)
chatgpt-web-codex (alias cgpt-codex) bridges Codex Responses turns through an
authenticated ChatGPT browser session. It is independent from the retired common
chatgpt-web provider and uses the MIT-noticed implementation under
open-sse/vendor/codex-chatgpt-web/.
Common provider retirement
The former common provider IDs chatgpt-web and cgpt-web no longer ship because the
provenance of their pre-key/proof-of-work implementation could not be cleared. Explicit
requests to either ID, including slash-prefixed model IDs and persisted aliases, fail
closed with HTTP 410 and code PROVIDER_RETIRED before any upstream request.
Migration 163_retire_chatgpt_web.sql tombstones matching provider connections and
invalidates their active session leases. It preserves connection history and API-key
allowlists; it does not add replacement access to an allowlist. The Codex provider and
its connections are not matched by this retirement.
Prerequisites
- a full Cookie header from a signed-in ChatGPT session;
- Chrome or Chromium for npm, systemd, and PM2 installs;
- with the Docker
webprofile, the internal Chromium service fromdocker-compose.yml; - an OpenAI tunnel and a ChatGPT custom connector for local Codex tools.
The tunnel is only needed for tool turns. The pro model is read-only and does not need
a local tool connector.
Dashboard setup
- Open the ChatGPT Web (Codex) provider and add a connection.
- Paste the full ChatGPT Cookie header, tunnel ID, runtime key, and custom connector name.
- Run the connection check. OmniRoute opens a headless Temporary Chat and detects
whether
prois available for the account. - Save the connection. OmniRoute replaces the pasted cookie with the verified Playwright storage state and stores it with the runtime key through the encrypted credential abstraction.
The raw cookie is not retained after a successful save. When the session expires, open the connection, paste a fresh full Cookie header, and rerun the check. The doctor status in the edit dialog reports browser, storage state, sign-in, Temporary Chat, tunnel, connector, and tool round-trip separately.
Never commit a real cookie, runtime key, storage state, or capability token. Test and documentation values must always be placeholders.
Models and combos
The fixed model routes are:
chatgpt-web-codex/instantchatgpt-web-codex/mediumchatgpt-web-codex/highchatgpt-web-codex/extra-highchatgpt-web-codex/pro
Add one of them to a combo like any other model. The Codex app sends the combo name as
model to the regular Responses endpoint, /v1/responses; there is no separate Codex
endpoint or mode switch.
pro does not run local tools. A forced tool makes that combo target incompatible. With
optional tools, the turn runs read-only and reports the limitation as commentary.
Security model
- The native path requires a Responses request, a recognized Codex client, and matching thread and turn identities.
- Workspace, sandbox, approval policy, and tool catalog come from the native Codex shell; free-form prompt text is not authority for them.
- ChatGPT receives only a short-lived capability per turn. The MCP broker accepts only tools Codex offered in that exact turn.
- Auto-confirming Allow once only returns the tool request to Codex. Codex alone decides on approval and execution.
- Before the first output, a combo may fall back to another compatible target. After output begins, provider, model, connection, and browser turn remain pinned until the turn completes.
- Cookies, runtime keys, storage state, and capability tokens do not appear in provider responses or request logs.
Headless VPS and Docker
For npm, systemd, and PM2 installs, OmniRoute detects common Chrome and Chromium paths.
Alternatively, set CHATGPT_WEB_CODEX_CHROME_PATH.
The Docker web profile starts chatgpt-web-codex-browser on the internal Compose
network. Its CDP port is not published on the host. The protected browser profile volume
is separate from the OmniRoute data volume, and the browser receives enough shared
memory. The internal CDP proxy listens only on port 9223 inside the Compose network;
Chrome remains bound to loopback in the sidecar.
A supervisor lease under DATA_DIR prevents multiple OmniRoute processes from owning
the same tunnel and broker state. A conflict is reported by the doctor.
Interactive recovery
The normal path is headless. When ChatGPT requires an interactive sign-in or challenge, the existing VNC browser infrastructure can be used for recovery. Browser UI and CDP must remain reachable only over loopback, an authenticated management connection, or an SSH tunnel; noVNC stays disabled during normal operation.
WebSocket fallback
When a combo contains ChatGPT Web (Codex), the Responses WebSocket bridge requests the
HTTP/SSE fallback before connecting upstream. The transfer then goes through
/v1/responses.
Verification
Run the provider controls without invoking the retired provider:
node --import tsx/esm --test \\
tests/unit/chatgpt-web-codex.test.ts \\
tests/unit/chatgpt-web-codex-turn-pin.test.ts \\
tests/unit/chatgpt-web-environment-double-unescape.test.ts
Retirement regression guards live in:
tests/unit/chatgpt-web-retirement.test.tstests/unit/chatgpt-web-runtime-block.test.tstests/unit/chatgpt-web-image-handler-retirement.test.tstests/unit/chatgpt-web-source-retirement.test.tstests/unit/migration-168-retire-chatgpt-web.test.ts