|
| 1 | +--- |
| 2 | +summary: "How active-run steering queues messages at runtime boundaries" |
| 3 | +read_when: |
| 4 | + - Explaining how steer behaves while an agent is using tools |
| 5 | + - Changing active-run queue behavior or runtime steering integration |
| 6 | + - Comparing steer, queue, collect, and followup modes |
| 7 | +title: "Steering queue" |
| 8 | +--- |
| 9 | + |
| 10 | +When a message arrives while a session run is already streaming, OpenClaw can |
| 11 | +send that message into the active runtime instead of starting another run for |
| 12 | +the same session. The public modes are runtime-neutral; Pi and the native Codex |
| 13 | +app-server harness implement the delivery details differently. |
| 14 | + |
| 15 | +## Runtime boundary |
| 16 | + |
| 17 | +Steering does not interrupt a tool call that is already running. Pi checks for |
| 18 | +queued steering messages at model boundaries: |
| 19 | + |
| 20 | +1. The assistant asks for tool calls. |
| 21 | +2. Pi executes the current assistant message's tool-call batch. |
| 22 | +3. Pi emits the turn end event. |
| 23 | +4. Pi drains queued steering messages. |
| 24 | +5. Pi appends those messages as user messages before the next LLM call. |
| 25 | + |
| 26 | +This keeps tool results paired with the assistant message that requested them, |
| 27 | +then lets the next model call see the latest user input. |
| 28 | + |
| 29 | +The native Codex app-server harness exposes `turn/steer` instead of Pi's |
| 30 | +internal steering queue. OpenClaw adapts the same modes there: |
| 31 | + |
| 32 | +- `steer` batches queued messages for the configured quiet window, then sends a |
| 33 | + single `turn/steer` request with all collected user input in arrival order. |
| 34 | +- `queue` keeps the legacy serialized shape by sending separate `turn/steer` |
| 35 | + requests. |
| 36 | +- `followup`, `collect`, `steer-backlog`, and `interrupt` stay OpenClaw-owned |
| 37 | + queue behavior around the active Codex turn. |
| 38 | + |
| 39 | +Codex review and manual compaction turns reject same-turn steering. When a |
| 40 | +runtime cannot accept steering, OpenClaw falls back to the followup queue where |
| 41 | +that mode allows it. |
| 42 | + |
| 43 | +## Modes |
| 44 | + |
| 45 | +| Mode | Active-run behavior | Later followup behavior | |
| 46 | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | |
| 47 | +| `steer` | Injects all queued steering messages together at the next runtime boundary. This is the default. | Falls back to followup only when steering is unavailable. | |
| 48 | +| `queue` | Legacy one-at-a-time steering. Pi injects one queued message per model boundary; Codex sends separate `turn/steer` requests. | Falls back to followup only when steering is unavailable. | |
| 49 | +| `steer-backlog` | Same active-run steering behavior as `steer`. | Also keeps the same message for a later followup turn. | |
| 50 | +| `followup` | Does not steer the current run. | Runs queued messages later. | |
| 51 | +| `collect` | Does not steer the current run. | Coalesces compatible queued messages into one later turn after the debounce window. | |
| 52 | +| `interrupt` | Aborts the active run, then starts the newest message. | None. | |
| 53 | + |
| 54 | +## Burst example |
| 55 | + |
| 56 | +If four users send messages while the agent is executing a tool call: |
| 57 | + |
| 58 | +- `steer`: the active runtime receives all four messages in arrival order before |
| 59 | + its next model decision. Pi drains them at the next model boundary; Codex |
| 60 | + receives them as one batched `turn/steer`. |
| 61 | +- `queue`: legacy serialized steering. Pi injects one queued message at a time; |
| 62 | + Codex receives separate `turn/steer` requests. |
| 63 | +- `collect`: OpenClaw waits until the active run ends, then creates a followup |
| 64 | + turn with compatible queued messages after the debounce window. |
| 65 | + |
| 66 | +## Scope |
| 67 | + |
| 68 | +Steering always targets the current active session run. It does not create a new |
| 69 | +session, change the active run's tool policy, or split messages by sender. In |
| 70 | +multi-user channels, inbound prompts already include sender and route context, so |
| 71 | +the next model call can see who sent each message. |
| 72 | + |
| 73 | +Use `collect` when you want OpenClaw to build a later followup turn that can |
| 74 | +coalesce compatible messages and preserve followup queue drop policy. Use |
| 75 | +`queue` only when you need the older one-at-a-time steering behavior. |
| 76 | + |
| 77 | +## Debounce |
| 78 | + |
| 79 | +`messages.queue.debounceMs` applies to followup delivery, including `collect`, |
| 80 | +`followup`, `steer-backlog`, and `steer` fallback when active-run steering is not |
| 81 | +available. For Pi, active `steer` itself does not use the debounce timer because |
| 82 | +Pi naturally batches messages until the next model boundary. For the native |
| 83 | +Codex harness, OpenClaw uses the same debounce value as the quiet window before |
| 84 | +sending the batched `turn/steer`. |
| 85 | + |
| 86 | +## Related |
| 87 | + |
| 88 | +- [Command queue](/concepts/queue) |
| 89 | +- [Messages](/concepts/messages) |
| 90 | +- [Agent loop](/concepts/agent-loop) |
0 commit comments