Skip to content

feat(opencode): configurable timeout for task tool - #43685

Open
georgeglarson wants to merge 4 commits into
anomalyco:devfrom
georgeglarson:task-timeout
Open

feat(opencode): configurable timeout for task tool#43685
georgeglarson wants to merge 4 commits into
anomalyco:devfrom
georgeglarson:task-timeout

Conversation

@georgeglarson

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #15080

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

The Task tool awaits its subagent prompt with no timeout. If the
subagent path stalls — provider hang, SSE keepalives with no content —
the parent session hangs with it.

This adds an optional timeout (ms) parameter to the Task tool,
mirroring how bash.ts already handles the same problem. Default 10
min; the default itself is overridable with
OPENCODE_EXPERIMENTAL_TASK_DEFAULT_TIMEOUT_MS. timeout: 0 waits
indefinitely (param and env var alike), so callers that manage their
own cancellation keep an opt-out. When the timeout fires, the
subagent is cancelled and the tool returns a <task_error>
block that includes the task_id so the caller can retry with a
larger timeout, narrow scope, or fall back.

This is a re-file of #25141. That PR was closed as a duplicate of
the broader #20103; #20103 has since stalled (0 reviews, no
maintainer engagement since 2026-04, last update 2026-06-11), so the
narrow patch is being re-filed against current dev. #20103 remains
open but stalled
— this PR is deliberately the narrow task-only
stopgap, not a substitute. If maintainers prefer the broader patch
and it lands, this should close in favor of it.

The timeout only applies to the foreground path; background tasks
(background: true) already return immediately to the caller, so a
timeout there would be meaningless.

How did you verify your code works?

bun typecheck clean:

$ bun run typecheck
$ tsgo --noEmit
EXIT CODE: 0

bun test test/tool/task.test.ts — 23 pass, 0 fail:

bun test v1.4.0 (34cbb9a40)

 23 pass
 0 fail
 74 expect() calls
Ran 22 tests across 1 file. [3.17s]

(20 pre-existing + 3 new: timeout-fires-and-cancels, negative-timeout rejected, timeout-0 waits indefinitely.)

The new timeout test exercises the exact claim: a subagent whose
prompt is Effect.never (a faithful stand-in for a stalled provider),
a 50 ms timeout, asserts the tool returns a <task_error> block that
contains the configured duration and the task_id, that no
<task_result> is produced, and that the subagent's cancel side-effect
is observed. If the timeout race were removed, this test would hang.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

georgeglarson and others added 4 commits August 20, 2026 12:19
Mirror the bash timeout pattern: surface the env var through RuntimeFlags
so the Task tool can use it as the default subagent timeout when callers
do not pass an explicit value.

Co-Authored-By: Claude <noreply@anthropic.com>
Awaiting a subagent with no timeout meant a provider hang, SSE
keepalives with no content, or a stalled download would hang the parent
session with it. Adds an optional 'timeout' (ms) parameter to the Task
tool, mirroring the shell tool's pattern. When the timeout fires, the
subagent is cancelled and the tool returns a <task_error> block that
includes the task_id so the caller can retry with a larger timeout,
narrow scope, or fall back.

Default is 10 minutes; overridable via
OPENCODE_EXPERIMENTAL_TASK_DEFAULT_TIMEOUT_MS. Timeout only applies to
the foreground path -- background tasks already return immediately.

Co-Authored-By: Claude <noreply@anthropic.com>
Adds two tests:
- timeout fires for a stalled subagent and returns a <task_error>
  block that carries the task_id, with the subagent session cancelled
- a negative timeout fails the execute with an error rather than
  hanging

Co-Authored-By: Claude <noreply@anthropic.com>
The default-10min shape had no opt-out: params.timeout ?? default meant
every foreground call was capped and 'wait forever' was unexpressible.
0 now disables the race (param and OPENCODE_EXPERIMENTAL_TASK_DEFAULT_TIMEOUT_MS
alike, the latter via a nonNegativeInteger flag), the validation message
and <task_error> guidance say so, and a 100ms-delayed prompt proves a
0 timeout does not fire. Validation also moved ahead of the
acquireUseRelease setup it short-circuits.
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Found one related PR:

PR #20103: feat(tool): configurable timeout protection for tool and task execution
#20103

This PR is already mentioned in the description of #43685 as the broader patch that stalled. It addresses a similar goal (configurable timeout protection), but takes a wider scope covering both tool and task execution, whereas #43685 is the narrow task-only stopgap. Per the PR description, #20103 remains open but stalled with no maintainer engagement since April 2026, making #43685 a deliberate re-filing of the narrower #25141 against current dev.

No other duplicate PRs found for this specific task tool timeout feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Add configurable timeout parameter to the Task tool

1 participant