# Pending Tasks and Cancellation

How a run waiting on the user is parked, and what cancel and pause do to a running task.

## Pending registry

`internal/runtime/pending.go` is the prefix-routed confirm/ask registry shared by the main agent and any in-process subagents. Producers (`toolCall` confirm, `ask_user` handler, `store_secret` handler) call `Ask(ctx, req)` and block on a per-entry buffered=1 reply channel. Each front-end registers a listener via `RegisterListener(prefix)` — the TUI uses `"cli-"`, the web dashboard `"chat-"`, and the Telegram / Discord listeners `"tg-"` / `"dc-"` (an empty prefix matches everything) — and claims only matching entries through `PickNext(prefix)` or `PickNextMatch(prefix, accept)`. `PickNextFor` was removed; use `PickNext` / `PickNextMatch`. ctx cancellation removes the entry so a stale producer never wastes a human interaction.

The gate `HasListener(origin)` checks whether a listener whose prefix matches the session's origin (`OriginOf` recognizes `cli-`, `chat-`, `tg-`, `dc-`) is registered. This replaces the old global `pending.Active atomic.Bool`, so TUI, web, Telegram, and Discord confirm flows run side by side without blocking each other.

Since v1.0.23 `ask_user` splits by origin. From the TUI (`cli-`) the question goes through `Ask` as an inline request and the same run continues with the answer. From any other origin the round's other tool results are committed, a pending snapshot is written (each tool result clamped to 4 KiB, arguments to 1 KiB), the run ends, and the answer resumes it as a new turn.

## Cancel and pause

Cancellation carries a cause since v1.0.10 (`context.WithCancelCause`). Only a cancel that names `runtime.ErrUserCanceled` — Ctrl+C in the TUI, or **Yes** in the Esc popup — deletes the pending task. Any other cancel, including the popup's **Pause**, tears down the run but leaves the pending record in place, so `/pending` or `GET /v1/session/:id/task` can resume it. An `ask_user` reply that fails for a reason other than user cancellation no longer discards the pending task either.
