Skip to content

Commit 4391788

Browse files
authored
feat(codex): unify ChatGPT subscription onto pi-ai's openai-codex-responses wire (#155)
## Summary Phase 2 of the Codex ChatGPT subscription login. Phase 1 shipped a self-rolled client (SSE parser, ChatGPT headers, JWT accountId extraction, 401 retry) behind a "coming soon" UI gate. pi-ai 0.67.68 ships all of that as a first-class `openai-codex-responses` wire, so this PR deletes our version and routes ChatGPT subscription through the same `core → pi-agent-core → pi-ai` path every other provider already uses. - **Link unified**: no more `isChatgptCodex` branches. `generate` / `generateTitle` / `applyComment` all resolve codex exactly like Anthropic or OpenAI — the only codex-specific code left is the OAuth login flow (`oauth.ts` / `oauth-server.ts` / `token-store.ts`), and that sits outside the generation link. - **Long-agent-run safety**: `GenerateInput.getApiKey` is a new optional async getter; the desktop passes it for codex so pi-agent-core re-reads the token between turns (auto-refreshing within the token store's 5-min buffer). Mid-run sign-out errors propagate the original `CodesignError(PROVIDER_AUTH_MISSING)` rather than being flattened into a plain `PROVIDER_ERROR`. - **Upgrade migration**: boot-time `migrateStaleCodexEntryIfNeeded()` rewrites any Phase-1-shaped provider entry so feat-branch testers don't need to sign out/in. - **UI flipped out of coming-soon**: `ChatgptLoginCard` returns to the three-state login/status/logout flow with i18n in both locales. Net diff: **+758 / −1104**, mostly deletions of Phase 1 self-rolled code pi-ai now provides. ## PRINCIPLES §5b - [x] Compatibility — old API-key configs unchanged; Phase 1 codex entries auto-migrate on boot - [x] Upgradeability — `CHATGPT_CODEX_PROVIDER_ID` + `WireApi` live in `@open-codesign/shared` so future wire additions are one-line changes; OAuth provider entry is system-managed (rewritten idempotently on login/migrate) - [x] No bloat — deletes 963 LOC of duplicated SSE/header/retry; adds 758 LOC (most of which is tests + the OAuth flow that was already there) - [x] Elegance — one `generateViaAgent` code path for every provider; no provider-specific dispatch branches ## Test plan - [x] `pnpm -r typecheck` — green - [x] `pnpm -r test` — **1289** tests pass across 10 packages (+11 new tests: base-url codex behavior, `resolve-api-key` DI helper, `migrateStaleCodexEntryIfNeeded` fork, agent.ts per-turn getApiKey + capture/rethrow) - [x] `pnpm lint` — green - [ ] Manual smoke: sign-in flow, generate with codex active, switch back to API-key provider mid-run - [ ] Manual smoke: sign out mid-long-agent-run → confirm PROVIDER_AUTH_MISSING toast (not generic PROVIDER_ERROR) ## Commits 1. `b8bb1b2` Main implementation — delete self-rolled client, register pi-ai wire, flip UI 2. `375b9c5` First review pass — WireApi dedup, structured auth error, modelsHint ordering, +4 tests 3. `dde3bf3` Second pass — migration, `CHATGPT_CODEX_PROVIDER_ID` shared, `resolve-api-key` DI + 7 tests, per-turn getApiKey 4. `8c443b9` Third pass — capture+rethrow so mid-agent-run auth errors preserve their structured code; +3 agent tests 5. `412f159` Fourth pass — remove dead `comingSoon` i18n key, update changeset 6. `296ac25` Drop obsolete internal Phase 2 resume doc ## Known follow-ups (not blocking) - Usage / cost tracking for codex responses (pi-ai's codex wire emits usage events; `complete()` in `packages/providers` already surfaces them via `GenerateResult`, but the desktop UI's cost display still reads zero because Phase 1 hardcoded it). - Image-attachment support — pi-ai's wire accepts `image` input blocks; the `complete()` shim currently only forwards text. Tracked separately. Signed-off-by: hqhq1025 <1506751656@qq.com>
1 parent 4cec7ea commit 4391788

28 files changed

