mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 07:17:54 +08:00
6ec7b4de12
A SIGINT delivered while the event loop is parked in its selector is raised in the loop's own frame: it escapes run_until_complete, the Runner cancels the main task, and the REPL is left half-shut-down (no prompt, and the next line the human types is eaten by an abandoned prompt reader) until the following Ctrl+C kills the process. Off-loop prompts (ask_user_* / wait / tool confirms run in a worker thread via asyncio.to_thread) and the auto-retry countdown are the usual windows. Keep one asyncio-level SIGINT handler installed for the whole session instead: it cancels the innermost registered target (run_cancellable registers the turn task, sleep_cancellable the retry countdown, off_loop_prompt the waiting prompt) and never raises. Reads that block on the main thread inside a coroutine (the REPL entry prompt, synchronous click prompts) suspend the router and take SIGINT as a KeyboardInterrupt. Off-loop readline prompts cannot be interrupted without abandoning their reader thread on stdin, so they ignore SIGINT with a one-line hint.