fix: run foreground tasks detached-worker-first so a timed-out wait hands back a resolvable task id - #590
Conversation
…ands back a resolvable task id A foreground task ran the whole Codex turn in-process with no internal deadline. When the invoking agent harness (Claude Code's Bash tool caps a call at 600s) timed the CLI out, the process's stdout was lost and the id the harness reported came from its own background-command namespace — which codex-companion status/result cannot resolve, so the run's outcome looked unrecoverable even though the state store had it. The foreground path now spawns the same detached task-worker the --background path uses and only WAITS in-process, inside a budget that defaults below the 600s ceiling (--wait-budget-ms, default 540000). On completion it emits the worker's stored payload/rendered output and exit status byte-compatibly with the old path (thrown worker errors are rethrown so auth failures still land on stderr, and unresolvable --resume-last still fails fast before a worker is spawned); on timeout it prints the companion's REAL task id with the retrieval command, and the run simply continues in the worker. Progress streams to stderr by tailing the worker's log, with a settle pass so the closing lines (including failure text) are carried. Regression test: a task outliving a 1ms wait budget hands back a task-* id that status --wait and result both resolve once the detached worker finishes.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 43661cc873
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| jobId: job.id | ||
| }); | ||
| const { payload } = enqueueBackgroundTask(cwd, job, request); | ||
| const waitBudgetMs = Math.max(0, Number(options["wait-budget-ms"]) || DEFAULT_TASK_WAIT_BUDGET_MS); |
There was a problem hiding this comment.
Honor the stop-gate timeout for JSON task callers
When the stop-review gate runs, stop-review-gate-hook.mjs invokes task --json with its own 15-minute spawnSync timeout and then parses payload.rawOutput; with this new default budget, any stop-gate review that runs for 9–15 minutes now returns a successful wait-timeout payload with no rawOutput, so the hook blocks as “no final output” even though it was configured to wait longer and could have produced an ALLOW:/BLOCK: verdict. Please let that internal caller wait for the full stop-gate timeout (or otherwise opt out of the 540s foreground handoff).
Useful? React with 👍 / 👎.
Summary
A foreground
taskruns the whole Codex turn in-process with no internal deadline. Agent harnesses cap shell calls (Claude Code's Bash tool at 600s); when that cap fires, the CLI's stdout is lost and the id the harness reports back comes from its own background-command namespace —status/resultcannot resolve it, so a long run's outcome looks unrecoverable even though the companion's state store holds it. (Observed in practice: a 13-minute verification run whose result had to be dug out of the state directory by hand.)Code changes
plugins/codex/scripts/codex-companion.mjs— the foreground path now spawns the same detachedtask-workerthe--backgroundpath uses and only WAITS in-process, inside--wait-budget-ms(default 540000, deliberately below the common 600s harness ceiling):--resume-laststill fails fast before any worker is spawned;task-*id plus the retrieval command, and the run simply continues in the worker — nothing is lost even if the harness kills the CLI afterwards;npm run bump-version.Tests
task-*id thatstatus --waitandresultboth resolve once the detached worker finishes.mainin this environment (status/result fixture expectations), i.e. no regressions from this change.