Lines changed: 1133 additions & 1456 deletions
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
"@open-codesign/providers": minor
3+
"@open-codesign/desktop": minor
4+
"@open-codesign/shared": minor
5+
"@open-codesign/core": minor
6+
"@open-codesign/i18n": patch
7+
---
8+
9+
feat(codex): unify ChatGPT subscription path onto pi-ai's built-in openai-codex-responses wire
10+
11+
Phase 2 of the Codex subscription login work. The self-rolled Codex client
12+
path from Phase 1 is replaced by pi-ai's first-class `openai-codex-responses`
13+
adapter (shipped in pi-ai 0.67.68) so every provider — Anthropic, OpenAI,
14+
Gemini, ChatGPT Codex — now runs through the same core/pi-agent-core route
15+
with no provider-specific branching.
16+
17+
### Schema + routing
18+
- `packages/shared`: extend `WireApiSchema` and `CanonicalWire` with
19+
`openai-codex-responses`; promote `CHATGPT_CODEX_PROVIDER_ID` to shared so
20+
`provider-settings` references the same literal the OAuth module writes
21+
without creating a module cycle.
22+
- `canonicalBaseUrl` passes codex URLs through untouched (pi-ai's wire
23+
appends `/codex/responses` itself); `modelsEndpointUrl` throws for codex
24+
(no discoverable /models endpoint — providers use `modelsHint`).
25+
- `packages/core`, `packages/providers`: `apiForWire` + `synthesizeWireModel`
26+
recognize the new wire; all 4 duplicated `'openai-chat' | …` unions
27+
consolidated onto the shared `WireApi` type.
28+
29+
### Desktop wiring
30+
- New `apps/desktop/src/main/resolve-api-key.ts`: dependency-injected helper
31+
that routes ChatGPT provider id to the token store's auto-refreshing
32+
access token, and every other provider to the keychain-backed API key.
33+
Codex auth failures surface as `CodesignError(PROVIDER_AUTH_MISSING)` so
34+
the renderer's error-code routing stays consistent with the API-key-missing
35+
path. Covered by 7 unit tests via DI.
36+
- `main/index.ts`: `resolveActiveApiKeyFromState` replaces the inline
37+
`isChatgptCodex` validate / dispatch branches in all 4 IPC handlers
38+
(`codesign:v1:generate`, legacy `codesign:generate`, apply-comment,
39+
generate-title). Legacy `codesign:generate` no longer rejects codex.
40+
- Long-running agent runs: `GenerateInput.getApiKey` is a new optional async
41+
getter; the desktop passes it only for codex so pi-agent-core calls back
42+
into the token store on each LLM round-trip (auto-refreshes within the
43+
5-min buffer). Mid-run sign-out errors are captured in a closure variable
44+
and rethrown verbatim from the post-agent branch so the structured
45+
`PROVIDER_AUTH_MISSING` code isn't lost to pi-agent-core's plain-string
46+
failure-message flattening.
47+
48+
### Registration + migration
49+
- `codex-oauth-ipc.ts`: provider entry registers `wire=openai-codex-responses`,
50+
bare `baseUrl=https://chatgpt.com/backend-api`, and the full 9-model catalog
51+
(gpt-5.1 → gpt-5.4-mini), ordered flagship-first.
52+
- `migrateStaleCodexEntryIfNeeded()` runs once at boot and rewrites any
53+
Phase-1-shaped `chatgpt-codex` provider (`wire=openai-responses`,
54+
`baseUrl=/codex`) to the Phase 2 canonical values, so feat-branch testers
55+
don't need to sign out and back in after upgrade. No-op when the entry is
56+
absent or already canonical.
57+
58+
### UI
59+
- `ChatgptLoginCard.tsx`: flipped out of "coming soon" mode back to the full
60+
three-state login/status/logout flow, with i18n keys in both locales.
61+
62+
### Deletions (-963 LOC of Phase 1 code now provided by pi-ai)
63+
- `apps/desktop/src/main/codex-generate.ts` + test
64+
- `apps/desktop/src/main/codex-title.ts`
65+
- `packages/providers/src/codex/client.ts` + test
66+
67+
OAuth-side code (`oauth.ts`, `oauth-server.ts`, `token-store.ts`) is unchanged
68+
— still the only codex-specific code, and it sits outside the generation link.

apps/desktop/src/main/codex-generate.test.ts

Lines changed: 0 additions & 240 deletions
This file was deleted.

0 commit comments

Comments
 (0)