Conversation
The bash tool's docstring has long claimed sync (foreground) calls are
subject to a runtime timeout ("tens of seconds") and get killed if they
exceed it, but nothing in the code enforced one -- a hung foreground
command would block forever (until the model gave up or the caller
aborted).
Adds real enforcement:
- Default foreground timeout of 60s (matches the docstring's "tens of
seconds"), configurable per-call via an optional `timeoutMs` schema
param bounded to [1_000, 600_000]ms. The 600s ceiling matches the
existing progressIntervalMs bound already in this file; the 1s floor
matches url_fetch's MIN_TIMEOUT and lets a 1s test actually exercise
it.
- On expiry: SIGTERM the whole process group, then SIGKILL after a
2s grace period -- the same two-step signal sequence and group-kill
helper PRI-3243 added for abort, so a grandchild in a pipeline
(`sleep | cat`) is killed too, not orphaned.
- Result carries a `timedOut: boolean` flag and a `timeoutMessage`
("Command timed out after Ns and was killed.") string; partial
stdout/stderr already captured before the kill are preserved
unmodified in stdoutPreview/stderrPreview.
- Background bash calls are unaffected (they're routed to a job before
ever reaching this code path; out of scope here regardless).
Stacked on fix-pri-3243-bash-stdin-and-kill: reuses its detached
process-group spawn and killProcessOrGroup() helper for the
SIGTERM/SIGKILL sequence.
Owner
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PRI-3251: Foreground bash tool timeout isn't enforced
Stacked on
fix-pri-3243-bash-stdin-and-kill(base of this PR), whichmade foreground bash spawns detached process-group leaders and closed
stdin, so an abort can kill a whole pipeline instead of orphaning it. This
PR reuses that same process-group kill for a new failure mode: a hung
foreground call with no abort in play at all.
The premise
The bash tool's own docstring has long claimed:
Nothing in the implementation enforced this.
executeCommandonly everkilled the child process in response to
context.signal's abort event —there was no timer, no schema
timeout/timeoutMsparameter, and nohost-level (agent loop / turn) timeout standing in for it either. A
command like
sleep 999999run in the foreground would simply hang untilsomething upstream (the caller aborting, or the whole turn timing out)
intervened — which for a bare tool call is never.
What changed
seconds" language.
timeoutMsschema field,bounded to
[1_000, 600_000]ms (1s–10min). The upper bound matches theprogressIntervalMsceiling already established in this same file; thelower bound matches
url_fetch'sMIN_TIMEOUTand is low enough for a1s test to actually exercise the path.
grace period if it's still alive — the exact signal sequence and
group-kill helper PRI-3243 added for abort, reused here via a shared
scheduleGracefulKill(). A grandchild in a pipeline (e.g.sleep | cat)is killed too, not left orphaned.
timedOut: booleanand,when true, a
timeoutMessagestring ("Command timed out after Ns andwas killed."). Partial stdout/stderr already captured before the kill
are preserved unmodified in
stdoutPreview/stderrPreview.ever reaching this code path, so the new timeout only applies to
genuine foreground/sync calls.
Tests (
packages/agent/src/tools/bash.test.ts)Added a
PRI-3251: foreground timeout is enforcedblock:sleep 60) withtimeoutMs: 1000returns promptly withtimedOut: true, a matchingtimeoutMessage, and the output producedbefore the sleep still present in
stdoutPreview;sh -c '...; exec sleep 60' | cat) isconfirmed gone (not orphaned) after the timeout fires;
timeoutMs: 1000override returns wellwithin budget with
timedOut: falseand notimeoutMessage.Verified fail→pass on this branch: checking out the pre-fix
bash.tsfrom thefix-pri-3243-bash-stdin-and-killbase while keepingthe new test file reproduces exactly the bug this PR closes — the two new
timeout tests hang to their test-level timeout (they never see a
timedOutflag because nothing sets one), and the docstring-textassertion fails because the docstring itself is unchanged. Restoring the
fix makes all cases pass.
packages/agentunit suite (excluding the integration/live-API testfiles the repo's own
testscript separates out), lint, and typecheckall pass on this branch.
Not in scope
background: true) bash jobs — these have their own joblifecycle and are explicitly excluded here.
this PR only adds enforcement inside the bash tool itself.