diff --git a/.openclaw-sync/source.json b/.openclaw-sync/source.json
index 3a2261e60..7e94901a0 100644
--- a/.openclaw-sync/source.json
+++ b/.openclaw-sync/source.json
@@ -1,5 +1,5 @@
{
"repository": "openclaw/openclaw",
- "sha": "601596bfe292739993c7c883fa173f2f6a97f79c",
- "syncedAt": "2026-04-30T00:06:01.930Z"
+ "sha": "30a2b3049ae04c695e6e65308196c55189c78d25",
+ "syncedAt": "2026-04-30T00:26:46.012Z"
}
diff --git a/docs/.generated/config-baseline.sha256 b/docs/.generated/config-baseline.sha256
index 21e0608e9..32b2e7519 100644
--- a/docs/.generated/config-baseline.sha256
+++ b/docs/.generated/config-baseline.sha256
@@ -1,4 +1,4 @@
-2af6bef21f530dc64e0379f7631bed410aee1d5c86604ef9fb149f546cfcb0e8 config-baseline.json
-8d75df355b7f6e44b9c2f195d9df86130beb697e26061469df7d60b7e8a2f204 config-baseline.core.json
+dbb3d39ddeb8a9ce03459d69774db7e457d33f47c585e0f8c7130b14b92cfcff config-baseline.json
+2197788a6a1e677fb34a4971ac4f254116c243753452397824e08431f8740aab config-baseline.core.json
fab66aa304db5697e87259165ad261006719eb6e6cdbd25f957fcba2b7b324e9 config-baseline.channel.json
c4231c2194206547af8ad94342dc00aadb734f43cb49cc79d4c46bdbb80c3f95 config-baseline.plugin.json
diff --git a/docs/.i18n/glossary.zh-CN.json b/docs/.i18n/glossary.zh-CN.json
index 466000477..ff1616612 100644
--- a/docs/.i18n/glossary.zh-CN.json
+++ b/docs/.i18n/glossary.zh-CN.json
@@ -51,6 +51,10 @@
"source": "Agent loop",
"target": "Agent loop"
},
+ {
+ "source": "Steering queue",
+ "target": "Steering queue"
+ },
{
"source": "Models",
"target": "Models"
diff --git a/docs/concepts/agent.md b/docs/concepts/agent.md
index 3277b7d4f..d7280dd0e 100644
--- a/docs/concepts/agent.md
+++ b/docs/concepts/agent.md
@@ -86,13 +86,15 @@ Legacy session folders from other tools are not read.
When queue mode is `steer`, inbound messages are injected into the current run.
Queued steering is delivered **after the current assistant turn finishes
-executing its tool calls**, before the next LLM call. Steering no longer skips
-remaining tool calls from the current assistant message; it injects the queued
-message at the next model boundary instead.
+executing its tool calls**, before the next LLM call. Pi drains all pending
+steering messages together for `steer`; legacy `queue` drains one message per
+model boundary. Steering no longer skips remaining tool calls from the current
+assistant message.
When queue mode is `followup` or `collect`, inbound messages are held until the
current turn ends, then a new agent turn starts with the queued payloads. See
-[Queue](/concepts/queue) for mode + debounce/cap behavior.
+[Queue](/concepts/queue) and [Steering queue](/concepts/queue-steering) for mode
+and boundary behavior.
Block streaming sends completed assistant blocks as soon as they finish; it is
**off by default** (`agents.defaults.blockStreamingDefault: "off"`).
diff --git a/docs/concepts/messages.md b/docs/concepts/messages.md
index c25a6a7ba..adbf5d243 100644
--- a/docs/concepts/messages.md
+++ b/docs/concepts/messages.md
@@ -127,9 +127,9 @@ current run, or collected for a followup turn.
- Default mode is `steer`, with a 500ms followup debounce when steering falls
back to queued followup delivery.
- Modes: `steer`, `followup`, `collect`, `steer-backlog`, `interrupt`, and the
- legacy `queue` alias.
+ legacy one-at-a-time `queue` mode.
-Details: [Command queue](/concepts/queue).
+Details: [Command queue](/concepts/queue) and [Steering queue](/concepts/queue-steering).
## Channel run ownership
diff --git a/docs/concepts/queue-steering.md b/docs/concepts/queue-steering.md
new file mode 100644
index 000000000..74419e0e4
--- /dev/null
+++ b/docs/concepts/queue-steering.md
@@ -0,0 +1,90 @@
+---
+summary: "How active-run steering queues messages at runtime boundaries"
+read_when:
+ - Explaining how steer behaves while an agent is using tools
+ - Changing active-run queue behavior or runtime steering integration
+ - Comparing steer, queue, collect, and followup modes
+title: "Steering queue"
+---
+
+When a message arrives while a session run is already streaming, OpenClaw can
+send that message into the active runtime instead of starting another run for
+the same session. The public modes are runtime-neutral; Pi and the native Codex
+app-server harness implement the delivery details differently.
+
+## Runtime boundary
+
+Steering does not interrupt a tool call that is already running. Pi checks for
+queued steering messages at model boundaries:
+
+1. The assistant asks for tool calls.
+2. Pi executes the current assistant message's tool-call batch.
+3. Pi emits the turn end event.
+4. Pi drains queued steering messages.
+5. Pi appends those messages as user messages before the next LLM call.
+
+This keeps tool results paired with the assistant message that requested them,
+then lets the next model call see the latest user input.
+
+The native Codex app-server harness exposes `turn/steer` instead of Pi's
+internal steering queue. OpenClaw adapts the same modes there:
+
+- `steer` batches queued messages for the configured quiet window, then sends a
+ single `turn/steer` request with all collected user input in arrival order.
+- `queue` keeps the legacy serialized shape by sending separate `turn/steer`
+ requests.
+- `followup`, `collect`, `steer-backlog`, and `interrupt` stay OpenClaw-owned
+ queue behavior around the active Codex turn.
+
+Codex review and manual compaction turns reject same-turn steering. When a
+runtime cannot accept steering, OpenClaw falls back to the followup queue where
+that mode allows it.
+
+## Modes
+
+| Mode | Active-run behavior | Later followup behavior |
+| --------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
+| `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. |
+| `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. |
+| `steer-backlog` | Same active-run steering behavior as `steer`. | Also keeps the same message for a later followup turn. |
+| `followup` | Does not steer the current run. | Runs queued messages later. |
+| `collect` | Does not steer the current run. | Coalesces compatible queued messages into one later turn after the debounce window. |
+| `interrupt` | Aborts the active run, then starts the newest message. | None. |
+
+## Burst example
+
+If four users send messages while the agent is executing a tool call:
+
+- `steer`: the active runtime receives all four messages in arrival order before
+ its next model decision. Pi drains them at the next model boundary; Codex
+ receives them as one batched `turn/steer`.
+- `queue`: legacy serialized steering. Pi injects one queued message at a time;
+ Codex receives separate `turn/steer` requests.
+- `collect`: OpenClaw waits until the active run ends, then creates a followup
+ turn with compatible queued messages after the debounce window.
+
+## Scope
+
+Steering always targets the current active session run. It does not create a new
+session, change the active run's tool policy, or split messages by sender. In
+multi-user channels, inbound prompts already include sender and route context, so
+the next model call can see who sent each message.
+
+Use `collect` when you want OpenClaw to build a later followup turn that can
+coalesce compatible messages and preserve followup queue drop policy. Use
+`queue` only when you need the older one-at-a-time steering behavior.
+
+## Debounce
+
+`messages.queue.debounceMs` applies to followup delivery, including `collect`,
+`followup`, `steer-backlog`, and `steer` fallback when active-run steering is not
+available. For Pi, active `steer` itself does not use the debounce timer because
+Pi naturally batches messages until the next model boundary. For the native
+Codex harness, OpenClaw uses the same debounce value as the quiet window before
+sending the batched `turn/steer`.
+
+## Related
+
+- [Command queue](/concepts/queue)
+- [Messages](/concepts/messages)
+- [Agent loop](/concepts/agent-loop)
diff --git a/docs/concepts/queue.md b/docs/concepts/queue.md
index a3ff4ec6e..50e7d7ae5 100644
--- a/docs/concepts/queue.md
+++ b/docs/concepts/queue.md
@@ -31,24 +31,28 @@ When unset, all inbound channel surfaces use:
- `drop: "summarize"`
`steer` is the default because it keeps the active model turn responsive without
-starting a second session run. If the current run cannot accept steering,
+starting a second session run. It drains all steering messages that arrived
+before the next model boundary. If the current run cannot accept steering,
OpenClaw falls back to a followup queue entry.
## Queue modes
Inbound messages can steer the current run, wait for a followup turn, or do both:
-- `steer`: queue a steering message into the active Pi run. Pi delivers it **after the current assistant turn finishes executing its tool calls**, before the next LLM call. If the run is not actively streaming or steering is unavailable, OpenClaw falls back to a followup queue entry.
+- `steer`: queue steering messages into the active runtime. Pi delivers all pending steering messages **after the current assistant turn finishes executing its tool calls**, before the next LLM call; Codex app-server receives one batched `turn/steer`. If the run is not actively streaming or steering is unavailable, OpenClaw falls back to a followup queue entry.
+- `queue` (legacy): old one-at-a-time steering. Pi delivers one queued steering message at each model boundary; Codex app-server receives separate `turn/steer` requests. Prefer `steer` unless you need the previous serialized behavior.
- `followup`: enqueue each message for a later agent turn after the current run ends.
- `collect`: coalesce queued messages into a **single** followup turn after the quiet window. If messages target different channels/threads, they drain individually to preserve routing.
- `steer-backlog` (aka `steer+backlog`): steer now **and** preserve the same message for a followup turn.
- `interrupt` (legacy): abort the active run for that session, then run the newest message.
-- `queue` (legacy alias): same as `steer`.
Steer-backlog means you can get a followup response after the steered run, so
streaming surfaces can look like duplicates. Prefer `collect`/`steer` if you want
one response per inbound message.
+For runtime-specific timing and dependency behavior, see
+[Steering queue](/concepts/queue-steering).
+
Configure globally or per channel via `messages.queue`:
```json5
@@ -67,7 +71,7 @@ Configure globally or per channel via `messages.queue`:
## Queue options
-Options apply to `followup`, `collect`, and `steer-backlog` (and to `steer` when it falls back to followup):
+Options apply to `followup`, `collect`, and `steer-backlog` (and to `steer` or legacy `queue` when steering falls back to followup):
- `debounceMs`: quiet window before draining queued followups. Bare numbers are milliseconds; units `ms`, `s`, `m`, `h`, and `d` are accepted by `/queue` options.
- `cap`: max queued messages per session. Values below `1` are ignored.
@@ -115,4 +119,5 @@ keys.
## Related
- [Session management](/concepts/session)
+- [Steering queue](/concepts/queue-steering)
- [Retry policy](/concepts/retry)
diff --git a/docs/docs.json b/docs/docs.json
index 3edd4ad3a..954694659 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -1177,7 +1177,8 @@
"concepts/messages",
"concepts/streaming",
"concepts/retry",
- "concepts/queue"
+ "concepts/queue",
+ "concepts/queue-steering"
]
}
]
@@ -2650,7 +2651,8 @@
"zh-TW/concepts/messages",
"zh-TW/concepts/streaming",
"zh-TW/concepts/retry",
- "zh-TW/concepts/queue"
+ "zh-TW/concepts/queue",
+ "zh-TW/concepts/queue-steering"
]
}
]
@@ -3508,7 +3510,8 @@
"ja-JP/concepts/messages",
"ja-JP/concepts/streaming",
"ja-JP/concepts/retry",
- "ja-JP/concepts/queue"
+ "ja-JP/concepts/queue",
+ "ja-JP/concepts/queue-steering"
]
}
]
@@ -4366,7 +4369,8 @@
"es/concepts/messages",
"es/concepts/streaming",
"es/concepts/retry",
- "es/concepts/queue"
+ "es/concepts/queue",
+ "es/concepts/queue-steering"
]
}
]
@@ -5224,7 +5228,8 @@
"pt-BR/concepts/messages",
"pt-BR/concepts/streaming",
"pt-BR/concepts/retry",
- "pt-BR/concepts/queue"
+ "pt-BR/concepts/queue",
+ "pt-BR/concepts/queue-steering"
]
}
]
@@ -6082,7 +6087,8 @@
"ko/concepts/messages",
"ko/concepts/streaming",
"ko/concepts/retry",
- "ko/concepts/queue"
+ "ko/concepts/queue",
+ "ko/concepts/queue-steering"
]
}
]
@@ -6940,7 +6946,8 @@
"de/concepts/messages",
"de/concepts/streaming",
"de/concepts/retry",
- "de/concepts/queue"
+ "de/concepts/queue",
+ "de/concepts/queue-steering"
]
}
]
@@ -7798,7 +7805,8 @@
"fr/concepts/messages",
"fr/concepts/streaming",
"fr/concepts/retry",
- "fr/concepts/queue"
+ "fr/concepts/queue",
+ "fr/concepts/queue-steering"
]
}
]
@@ -8656,7 +8664,8 @@
"ar/concepts/messages",
"ar/concepts/streaming",
"ar/concepts/retry",
- "ar/concepts/queue"
+ "ar/concepts/queue",
+ "ar/concepts/queue-steering"
]
}
]
@@ -9514,7 +9523,8 @@
"it/concepts/messages",
"it/concepts/streaming",
"it/concepts/retry",
- "it/concepts/queue"
+ "it/concepts/queue",
+ "it/concepts/queue-steering"
]
}
]
@@ -10372,7 +10382,8 @@
"vi/concepts/messages",
"vi/concepts/streaming",
"vi/concepts/retry",
- "vi/concepts/queue"
+ "vi/concepts/queue",
+ "vi/concepts/queue-steering"
]
}
]
@@ -11230,7 +11241,8 @@
"nl/concepts/messages",
"nl/concepts/streaming",
"nl/concepts/retry",
- "nl/concepts/queue"
+ "nl/concepts/queue",
+ "nl/concepts/queue-steering"
]
}
]
@@ -12088,7 +12100,8 @@
"tr/concepts/messages",
"tr/concepts/streaming",
"tr/concepts/retry",
- "tr/concepts/queue"
+ "tr/concepts/queue",
+ "tr/concepts/queue-steering"
]
}
]
@@ -12946,7 +12959,8 @@
"uk/concepts/messages",
"uk/concepts/streaming",
"uk/concepts/retry",
- "uk/concepts/queue"
+ "uk/concepts/queue",
+ "uk/concepts/queue-steering"
]
}
]
@@ -13804,7 +13818,8 @@
"id/concepts/messages",
"id/concepts/streaming",
"id/concepts/retry",
- "id/concepts/queue"
+ "id/concepts/queue",
+ "id/concepts/queue-steering"
]
}
]
@@ -14662,7 +14677,8 @@
"pl/concepts/messages",
"pl/concepts/streaming",
"pl/concepts/retry",
- "pl/concepts/queue"
+ "pl/concepts/queue",
+ "pl/concepts/queue-steering"
]
}
]
diff --git a/docs/gateway/config-agents.md b/docs/gateway/config-agents.md
index a7baf7a80..b1861d7c2 100644
--- a/docs/gateway/config-agents.md
+++ b/docs/gateway/config-agents.md
@@ -1226,7 +1226,7 @@ See [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) for preceden
ackReactionScope: "group-mentions", // group-mentions | group-all | direct | all
removeAckAfterReply: false,
queue: {
- mode: "steer", // steer | followup | collect | steer-backlog | steer+backlog | queue | interrupt
+ mode: "steer", // steer | queue (legacy one-at-a-time) | followup | collect | steer-backlog | steer+backlog | interrupt
debounceMs: 500,
cap: 20,
drop: "summarize", // old | new | summarize
diff --git a/docs/help/faq.md b/docs/help/faq.md
index a9c228787..c9db380d7 100644
--- a/docs/help/faq.md
+++ b/docs/help/faq.md
@@ -1943,13 +1943,14 @@ lives on the [Models FAQ](/help/faq-models).
Queue mode controls how new messages interact with an in-flight run. Use `/queue` to change modes:
- - `steer` - queue steering for the next model boundary in the current run
+ - `steer` - queue all pending steering for the next model boundary in the current run
+ - `queue` - legacy one-at-a-time steering
- `followup` - run messages one at a time
- `collect` - batch messages and reply once
- `steer-backlog` - steer now, then process backlog
- `interrupt` - abort current run and start fresh
- Default mode is `steer`. You can add options like `debounce:0.5s cap:25 drop:summarize` for followup modes. See [Command queue](/concepts/queue).
+ Default mode is `steer`. You can add options like `debounce:0.5s cap:25 drop:summarize` for followup modes. See [Command queue](/concepts/queue) and [Steering queue](/concepts/queue-steering).
diff --git a/docs/plugins/codex-harness.md b/docs/plugins/codex-harness.md
index dd9a835bf..d6223cf81 100644
--- a/docs/plugins/codex-harness.md
+++ b/docs/plugins/codex-harness.md
@@ -946,6 +946,14 @@ originating chat, and the next queued follow-up message answers that native
server request instead of being steered as extra context. Other MCP elicitation
requests still fail closed.
+Active-run queue steering maps onto Codex app-server `turn/steer`. With the
+default `messages.queue.mode: "steer"`, OpenClaw batches queued chat messages
+for the configured quiet window and sends them as one `turn/steer` request in
+arrival order. Legacy `queue` mode sends separate `turn/steer` requests. Codex
+review and manual compaction turns can reject same-turn steering, in which case
+OpenClaw uses the followup queue when the selected mode allows fallback. See
+[Steering queue](/concepts/queue-steering).
+
When the selected model uses the Codex harness, native thread compaction is
delegated to Codex app-server. OpenClaw keeps a transcript mirror for channel
history, search, `/new`, `/reset`, and future model or harness switching. The
diff --git a/docs/tools/slash-commands.md b/docs/tools/slash-commands.md
index 05543cd6a..3d5c88063 100644
--- a/docs/tools/slash-commands.md
+++ b/docs/tools/slash-commands.md
@@ -142,7 +142,7 @@ Current source-of-truth:
- `/exec host= security= ask= node=` shows or sets exec defaults.
- `/model [name|#|status]` shows or sets the model.
- `/models [provider] [page] [limit=|size=|all]` lists configured/auth-available providers or models for a provider; add `all` to browse that provider's full catalog.
- - `/queue ` manages queue behavior (`steer`, `followup`, `collect`, `steer-backlog`, `interrupt`) plus options like `debounce:0.5s cap:25 drop:summarize`; `/queue default` or `/queue reset` clears the session override. See [Command queue](/concepts/queue).
+ - `/queue ` manages queue behavior (`steer`, legacy `queue`, `followup`, `collect`, `steer-backlog`, `interrupt`) plus options like `debounce:0.5s cap:25 drop:summarize`; `/queue default` or `/queue reset` clears the session override. See [Command queue](/concepts/queue) and [Steering queue](/concepts/queue-steering).