Streaming + chunking
OpenClaw has two separate “streaming” layers:- Block streaming (channels): emit completed blocks as the assistant writes. These are normal channel messages (not token deltas).
- Token-ish streaming (Telegram only): update a draft bubble with partial text while generating; final message is sent at the end.
Block streaming (channel messages)
Block streaming sends assistant output in coarse chunks as it becomes available.-
text_delta/events: model stream events (may be sparse for non-streaming models). -
chunker:EmbeddedBlockChunkerapplying min/max bounds + break preference. channel send: actual outbound messages (block replies).
-
agents.defaults.blockStreamingDefault:"on"/"off"(default off). -
Channel overrides:
*.blockStreaming(and per-account variants) to force"on"/"off"per channel. -
agents.defaults.blockStreamingBreak:"text_end"or"message_end". -
agents.defaults.blockStreamingChunk:{ minChars, maxChars, breakPreference? }. -
agents.defaults.blockStreamingCoalesce:{ minChars?, maxChars?, idleMs? }(merge streamed blocks before send). -
Channel hard cap:
*.textChunkLimit(e.g.,channels.whatsapp.textChunkLimit). -
Channel chunk mode:
*.chunkMode(lengthdefault,newlinesplits on blank lines (paragraph boundaries) before length chunking). -
Discord soft cap:
channels.discord.maxLinesPerMessage(default 17) splits tall replies to avoid UI clipping.
-
text_end: stream blocks as soon as chunker emits; flush on eachtext_end. -
message_end: wait until assistant message finishes, then flush buffered output.
message_end still uses the chunker if the buffered text exceeds
maxChars, so it can emit multiple chunks at the end.
Chunking algorithm (low/high bounds)
Block chunking is implemented byEmbeddedBlockChunker:
-
Low bound: don’t emit until buffer >=
minChars(unless forced). -
High bound: prefer splits before
maxChars; if forced, split atmaxChars. -
Break preference:
paragraph→newline→sentence→whitespace→ hard break. -
Code fences: never split inside fences; when forced at
maxChars, close + reopen the fence to keep Markdown valid.
maxChars is clamped to the channel textChunkLimit, so you
can’t exceed
per-channel caps.
Coalescing (merge streamed blocks)
When block streaming is enabled, OpenClaw can merge consecutive block chunks before sending them out. This reduces “single-line spam” while still providing progressive output.- Coalescing waits for idle gaps (
idleMs) before flushing. - Buffers are capped by
maxCharsand will flush if they exceed it. -
minCharsprevents tiny fragments from sending until enough text accumulates (final flush always sends remaining text). -
Joiner is derived from
blockStreamingChunk.breakPreference(paragraph→\n\n,newline→\n,sentence→ space). -
Channel overrides are available via
*.blockStreamingCoalesce(including per-account configs). -
Default coalesce
minCharsis bumped to 1500 for Signal/Slack/Discord unless overridden.
Human-like pacing between blocks
When block streaming is enabled, you can add a randomized pause between block replies (after the first block). This makes multi-bubble responses feel more natural.-
Config:
agents.defaults.humanDelay(override per agent viaagents.list[].humanDelay). -
Modes:
off(default),natural(800–2500ms),custom(minMs/maxMs). - Applies only to block replies, not final replies or tool summaries.
“Stream chunks or everything”
This maps to:-
Stream chunks:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(emit as you go). Non-Telegram channels also need*.blockStreaming: true. -
Stream everything at end:
blockStreamingBreak: "message_end"(flush once, possibly multiple chunks if very long). -
No block streaming:
blockStreamingDefault: "off"(only final reply).
*.blockStreaming is explicitly set to true.
Telegram can stream drafts (channels.telegram.streamMode) without block
replies.
Config location reminder: the blockStreaming* defaults live under
agents.defaults, not the root config.
Telegram draft streaming (token-ish)
Telegram is the only channel with draft streaming:- Uses Bot API
sendMessageDraftin private chats with topics. -
channels.telegram.streamMode: "partial" | "block" | "off".partial: draft updates with the latest stream text.block: draft updates in chunked blocks (same chunker rules).off: no draft streaming.
-
Draft chunk config (only for
streamMode: "block"):channels.telegram.draftChunk(defaults:minChars: 200,maxChars: 800). -
Draft streaming is separate from block streaming; block replies are off by default and only
enabled by
*.blockStreaming: trueon non-Telegram channels. - Final reply is still a normal message.
/reasoning streamwrites reasoning into the draft bubble (Telegram only).
sendMessageDraft: Telegram draft bubble (not a real message).final reply: normal Telegram message send.