Repository navigation
fix(chat): codex exec OPTIONS must precede resume subcommand (multi-turn resume) - #21
Conversation
…ti-turn resume Codex's CLI grammar is `codex exec [OPTIONS] resume <SESSION_ID> [PROMPT]` (confirmed via `codex exec --help`, codex-cli 0.139.0): `resume` is a subcommand of `exec`, so every exec-level OPTION (--json, --model, sandbox/approval flags, --ignore-user-config, --skip-git-repo-check, -C <dir>) must precede it; only SESSION_ID and PROMPT follow. Both codex argv builders emitted `resume <id>` immediately after `exec`, BEFORE the option flags. On a resume turn codex parsed `resume` first and then rejected the trailing exec options against the resume subparser with `error: unexpected argument '-C' found`, breaking multi-turn resume for codex chats. - src/main/chat/providers/agent-mode-payloads.ts (buildCodexSpawnArgs): the runtime path chatCodex spawns. Push all option flags first, THEN `resume <threadId>`, THEN the prompt. - packages/codesurf-daemon/bin/chat-jobs.mjs (buildCodexExecArgs): the daemon path. Same reorder. (This builder introduced the defect in 64980c8 "Fix daemon multi-turn chat continuity".) Non-resume (first-turn) argv is functionally unchanged: just `exec <flags> <prompt>`. Audit of every harness resume invocation in the daemon — no other site repeats the subcommand-before-options defect: - src/main/relay/provider-executor.ts runCodexTurn — no resume path (clean) - src/main/session-sources.ts:1384, packages/.../session-index.mjs:923 — `resumeBin`/`resumeArgs` launch metadata for the interactive `codex resume <id>` TUI (not `codex exec`); top-level command, order- independent (clean) - hermes (--resume <id>), claude (--resume / SDK options.resume), opencode (--session) — all flag-form, order-independent (clean) Claude resume (claude.ts:725 options.resume) was investigated and verified CORRECT — not the same bug class. `resume` is a named SDK option, immune to positional ordering. A live 2-turn SDK spike (haiku, claude-opus-4-7, and with the named-agent options chatClaude sets) resumes correctly every time; the renderer round-trip is intact (useChatStreamHandler captures the `session` event → useChatTileMessaging sends `sessionId` on the next turn). The desktop "claude" provider dispatches to chatClaude (chat.ts:1025), the verified path. No provider-level Claude fix is warranted. Tests: - packages/codesurf-daemon/test/codex-exec-args.test.mjs (new): assert buildCodexExecArgs puts all options before `resume`, `-C` never follows `resume`, and fresh turns omit `resume`. - test/daemon/chat-jobs-agent-mode.test.mjs: corrected the prior test that asserted the buggy `resume`-immediately-after-`exec` order; added direct coverage for buildCodexSpawnArgs (BUG 1's actual function).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughBoth ChangesCodex argv ordering fix
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Fixes broken multi-turn resume for the Codex CLI provider by ensuring codex exec options are emitted before the resume subcommand, matching Codex’s grammar (codex exec [OPTIONS] resume <SESSION_ID> [PROMPT]). This restores continuity on resumed turns while keeping first-turn behavior effectively unchanged.
Changes:
- Reordered Codex argv construction so exec-level flags precede
resume <id>in both runtime and daemon builders. - Updated/added tests to assert
resumeplacement and prevent regressions (especially ensuring-C <dir>never appears afterresume).
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/main/chat/providers/agent-mode-payloads.ts |
Reorders buildCodexSpawnArgs to place all exec options before resume <threadId> (runtime spawn path). |
packages/codesurf-daemon/bin/chat-jobs.mjs |
Reorders buildCodexExecArgs to place all exec options before resume <sessionId> (daemon exec path). |
test/daemon/chat-jobs-agent-mode.test.mjs |
Updates daemon resume test expectations and adds runtime buildCodexSpawnArgs ordering coverage. |
packages/codesurf-daemon/test/codex-exec-args.test.mjs |
New unit tests specifically guarding daemon buildCodexExecArgs resume ordering invariants. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Problem
Resuming a multi-turn codex chat was broken. Codex's CLI grammar is
codex exec [OPTIONS] resume <SESSION_ID> [PROMPT](confirmed viacodex exec --help, codex-cli 0.139.0) —resumeis a subcommand ofexec, so every exec-level OPTION (--json,--model, sandbox/approval flags,--ignore-user-config,--skip-git-repo-check,-C <dir>) must come beforeresume; only SESSION_ID and PROMPT follow it.Both codex argv builders emitted
resume <id>immediately afterexec, before the flags. On a resume turn codex matched theresumesubcommand first and rejected the trailing options against the resume subparser:Codex argv (resume case) — before → after
First-turn (non-resume) argv is functionally unchanged.
Fixes
src/main/chat/providers/agent-mode-payloads.ts(buildCodexSpawnArgs) — runtime pathchatCodexspawns. Options first, thenresume <threadId>, then prompt.packages/codesurf-daemon/bin/chat-jobs.mjs(buildCodexExecArgs) — daemon path. Same reorder. (This builder introduced the defect in64980c8.)Audit (same bug class)
No other harness resume site repeats the subcommand-before-options defect:
relay/provider-executor.tsrunCodexTurnsession-sources.ts:1384,session-index.mjs:923resumeBin/resumeArgsmetadata for the interactivecodex resume <id>TUI (notcodex exec); top-level, order-independent--resume <id>), claude (--resume/ SDKoptions.resume), opencode (--session)Claude resume (BUG 2) — investigated, verified correct (no fix)
claude.ts:725 options.resume = existingSessionIdis not the same bug class —resumeis a named SDK option, immune to positional ordering. Verified empirically with a live 2-turn SDK spike (haiku,claude-opus-4-7, and with the named-agent optionschatClaudesets): resume carries context every time, session id stable. The client round-trip is intact (useChatStreamHandlercaptures thesessionevent →useChatTileMessagingsendssessionIdon the next turn), and the desktop "claude" provider dispatches tochatClaude(chat.ts:1025). Field-name, model-resolution, threading, and CLI-ordering candidates were all ruled out. No provider-level Claude fix is warranted.Tests
packages/codesurf-daemon/test/codex-exec-args.test.mjs(new) — assertsbuildCodexExecArgsputs all options beforeresume,-Cnever followsresume, and fresh turns omitresume.test/daemon/chat-jobs-agent-mode.test.mjs— corrected the prior test that asserted the buggyresume-after-execorder; added direct coverage forbuildCodexSpawnArgs.Gates
node --test packages/codesurf-daemon/test/codex-exec-args.test.mjs→ 3/3 passcd packages/codesurf-daemon && npm test→ 14/14 passnpm run test:daemon→ 219 pass / 3 fail; the 3 failures (persist detached background mode,persisted chat job timeline replay,composer pills disabled) are pre-existing on origin/main (verified) and unrelated to codex args.npm run typecheck:go→ edited TS file (agent-mode-payloads.ts) is clean; the 16 remaining tsgo errors are pre-existing baseline in unrelated files.Summary by CodeRabbit
Bug Fixes
Tests