fix(opencode): add configurable timeout to Task tool#36755
fix(opencode): add configurable timeout to Task tool#36755rajarshighoshal wants to merge 4 commits into
Conversation
Task subagents had no timeout, so a hung subagent blocked the parent session indefinitely with no way to recover. Adds an optional timeout parameter (milliseconds), a RuntimeFlags-backed default, and a cancel-and-fail-on-timeout path, mirroring the Bash tool's existing timeout implementation. Closes anomalyco#15080
|
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate FoundPR #20103: feat(tool): configurable timeout protection for tool and task execution Why it's related: This PR appears to address the exact same feature — configurable timeout protection for task execution. The current PR (36755) is implementing task tool timeout, which overlaps directly with the scope of PR #20103. Please verify the status and content of PR #20103 to confirm whether it was already merged, closed, or abandoned before proceeding with the current implementation. |
|
Thanks for the flag. Checked both:
This PR is narrower (task tool only, no global non-task-tool timeout), has no merge conflicts with One thing worth flagging regardless of which lands: @maiterth noted on #25141 that some subagent hangs may actually be a permission-prompt ( Happy to help rebase #20103's broader approach onto current |
Issue for this PR
Closes #15080
Related: #11865 (same underlying symptom — subagent hangs forever with no way for the caller to recover)
Type of change
What does this PR do?
Adds an optional
timeoutparameter (milliseconds) to the Task tool, mirroring the Bash tool's existing timeout support (packages/opencode/src/tool/shell.ts) almost line for line:timeoutadded to the Task tool's parameter schema, typed asPositiveInt(same type Bash uses).RuntimeFlags.taskDefaultTimeoutMs(envOPENCODE_EXPERIMENTAL_TASK_DEFAULT_TIMEOUT_MS), defaulting to 5 minutes if that's unset.Effect.raceFirst(background.wait(...), background.waitForPromotion(...))wait is now raced against anEffect.sleeptimeout viaEffect.raceAll, same discriminated-result pattern the Bash tool uses.cancel/background.cancel(nextSession.id)calls already used for abort-handling) and fails with a message telling the caller to retry with a larger timeout — consistent with how this file already fails on "Task cancelled" / "Task failed".I picked 5 minutes as the fallback default rather than copying Bash's 2-minute default, because subagent tasks are inherently longer-running than shell commands (multi-step exploration/reasoning) — a 2-minute default would misfire on completely normal Task usage. Open to tuning this if maintainers disagree.
task.txt(the tool's prose description) is intentionally left untouched —shell/prompt.tsis the only place that documentstimeoutin prose (and only there because it dynamically renders the resolved default into the description), andtask.txtdoesn't document any of its other schema fields in prose either. The per-field JSON schemadescriptioncarries the docs, same astask_id/commandalready do.How did you verify your code works?
packages/opencode/test/tool/task.test.ts: timeout terminates the task and cancels the child session, negative timeout is rejected, andRuntimeFlags.taskDefaultTimeoutMsis honored whentimeoutis omitted. All follow the file's existingstubOps/seed/layertest conventions.bun test test/tool/task.test.ts test/permission-task.test.ts— 65 pass, 0 fail.bun test test/tool/(full tool suite) — 339 pass, 0 fail, after updating the one wire-shape snapshot (parameters.test.ts.snap) that needed the newtimeoutfield.bun run typecheckinpackages/opencode, and the full monorepobun turbo typecheck(30/30 packages) via the pre-push hook — both clean.oxlint— no new warnings introduced by this change (verified the diff against a full-repo lint pass).Checklist