From d5c3f712ff84d8445d16ef79e1223b8216d62690 Mon Sep 17 00:00:00 2001 From: worldmozara Date: Fri, 23 Oct 2026 10:25:40 +0800 Subject: [PATCH] docs: describe when a prompt listens for the answer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page said a notification answer is treated like a typed one, without saying that the prompt has to be listening before the notification exists — the grace period is why. One paragraph says it, together with the price: a question that offers a reply field reads in polling mode, so no Tab completion for that prompt. --- AGENTS.md | 2 +- doc/notifications.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index d9aeb55..21c092b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -117,7 +117,7 @@ Module-level `@tool` handlers. Call `set_workspace_root()` before use. Shared interactive I/O: `ask` / `choose` / `form` / `confirm` with pluggable backend; non-TTY uses defaults or errors. CLI limit/confirm hooks and chat tools both use this. Async helpers serialize prompts (`run_prompt_async`). -Three process-wide hooks let a host take over a prompt: `set_prompt_output_hook` (break an open pretty line before the prompt draws), `configure_prompting(pause_factory=…)` (the SIGINT guard around an off-loop read), and `set_prompt_wait_hook` — a prompt that blocks announces itself through `prompt_wait(kind, title, detail)`, which yields the `PromptAnswerSource` the read may consult (`take()` returns `allow` / `deny` / reply text without blocking) or `None` for notify-only. Only the outermost prompt of a nested read is announced; with no hook installed nothing changes. `read_line_with_timeout` accepts a `source` and a `None` deadline, and stdin always wins over a host answer. The CLI's implementation is `cli/notify.py` (`[notify]`, desktop via the optional `desktop-notifier` extra, terminal via OSC 777/9 to `/dev/tty`): a prompt is announced only after `grace_seconds`, the answer is treated like a typed one (never a session grant), and every failure falls through to the next channel instead of raising. +Three process-wide hooks let a host take over a prompt: `set_prompt_output_hook` (break an open pretty line before the prompt draws), `configure_prompting(pause_factory=…)` (the SIGINT guard around an off-loop read), and `set_prompt_wait_hook` — a prompt that blocks announces itself through `prompt_wait(kind, title, detail)`, which yields the `PromptAnswerSource` the read may consult (`take()` returns `allow` / `deny` / reply text without blocking) or `None` for notify-only. Only the outermost prompt of a nested read is announced; with no hook installed nothing changes. A source that *will* offer an answer says so through `supports_actions` before it offers it, so the read polls from its first moment instead of deciding once. `read_line_with_timeout` accepts a `source` and a `None` deadline, and stdin always wins over a host answer. The CLI's implementation is `cli/notify.py` (`[notify]`, desktop via the optional `desktop-notifier` extra, terminal via OSC 777/9 to `/dev/tty`): a prompt is announced only after `grace_seconds`, the answer is treated like a typed one (never a session grant), and every failure falls through to the next channel instead of raising. ### CLI (`cli/`) diff --git a/doc/notifications.md b/doc/notifications.md index 4cda01a..2383ade 100644 --- a/doc/notifications.md +++ b/doc/notifications.md @@ -45,6 +45,12 @@ session grant: the button means "this once". "Go to terminal" withdraws the notification and leaves the prompt waiting. A secret is never asked for in a notification, and never echoed into one. +A prompt that can be answered from the notification reads both surfaces while it +blocks, from the first moment — the notification itself only shows up after +`grace_seconds`, so waiting for it to appear before listening would block on the +terminal alone. Typing at the terminal always wins; a readline-only convenience +(Tab completion on `ask_user_line`) is what a question gives up in exchange. + ## Desktop channel The desktop channel needs the optional extra: