fix: drain queue-mode steers at the idle prompt (Discord/queue messages stuck 'pending') - #716
Open
kooricold wants to merge 1 commit into
Open
fix: drain queue-mode steers at the idle prompt (Discord/queue messages stuck 'pending')#716kooricold wants to merge 1 commit into
kooricold wants to merge 1 commit into
Conversation
A queue-mode steer (e.g. a message routed in by the cp_discord plugin, a /queue entry, or a cancelled run's leftovers) that arrived while the REPL was parked at the idle prompt sat unseen until the user typed something at the terminal. Root cause: PauseController.pop_next_steer_queued() -- documented as "owned by the idle REPL loop" -- was only consulted once at the top of the persistent-prompt branch, after which the loop blocked on wait_for_idle_submission(). A steer arriving while blocked had nothing to wake it. The classic prompt_toolkit branch never consulted it at all. Fix: - run_ui: add a _WAKE idle-queue sentinel (public alias IDLE_WAKE) and wake_idle_for_queued_steer(), which reuses the existing thread-safe _push_idle -> loop.call_soon_threadsafe hand-off. A pause-queue listener (_on_steer_queue_change) nudges the idle prompt only when a queue-mode steer is actually pending AND no run is in flight; it is registered in start_persistent_ui and removed in stop_persistent_ui. - wait_for_idle_submission() returns IDLE_WAKE when it dequeues the wake sentinel so the REPL can re-check the queue. - cli_runner: hoist the pop_next_steer_queued() drain above the persistent/classic split so BOTH modes drain queued steers, and treat IDLE_WAKE as "loop back and drain". Adds tests/messaging/test_run_ui_idle_wake.py covering the wake decision (queued vs now vs run-active), listener error isolation, and the sentinel round-trip through wait_for_idle_submission.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A queue-mode steer that arrives while the REPL is parked at the idle prompt is not processed until the user types something at the terminal.
This is most visible with the
cp_discordplugin: send a message from Discord while the session sits idle, and it shows as "pending" but never runs until you press a key in the terminal. It also affects/queueentries and steers left over from a cancelled run.Root cause
PauseController.pop_next_steer_queued()is documented as "Owned by the idle REPL loop: consume queued prompts one at a time as fresh turns when no run is in flight." — but the idle loop only consulted it once, at the top of the persistent-prompt branch, and then blocked onwait_for_idle_submission(). A steer arriving while blocked had nothing to wake it. The classicprompt_toolkitbranch never consulted it at all.cp_discord's inbound router is doing the right thing: whenrun_depth == 0(idle) it correctly picksMODE_QUEUE. The gap was entirely on the core side — the idle loop never drained the queue until the next keystroke.Fix
messaging/run_ui.py_WAKEidle-queue sentinel (public aliasIDLE_WAKE) andwake_idle_for_queued_steer(), which reuses the existing thread-safe_push_idle→loop.call_soon_threadsafehand-off (no new threading machinery)._on_steer_queue_changeinstart_persistent_ui(removed instop_persistent_ui) that nudges the idle prompt only when a queue-mode steer is actually pending and no run is in flight. now-mode steers (drained by the run's history processor) and drains-to-zero are ignored.wait_for_idle_submission()returnsIDLE_WAKEwhen it dequeues the sentinel so the REPL can re-check the queue.cli_runner.pypop_next_steer_queued()drain above the persistent/classic split so both prompt modes drain queued steers, and treatIDLE_WAKEas "loop back and drain".The instant-wake works in the persistent-prompt mode (the default). Classic
prompt_toolkitmode now at least drains queued steers at the top of each loop iteration (previously it never did).Tests
Adds
tests/messaging/test_run_ui_idle_wake.py:wait_for_idle_submission()returnsIDLE_WAKEfor the sentinel and plain text otherwiseAll 6 new tests pass, along with the existing
test_run_ui*,test_pause_controller*, andtest_steer_queuesuites.ruff checkandruff format --checkare clean on the changed files.(Three unrelated pre-existing failures —
test_tty_without_flags_selects_new_pathand twoQueueMenuApptests — reproduce on a pristine checkout in a headless environment because prompt_toolkit needs a real Windows console; they are not touched by this change.)