Background
run_scheduler_loop() holds &mut self for the entire plan execution, blocking the agent command dispatch loop. This means /plan cancel cannot be delivered while a plan is executing on CLI or any synchronous channel.
Current state
The CancellationToken plumbing is in place (PR #1515/#1516/#1457):
plan_cancel_token: Option<CancellationToken> field on Agent
run_scheduler_loop() has tokio::select! on the token at wait_event() and RunInline boundaries
handle_plan_cancel() fires the token if plan_cancel_token.is_some()
The mechanism is ready. The delivery path is not connected for CLI and synchronous channels.
What needs to change
The agent message loop must be restructured so that /plan cancel (and other commands) can be received and dispatched while the scheduler loop is active. Options:
- Spawn the scheduler loop as a
tokio::task: requires decoupling the loop from &mut self (Arc/Mutex wrapping of shared state, or moving affected fields out of Agent).
- Side-channel via
cancel_signal: Arc<Notify>: CLI/TUI reads stdin in a background task and writes to the shared notify; the scheduler loop polls it.
- Split agent state: separate mutable state needed by the scheduler loop from state needed by the command dispatch loop.
Affected channels
- CLI (synchronous stdin): fully blocked during scheduler loop
- TUI (crossterm events): has a separate event loop — may be wirable with less refactor
- Telegram: separate teloxide task, already concurrent — may be wirable
References
Background
run_scheduler_loop()holds&mut selffor the entire plan execution, blocking the agent command dispatch loop. This means/plan cancelcannot be delivered while a plan is executing on CLI or any synchronous channel.Current state
The
CancellationTokenplumbing is in place (PR #1515/#1516/#1457):plan_cancel_token: Option<CancellationToken>field onAgentrun_scheduler_loop()hastokio::select!on the token atwait_event()andRunInlineboundarieshandle_plan_cancel()fires the token ifplan_cancel_token.is_some()The mechanism is ready. The delivery path is not connected for CLI and synchronous channels.
What needs to change
The agent message loop must be restructured so that
/plan cancel(and other commands) can be received and dispatched while the scheduler loop is active. Options:tokio::task: requires decoupling the loop from&mut self(Arc/Mutex wrapping of shared state, or moving affected fields out of Agent).cancel_signal: Arc<Notify>: CLI/TUI reads stdin in a background task and writes to the shared notify; the scheduler loop polls it.Affected channels
References
crates/zeph-core/src/agent/mod.rs(struct field andrun_scheduler_loopdoc)