feat(agents): route cohort ChatGPT-plan agents to Codex

Merged
CH
5d ago
+675-63

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 a chatgpt_oauth sign-in that is neither invalid (OpenAI signed it out) nor unreadable, starts on codex with payer chatgpt_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): NativeAgentSessions now hands out codexSessions (P21) for a codex conversation, 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/send by stored runtime, cancel/reset/stream by the luke-codex- prefix.
  • Plan refusals: a planRefusal from 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 answers IMAGE_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 CODEX entry in the coder instructions' TOOL_WORDS (its shell and apply_patch, update_plan for to-dos, its subagents, skills under .agents/skills, its web search; CI is watched with gh pr checks --watch since Codex's shell waits on a long command inside the turn). It goes in as Codex's developer_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_models and update_agent read it.
  • PRIVACY.md: Codex's thread files under CODEX_HOME on the sandbox disk, deleted with the task; only the short-lived access token reaches Codex.
  • The NATIVE_NOT_HERE tool words now say "Claude Code or Codex".

Tests

  • runtime-sessions.test.ts: a codex conversation 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 to codex/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_models for a Codex agent lists GPT models alone; update_agent refuses 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' testApiKey isn'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_exceeded or unverified still 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