Example

Steer a run without interrupting it

Watch a slow turn: where steering lands, when follow-ups arrive, and how clearQueue returns what Escape restores to the editor.

Typing while Pi works is not an interruption: a steering message enters after the current turn’s tool calls and before the next request, a follow-up waits until the agent would otherwise stop, and Escape aborts and returns your queued text. The walkthrough below mirrors ch25-queue/queue.test.ts on 1.0.4, which queues messages into a real session running a deliberately slow tool with a scripted provider.

The timeline

turn 1   prompt "start"
         the model asks for the slow tool; its tool calls run
         you type steer "change direction"      → queued, not yet readable by the model
turn_end after the last tool result
         next request  system | user:start | assistant | toolResult | user:change direction
turn 2   the model answers the correction
         a follow-up queued earlier is still waiting
agent_settled  nothing left outstanding → the follow-up is finally delivered

The request shape in the middle is exactly what the test asserts: steering landed after the tool result and before the next prompt (shape() in the test omits the system message). One ordering you cannot guess from the keys: steering drains before follow-ups, even when the follow-up was queued first.

The delivery rules

Event What happens
steer() while a turn runs lands after that turn’s tool calls, before the next request
followUp() delivered only when there are no tool calls or steering messages left
prompt while streaming, no streamingBehavior rejected — an error, not a guess
extension command (/status) while streaming runs immediately; the same text steered is refused

queue_update carries the complete queue each time, not a delta — the test asserts the second update still lists the first message and the last update is empty. steeringMode and followUpMode each default to "one-at-a-time", which delivers one steering message per turn; "all" delivers every queued message at once.

Escape returns your text

clearQueue() returns the queued text — the test observes { steering: ["S1"], followUp: ["F1"] } — which is what a client restores into its editor, and pendingMessageCount drops to zero. To reproduce Escape, send clear_queue before abort, so the run stops with nothing left pending.

Mechanism and limitations

Documented: the two delivery points, the mode settings, queue_update, and the clear_queue-then-abort ordering are documented RPC/SDK behaviour on 1.0.4. Observed: queue.test.ts asserts every row above through a real session — including the exact ["user:start","assistant","toolResult","user:change direction"] shape, one-at-a-time vs all delivery, the complete-queue updates, and the extension command that ran while streaming.

Everything here is about when a message is delivered, not whether the model takes it: the provider is a scripted faux, so nothing on this page shows a real model obeying a steering instruction. And the boundary is agent_settled, not agent_end — retries, compaction recovery and queued work can still follow agent_end, a distinction this queue example does not itself exercise.

Full source and test .

Understand this example

Copy this prompt into your AI tool. No code runs here.

Apply this example

Copy this prompt into your AI tool. No code runs here.