pi-agent-wait

Interruptible, token-idle wait/yield primitives for Pi agents with aggregated host UI, batched wake coordination, event-driven background-task watches, and pi-subagents integration.

Packages

Package details

extension

Install pi-agent-wait from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-agent-wait
Package
pi-agent-wait
Version
0.6.0
Published
Aug 12, 2026
Downloads
147/mo · 9/wk
Author
aledhe
License
MIT
Types
extension
Size
90.4 KB
Dependencies
0 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-agent-wait

Wait tools for Pi agents that don't burn tokens while waiting.

The usual way an agent waits for something (dev server booting, background task finishing) is to poll: check status, sleep, check again. Each poll is a model call, so you pay inference cost for doing nothing.

This extension registers two tools that do the waiting on the host side. While a wait is pending, the model is not running at all.

Install

pi install npm:pi-agent-wait

Or for a single session:

pi -e npm:pi-agent-wait

wait_for_background_task requires pi-background-tasks. The plain wait tool has no dependencies.

Tools

wait(seconds, reason, mode)

Waits for time to pass. Max 300s per call.

wait_for_background_task(taskId, timeoutSeconds, mode)

Waits for a pi-background-tasks task to reach completed, failed, or killed. Max 900s per call. This goes through the public EventBus API, not by reading .pi/tasks internals or polling bg_status.

Both tools take a mode:

  • block: the tool call stays pending until the wait resolves, then the same agent run continues. No inference happens in between. Use when the result is needed soon.
  • yield: arms a host-side timer/watcher, ends the current turn, and wakes a later turn when done. Use for long waits where there's nothing else to do. Note: call it as a standalone tool call. Pi only honors early termination when every tool in the batch asks for it.

If you type a message while a wait is showing, the foreground wait is interrupted (the background task itself is not killed) and your message goes through normally. The wait moves to a compact footer entry. Esc cancels outright.

UI

All waits in a session share one panel. While Pi is actually idle-waiting, you get an animated list with progress bars. For wait the bar is real elapsed time. For task waits it's the fraction of the timeout budget used, since there's no way to know how far along the task actually is.

⠹ Waiting · 2 host waits · token-idle
  1. background task · foreground · npm test (b12ab34c)
     [███████░░░░░░░░░░░░░░░░░] 00:31 / 02:00 · event-driven
  2. timer · background · allow server to settle
     [████████████░░░░░░░░░░░░] 00:31 / 01:00 · host timer

When the agent goes back to doing useful work, the panel collapses to a one-line footer (background: 2 waits · task 01:29 left +1) with no spinner and no repaint timer. In headless mode the UI is a no-op.

Wake batching

Completions that arrive while the main agent is busy don't interrupt it. They are held host-side and delivered as one batched follow-up when the run ends. Debounce is 150ms, max window 500ms, deduplicated by wake key.

pi-subagents integration

If pi-subagents is loaded in the same process, detached/yielded waits show up as background-work provider items, so a bare subagent_wait() covers subagent runs and these waits together.

There is no dependency between the two packages. They find each other through a shared Symbol.for("pi-subagents.background-work.v1") registry, and each works normally if the other is absent. The registry is process-local on purpose: a parent can't inspect a child subagent's waits, each process only sees its own.

Limits

  • wait: 300s max per call. wait_for_background_task: 900s max.
  • Blocking waits share a 900s budget per agent run. The budget is reserved up front so sibling tool calls can't double-spend it.
  • After 8 unattended yields in a row, further yields are refused until the user says something. This stops a self-waking wait chain from running forever.
  • Background timers are unref'd, so pending waits never keep a Pi process alive on their own.
  • Task names and errors come from arbitrary subprocess output. They are flattened, length-bounded, and fenced as <<untrusted:...>> before the model sees them.

Known issue

Don't put bg_run and wait_for_background_task in the same tool batch. Sibling calls can run concurrently, so the wait may look up the task id before it exists. There is a 2-second grace retry that catches near-misses, but the reliable pattern is: bg_run, get the id, then wait.

Requirements

  • Node.js >= 22.19
  • A current Pi release with the TypeScript extension API
  • pi-background-tasks, for the task wait tool
  • Optional: pi-subagents >= 0.47.1

Development

npm run check

This typechecks against hand-written stubs in test-support/, which can drift from the real API. If you have the actual Pi packages installed, also run npm run typecheck:real.

License

MIT