Files
openclaw/docs/concepts/messages.md

155 lines
5.5 KiB
Markdown
Raw Normal View History

2026-01-09 19:03:17 +00:00
---
summary: "Message flow, sessions, queueing, and reasoning visibility"
read_when:
- Explaining how inbound messages become replies
- Clarifying sessions, queueing modes, or streaming behavior
- Documenting reasoning visibility and usage implications
title: "Messages"
2026-01-09 19:03:17 +00:00
---
2026-01-31 21:13:13 +09:00
2026-01-09 19:03:17 +00:00
# Messages
2026-01-30 03:15:10 +01:00
This page ties together how OpenClaw handles inbound messages, sessions, queueing,
2026-01-09 19:03:17 +00:00
streaming, and reasoning visibility.
## Message flow (high level)
```
Inbound message
-> routing/bindings -> session key
-> queue (if a run is active)
-> agent run (streaming + tools)
2026-01-13 07:15:57 +00:00
-> outbound replies (channel limits + chunking)
2026-01-09 19:03:17 +00:00
```
Key knobs live in configuration:
2026-01-31 21:13:13 +09:00
2026-01-09 19:03:17 +00:00
- `messages.*` for prefixes, queueing, and group behavior.
- `agents.defaults.*` for block streaming and chunking defaults.
2026-01-13 07:15:57 +00:00
- Channel overrides (`channels.whatsapp.*`, `channels.telegram.*`, etc.) for caps and streaming toggles.
2026-01-09 19:03:17 +00:00
See [Configuration](/gateway/configuration) for full schema.
## Inbound dedupe
2026-01-30 03:15:10 +01:00
Channels can redeliver the same message after reconnects. OpenClaw keeps a
2026-01-13 07:15:57 +00:00
short-lived cache keyed by channel/account/peer/session/message id so duplicate
deliveries do not trigger another agent run.
## Inbound debouncing
Rapid consecutive messages from the **same sender** can be batched into a single
agent turn via `messages.inbound`. Debouncing is scoped per channel + conversation
and uses the most recent message for reply threading/IDs.
Config (global default + per-channel overrides):
2026-01-31 21:13:13 +09:00
```json5
{
messages: {
inbound: {
debounceMs: 2000,
byChannel: {
whatsapp: 5000,
slack: 1500,
2026-01-31 21:13:13 +09:00
discord: 1500,
},
},
},
}
```
Notes:
2026-01-31 21:13:13 +09:00
- Debounce applies to **text-only** messages; media/attachments flush immediately.
- Control commands bypass debouncing so they remain standalone.
2026-01-09 19:03:17 +00:00
## Sessions and devices
Sessions are owned by the gateway, not by clients.
2026-01-31 21:13:13 +09:00
2026-01-09 19:03:17 +00:00
- Direct chats collapse into the agent main session key.
- Groups/channels get their own session keys.
- The session store and transcripts live on the gateway host.
2026-01-13 07:15:57 +00:00
Multiple devices/channels can map to the same session, but history is not fully
2026-01-09 19:03:17 +00:00
synced back to every client. Recommendation: use one primary device for long
conversations to avoid divergent context. The Control UI and TUI always show the
gateway-backed session transcript, so they are the source of truth.
Details: [Session management](/concepts/session).
## Inbound bodies and history context
2026-01-30 03:15:10 +01:00
OpenClaw separates the **prompt body** from the **command body**:
2026-01-31 21:13:13 +09:00
2026-01-13 07:15:57 +00:00
- `Body`: prompt text sent to the agent. This may include channel envelopes and
optional history wrappers.
- `CommandBody`: raw user text for directive/command parsing.
- `RawBody`: legacy alias for `CommandBody` (kept for compatibility).
2026-01-13 07:15:57 +00:00
When a channel supplies history, it uses a shared wrapper:
2026-01-31 21:13:13 +09:00
- `[Chat messages since your last reply - for context]`
- `[Current message - respond to this]`
2026-01-17 05:21:02 +00:00
For **non-direct chats** (groups/channels/rooms), the **current message body** is prefixed with the
sender label (same style used for history entries). This keeps real-time and queued/history
messages consistent in the agent prompt.
2026-01-31 21:13:13 +09:00
History buffers are **pending-only**: they include group messages that did _not_
trigger a run (for example, mention-gated messages) and **exclude** messages
already in the session transcript.
Directive stripping only applies to the **current message** section so history
2026-01-13 07:15:57 +00:00
remains intact. Channels that wrap history should set `CommandBody` (or
`RawBody`) to the original message text and keep `Body` as the combined prompt.
History buffers are configurable via `messages.groupChat.historyLimit` (global
2026-01-13 07:15:57 +00:00
default) and per-channel overrides like `channels.slack.historyLimit` or
`channels.telegram.accounts.<id>.historyLimit` (set `0` to disable).
2026-01-09 19:03:17 +00:00
## Queueing and followups
If a run is already active, inbound messages can be queued, steered into the
current run, or collected for a followup turn.
2026-01-13 07:15:57 +00:00
- Configure via `messages.queue` (and `messages.queue.byChannel`).
2026-01-09 19:03:17 +00:00
- Modes: `interrupt`, `steer`, `followup`, `collect`, plus backlog variants.
Details: [Queueing](/concepts/queue).
## Streaming, chunking, and batching
Block streaming sends partial replies as the model produces text blocks.
2026-01-13 07:15:57 +00:00
Chunking respects channel text limits and avoids splitting fenced code.
2026-01-09 19:03:17 +00:00
Key settings:
2026-01-31 21:13:13 +09:00
- `agents.defaults.blockStreamingDefault` (`on|off`, default off)
2026-01-09 19:03:17 +00:00
- `agents.defaults.blockStreamingBreak` (`text_end|message_end`)
- `agents.defaults.blockStreamingChunk` (`minChars|maxChars|breakPreference`)
- `agents.defaults.blockStreamingCoalesce` (idle-based batching)
- `agents.defaults.humanDelay` (human-like pause between block replies)
2026-01-13 07:15:57 +00:00
- Channel overrides: `*.blockStreaming` and `*.blockStreamingCoalesce` (non-Telegram channels require explicit `*.blockStreaming: true`)
2026-01-09 19:03:17 +00:00
Details: [Streaming + chunking](/concepts/streaming).
## Reasoning visibility and tokens
2026-01-30 03:15:10 +01:00
OpenClaw can expose or hide model reasoning:
2026-01-31 21:13:13 +09:00
2026-01-09 19:03:17 +00:00
- `/reasoning on|off|stream` controls visibility.
- Reasoning content still counts toward token usage when produced by the model.
- Telegram supports reasoning stream into the draft bubble.
Details: [Thinking + reasoning directives](/tools/thinking) and [Token use](/reference/token-use).
2026-01-09 19:03:17 +00:00
## Prefixes, threading, and replies
Outbound message formatting is centralized in `messages`:
2026-01-31 21:13:13 +09:00
feat: per-channel responsePrefix override (#9001) * feat: per-channel responsePrefix override Add responsePrefix field to all channel config types and Zod schemas, enabling per-channel and per-account outbound response prefix overrides. Resolution cascade (most specific wins): L1: channels.<ch>.accounts.<id>.responsePrefix L2: channels.<ch>.responsePrefix L3: (reserved for channels.defaults) L4: messages.responsePrefix (existing global) Semantics: - undefined -> inherit from parent level - empty string -> explicitly no prefix (stops cascade) - "auto" -> derive [identity.name] from routed agent Changes: - Core logic: resolveResponsePrefix() in identity.ts accepts optional channel/accountId and walks the cascade - resolveEffectiveMessagesConfig() passes channel context through - Types: responsePrefix added to WhatsApp, Telegram, Discord, Slack, Signal, iMessage, Google Chat, MS Teams, Feishu, BlueBubbles configs - Zod schemas: responsePrefix added for config validation - All channel handlers wired: telegram, discord, slack, signal, imessage, line, heartbeat runner, route-reply, native commands - 23 new tests covering backward compat, channel/account levels, full cascade, auto keyword, empty string stops, unknown fallthrough Fully backward compatible - no existing config is affected. Fixes #8857 * fix: address CI lint + review feedback - Replace Record<string, any> with proper typed helpers (no-explicit-any) - Add curly braces to single-line if returns (eslint curly) - Fix JSDoc: 'Per-channel' → 'channel/account' on shared config types - Extract getChannelConfig() helper for type-safe dynamic key access * fix: finish responsePrefix overrides (#9001) (thanks @mudrii) * fix: normalize prefix wiring and types (#9001) (thanks @mudrii) --------- Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
2026-02-05 05:16:34 +08:00
- `messages.responsePrefix`, `channels.<channel>.responsePrefix`, and `channels.<channel>.accounts.<id>.responsePrefix` (outbound prefix cascade), plus `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
2026-01-13 07:15:57 +00:00
- Reply threading via `replyToMode` and per-channel defaults
2026-01-09 19:03:17 +00:00
2026-01-13 07:15:57 +00:00
Details: [Configuration](/gateway/configuration#messages) and channel docs.