Skip to content

Fix Codex connect: streaming repair, named accounts, Alt+A picker - #468

Merged
TheGreatAxios merged 8 commits into
mainfrom
codex-connect-fixes
Aug 10, 2026
Merged

Fix Codex connect: streaming repair, named accounts, Alt+A picker#468
TheGreatAxios merged 8 commits into
mainfrom
codex-connect-fixes

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Fixes the "cannot connect Codex" complaint class end to end. Closes CL-5894, CL-5895, CL-5896, CL-5897.

What broke

  • The Codex backend serves some models (gpt-5.6 family) as HTTP 200 with a valid SSE body but no Content-Type header; the harness treats that as an unrecoverable protocol error, so every turn died with "Cannot detect response kind".
  • The model picker hid a provider's connect row once any account existed, so a second ChatGPT account could never be added.
  • Browser sign-in always saved to a profile hard-named "default" — a second sign-in silently overwrote the first account's tokens, and expired tokens had no re-auth surface.

What changed

  • Content-Type repair at the fetch boundary (vendor untouched): a decorator scoped to Codex responses URLs restores the missing header from the request's accept header; unsupported declared types, ambiguous accepts, and non-2xx keep the loud failure. Verified live against the real backend on gpt-5.6-sol.
  • Named OAuth accounts: the connect flow asks for an account name before the browser opens (suggested slug, auto-suffix on collision); reusing an existing name is an explicit re-auth confirm — the recovery path for expired tokens. Unlimited accounts per provider.
  • Alt+A add-provider selector: every first-class provider kind, always listed, with live connected-account counts. On success the picker reopens focused on the new account. The flat /model list drops its connect rows; docs/TUI.md updated.
  • Two integration fixes found in live testing: the inline connect surface now borrows the session's renderer instead of crashing on a second stdin reader, and the overlay host clears stale landing-float offsets so pickers no longer render below the prompt after a landing overlay.

Verification

  • Full suite 4537 pass / 0 fail, typecheck and build clean; regression tests for every fix.
  • Live end-to-end: browser sign-in, second account add, re-auth, and a completed gpt-5.6-sol turn on a real subscription.
  • Reviewed: per-commit critique loops plus a full-branch sign-off review.

The Codex backend serves some models (observed live with the gpt-5.6
family) as HTTP 200 with a valid SSE body but no Content-Type header at
all. The inference harness detects the response protocol from that
header alone, so every turn on those models died with an unrecoverable
protocol error despite a healthy stream. The fetch boundary now restores
the header for Codex responses requests from the protocol the request's
accept header declared; declared-but-unsupported types, ambiguous accept
headers, and non-2xx responses keep the loud failure.
The connect flow always signed in under the same hardcoded profile
name, so a second ChatGPT or xAI account silently overwrote the
first one's tokens and there was no way to re-authorize an existing
account. OAuth choices now insert a name step between provider
selection and login: it prefills a suggested slug that auto-suffixes
on collision, validates the entered slug (lowercase, restricted
charset, length-capped) since it flows into a settings key, and asks
for an explicit confirm before re-authorizing a name that already
exists. The slug lives in its own form field rather than overloading
the provider name field, which only gets the compound catalog name
once login succeeds.
The flat /model list only shows a provider once it has zero connected
accounts, so a second OAuth account (a second Codex or xAI login) had
no path to a connect flow. Alt+A opens a fresh selector over every
first-class provider kind, with a live connected-account count per
row and no already-connected filtering, so a provider stays reachable
no matter how many accounts it already has. Picking a row runs the
same inline connect flow the flat list's connect rows use, and now
reopens the model picker focused on the account's default model
instead of leaving the operator to find it themselves.
Alt+A's add-provider selector is now the only path to connecting a
provider, so the flat list's "connect →" rows and the filtering that
fed them are dead weight: the unconnected-providers plumbing, the
unconnected section of the models-first catalog, and the connect-row
id helpers all go. The connected-choice predicates were only ever
called to build that filtering, so they go too — their matching logic
already lives on in the account-count helper.
Choosing a provider from Alt+A crashed with "Cannot create
CliRenderer: stdin is already used by another CliRenderer": the
inline connect flow asked the setup surface to create its own
renderer while the session's TUI still owned stdin. The surface
already supports a caller-owned renderer, so the session now lends
it its own, suspends the shell's key/paste/submit handling for the
surface's lifetime (Ctrl+C during sign-in must cancel the sign-in,
not interrupt the running agent), and restores prompt focus after.
The overlay host floats absolutely over the landing screen, and the
un-float path only flipped position back to relative. Yoga treats the
leftover top inset as a relative offset, so after any overlay had
opened on the landing, every later in-session overlay — the slash
popup, the model picker — rendered that many rows below its flow
slot, ending up under the prompt and clipped off the screen.
@linear-code

linear-code Bot commented Aug 10, 2026

Copy link
Copy Markdown

CL-5894

CL-5895

CL-5896

CL-5897

@TheGreatAxios
TheGreatAxios merged commit 759fc67 into main Aug 10, 2026
2 checks passed
@TheGreatAxios
TheGreatAxios deleted the codex-connect-fixes branch August 10, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant