feat(agents): route cohort ChatGPT-plan agents to Codex
Merged
CH
5d ago+675+675+012345678901234567890123456789-63-63-01234567890123456789
P24 of the native-harness rollout: the Codex counterpart of P11 (#4313).
What changes
- Routing (
agent-runtime-choice.ts): a cohort account (LUKE_NATIVE_AGENT_ACCOUNTS) on a GPT model (no fast version), in a function that provides the native harnesses, keeping achatgpt_oauthsign-in that is neitherinvalid(OpenAI signed it out) norunreadable, starts oncodexwith payerchatgpt_plan. Everything else is unchanged: the Claude branch decides exactly as before, and every other start goes to eve with no payer. - Harness (
native-agent-sessions.ts):NativeAgentSessionsnow hands outcodexSessions(P21) for acodexconversation, with the same events/MCP URLs, sequence numbering and per-harness instructions as Claude Code. The router (runtime-sessions.ts) was already runtime-generic:open/sendby stored runtime, cancel/reset/stream by theluke-codex-prefix. - Plan refusals: a
planRefusalfrom a Codex launch or message (none/signed_out/unreadable→agent-plan-signed-out,unreachable→agent-plan-unreachable) is answered as a named refusal, the same way P11 answersIMAGE_PREPARING: in the hosted vocabulary, the client's call failures, the panel's notes, and the agent tools' words. Nothing turns to another payer, and a Start leaves no agent. - Instructions: a
CODEXentry in the coder instructions'TOOL_WORDS(its shell andapply_patch,update_planfor to-dos, its subagents, skills under.agents/skills, its web search; CI is watched withgh pr checks --watchsince Codex's shell waits on a long command inside the turn). It goes in as Codex'sdeveloper_instructions. eve's words are untouched (the default harness is still eve and its entry didn't change). - Model rule: Codex's row in P12's
NATIVE_MODEL_RULE: GPT models only, no fast versions, no context-window choice. The chip,list_modelsandupdate_agentread it. PRIVACY.md: Codex's thread files underCODEX_HOMEon the sandbox disk, deleted with the task; only the short-lived access token reaches Codex.- The
NATIVE_NOT_HEREtool words now say "Claude Code or Codex".
Tests
runtime-sessions.test.ts: acodexconversation reaches the Codex harness from the router, the agent doors' composition, a composer message (under its line id) and a Stop, and eve and Claude Code hear none of it. A Start routes cohort + GPT + sign-in tocodex/chatgpt_plan; a fast GPT model, a signed-out sign-in, no sign-in, outside the cohort, no harness, or a Claude model with no setup-token stays on eve. Every plan refusal is named, and a Start refused by the plan leaves no agent. The existing eve and Claude Code cases are unchanged and still pass.coder-agent.test.ts: a Codex agent's instructions name Codex's tools and none of Luke's dropped ones or Claude Code's.coder-agent-tools.test.ts:list_modelsfor a Codex agent lists GPT models alone;update_agentrefuses a Claude model and a context window in words and accepts a GPT model.
Notes
- Gate B2 (a Preview run of a Codex agent in test mode on an OpenAI API key) is the developer's, later. Heads-up: like Claude Code's,
codexSessions'testApiKeyisn't wired from the deployment's environment yet, so that run needs the same test-mode wiring Gate B needs. - The developer waived per-PR Preview runs for this rollout.
- Judgment call: a sign-in at
quota_exceededorunverifiedstill routes to Codex (a plan limit pauses the agent, per the plan, and never moves it to another payer). P25 owns statuses. - P14 is changing
agentRuntimeChoice's signature (adding a picked payer); whichever lands second will need a small merge. - Out of scope: Start's ChatGPT payer, statuses and the label (P25); native agents from the eve apps (P11b).
Made with Luke