Skip to content

fix: allow durable tools to opt out of command timeout - #12

Merged
mjasnikovs merged 1 commit into
mjasnikovs:mainfrom
daanbosch:fix/long-running-tool-watchdog
Aug 4, 2026
Merged

fix: allow durable tools to opt out of command timeout#12
mjasnikovs merged 1 commit into
mjasnikovs:mainfrom
daanbosch:fix/long-running-tool-watchdog

Conversation

@daanbosch

Copy link
Copy Markdown
Contributor

Problem

The command watchdog currently arms for every tool. Durable orchestration tools can own longer child timeout and cancellation contracts, but are still aborted at the default 15-minute boundary.

This was reproduced with fable_loop: two jobs were cancelled at 15:00.5 despite healthy child progress and a 30-minute child timeout.

Change

  • add an exact-name commandTimeoutExemptTools advanced config option
  • skip only configured tools in the generic command watchdog
  • preserve the model-stream watchdog and every tool-owned timeout
  • keep bash and all non-exempt tools guarded
  • document the setting and sanitize hand-edited config

Tests

  • PI_SKIP_SMOKE=1 bun run test: 2671 passed, 0 failed, 6 skipped
  • bun run build
  • bunx tsc --noEmit
  • bunx tsc -p scripts/tsconfig.json --noEmit
  • bunx eslint .

The two optional real-Pi smoke tests were separately attempted but this checkout has no Anthropic credential/model mapping; they fail before exercising this change.

@daanbosch
daanbosch force-pushed the fix/long-running-tool-watchdog branch from 5c4fe05 to ab36952 Compare August 4, 2026 16:26
mjasnikovs added a commit that referenced this pull request Aug 4, 2026
Builds on the PR's exemption mechanism (#12) but replaces the hand-edited
name list with a discovered one, so pi-task never stores a foreign tool
name it cannot verify.

MEASURED against pi 0.83.0 with a probe extension, not assumed:
  - pi.getAllTools() reports every tool with sourceInfo; built-ins carry
    source "builtin", extension tools carry the extension's real entry
    point — the same identity extensionWhitelist already keys on
  - getAllTools() THROWS during extension loading ("Extension runtime not
    initialized"), so it can only be read when the menu opens
  - getActiveTools() is a strict subset (4 of 7 built-ins) and is
    therefore the wrong source: an inactive tool would still be armed on
  - live round trip: a saved exemption survives load, renders `off` in
    the menu, and yields shouldWatch(bash)=true / shouldWatch(exempt)=false;
    a stale name for an uninstalled tool renders no row and is harmless

/task-config gains one `watch:` row per live tool, defaulting to on. The
config stores the EXEMPTIONS, so the default and every unseen tool stay
guarded.

Also corrects a comment that claimed ctx.abort() cancels just the one
tool call. pi types it "Abort the current agent operation" and runs
sibling calls concurrently, so an overrun kills every tool in flight in
that turn — an exempt tool is spared its own timer, not the collateral.
Both limits are now stated in the README and pinned by a test.
@mjasnikovs
mjasnikovs merged commit ab36952 into mjasnikovs:main Aug 4, 2026
@mjasnikovs

Copy link
Copy Markdown
Owner

Thanks — real bug, confirmed. The watchdog exists because pi's bash has no default timeout, so it shouldn't kill a tool that has one.

I kept your mechanism and changed one thing: instead of typing tool names into config.json, /task-config now lists every live tool with an on/off toggle — names come from pi's getAllTools(), same as the extension toggles.

One caveat I found: exempting a tool doesn't always save it. ctx.abort() ends the whole turn and pi runs tools side by side, so an exempt tool still dies if a guarded sibling times out. No per-call cancel exists in pi. Now documented and tested instead of silently wrong.

Your commit ab36952 is merged to main as-is with mine on top, shipped in v0.29.0. Closing in favour of that — thanks for finding it.

If you'd like to be listed in CONTRIBUTORS.md, please open a small PR adding your own name — the file's CLA wording requires you to add it yourself.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants