What a prompt declares (question, object, deadline), how the two channels
render it (lines apart on the desktop, one line in a terminal), that a long
reason goes before the deadline does, that a question keeps its reply field
*and* the way back to the terminal, that a body click leaves the prompt
waiting, that a reply spelling "review" is still an answer, and that a secret
is never announced.
Three seams: the offer is known when the wait starts (a confirm and a question,
with and without the platform capability), a button pressed after the
notification appears answers the tool confirm it belongs to — a pty stands in
for the terminal so the read has to consult both surfaces — and `confirm()`
takes an answer passed in and one offered by the wait hook, without asking the
backend.
`ask` now reads its answer from the wait's source as well, which is what makes
the notification's reply field mean something: the reply typed into it is the
answer the caller gets. The readline path stays whenever the source offers no
answers, so line editing and Tab completion only go away when the human asked
for a surface that can answer — and a terminal answer still wins over one that
arrives through the notification.
The read itself is the poll-based one this module already had, so the same
"no deadline, wait for a line or an answer" rule and the same Ctrl+C handling
apply; a cancelled read raises `NonInteractiveError`, as the backend's own
cancellation does.
A prompt that blocks on the human now announces itself through one process-wide
hook: `prompt_wait(kind, title, detail)` wraps `ask`, `ask_secret`, `choose` and
`confirm` and yields the answer source the host offers. `kind` names the prompt
family (`ask`, `secret`, `choose`, `confirm`, and the CLI's own `policy` /
`access` / `skills` / `limit`) so a host can pick a surface, while `title` stays
short enough to show anywhere and `detail` carries one line the caller has
already redacted. No hook installed means no behaviour change, which keeps
library hosts and the test suite exactly as they were.
The read side of the seam is `read_line_with_timeout`: an optional `source` ends
the read with the host's answer (echoed on the prompt line like a typed one) and
a `None` timeout now means "wait until a line or an answer arrives" instead of
giving up. Stdin keeps priority, so a human typing at the terminal is never
raced by a notification answer that shows up at the same moment.
`reset_prompting` clears the hook along with the output hook and the pause
factory.
The wait tool's prompt runs off-loop on a worker thread, but its read polls
select/msvcrt, so it can act on a cancel: the SIGINT target now sets a flag the
reader checks between polls and raises PromptCancelledError with, which the tool
reports as "cancelled by user" while the turn continues. run_prompt_async /
run_cancellable_prompt_async hand the matching hook to the CLI guard; a stale
cancel never leaks into the next prompt read.
Prompt the human (optional no-echo secret) and write only to the PTY.
Tool results never include the answer so secrets stay off external APIs.
Empty/Ctrl-C cancel without writing; submit defaults to trailing newline.
Store provider_name/model on sessions (SQLite migrate); restore on
resume and persist on create//model//provider. Startup prefers session
selection over re-asking. ask/choose and provider/model pick use
readline with Tab completion when available.
Add process-wide prompting backends for interactive human I/O; wire CLI
limit/confirm/workspace prompts through it. Expose ask_user, choose_user,
and form_user under tools/chat and include them in DEFAULT_TOOLS.