144 lines
5.4 KiB
Markdown
144 lines
5.4 KiB
Markdown
---
|
|
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
|
|
---
|
|
# Messages
|
|
|
|
This page ties together how Clawdbot handles inbound messages, sessions, queueing,
|
|
streaming, and reasoning visibility.
|
|
|
|
## Message flow (high level)
|
|
|
|
```
|
|
Inbound message
|
|
-> routing/bindings -> session key
|
|
-> queue (if a run is active)
|
|
-> agent run (streaming + tools)
|
|
-> outbound replies (channel limits + chunking)
|
|
```
|
|
|
|
Key knobs live in configuration:
|
|
- `messages.*` for prefixes, queueing, and group behavior.
|
|
- `agents.defaults.*` for block streaming and chunking defaults.
|
|
- Channel overrides (`channels.whatsapp.*`, `channels.telegram.*`, etc.) for caps and streaming toggles.
|
|
|
|
See [Configuration](/gateway/configuration) for full schema.
|
|
|
|
## Inbound dedupe
|
|
|
|
Channels can redeliver the same message after reconnects. Clawdbot keeps a
|
|
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):
|
|
```json5
|
|
{
|
|
messages: {
|
|
inbound: {
|
|
debounceMs: 2000,
|
|
byChannel: {
|
|
whatsapp: 5000,
|
|
slack: 1500,
|
|
discord: 1500
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
- Debounce applies to **text-only** messages; media/attachments flush immediately.
|
|
- Control commands bypass debouncing so they remain standalone.
|
|
|
|
## Sessions and devices
|
|
|
|
Sessions are owned by the gateway, not by clients.
|
|
- 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.
|
|
|
|
Multiple devices/channels can map to the same session, but history is not fully
|
|
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
|
|
|
|
Clawdbot separates the **prompt body** from the **command body**:
|
|
- `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).
|
|
|
|
When a channel supplies history, it uses a shared wrapper:
|
|
- `[Chat messages since your last reply - for context]`
|
|
- `[Current message - respond to this]`
|
|
|
|
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.
|
|
|
|
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
|
|
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
|
|
default) and per-channel overrides like `channels.slack.historyLimit` or
|
|
`channels.telegram.accounts.<id>.historyLimit` (set `0` to disable).
|
|
|
|
## 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.
|
|
|
|
- Configure via `messages.queue` (and `messages.queue.byChannel`).
|
|
- 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.
|
|
Chunking respects channel text limits and avoids splitting fenced code.
|
|
|
|
Key settings:
|
|
- `agents.defaults.blockStreamingDefault` (`on|off`, default off)
|
|
- `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)
|
|
- Channel overrides: `*.blockStreaming` and `*.blockStreamingCoalesce` (non-Telegram channels require explicit `*.blockStreaming: true`)
|
|
|
|
Details: [Streaming + chunking](/concepts/streaming).
|
|
|
|
## Reasoning visibility and tokens
|
|
|
|
Clawdbot can expose or hide model reasoning:
|
|
- `/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](/token-use).
|
|
|
|
## Prefixes, threading, and replies
|
|
|
|
Outbound message formatting is centralized in `messages`:
|
|
- `messages.responsePrefix` (outbound prefix) and `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
|
|
- Reply threading via `replyToMode` and per-channel defaults
|
|
|
|
Details: [Configuration](/gateway/configuration#messages) and channel docs.
|