ストリーミング+チャンキング
OpenClawには2つの独立したストリーミングレイヤーがあります:
- ブロックストリーミング(チャネル): アシスタントが書き込むにつれて、完成したブロックを送出する。通常のチャネルメッセージであり、トークンデルタではない。
- プレビューストリーミング(Telegram/Discord/Slack): 生成中に一時的なプレビューメッセージを更新する。
現時点ではチャネルメッセージへの真のトークンデルタストリーミングはありません。プレビューストリーミングはメッセージベース(送信+編集/追記)です。
ブロックストリーミング(チャネルメッセージ)
ブロックストリーミングは、アシスタントの出力を大まかなチャンクで利用可能になり次第送信します。
Model output
└─ text_delta/events
├─ (blockStreamingBreak=text_end)
│ └─ chunker emits blocks as buffer grows
└─ (blockStreamingBreak=message_end)
└─ chunker flushes at message_end
└─ channel send (block replies)
凡例:
text_delta/events:モデルストリームイベント(非ストリーミングモデルではまばらになる場合がある)。chunker:EmbeddedBlockChunkerがmin/max境界+ブレーク優先度を適用。channel send:実際の送信メッセージ(ブロック返信)。
制御パラメータ:
agents.defaults.blockStreamingDefault:"on"/"off"(デフォルトはoff)。- チャネルオーバーライド:
*.blockStreaming(およびアカウント別バリアント)でチャネルごとに"on"/"off"を強制。 agents.defaults.blockStreamingBreak:"text_end"または"message_end"。agents.defaults.blockStreamingChunk:{ minChars, maxChars, breakPreference? }。agents.defaults.blockStreamingCoalesce:{ minChars?, maxChars?, idleMs? }(送信前にストリーミングされたブロックをマージ)。- チャネルハードキャップ:
*.textChunkLimit(例:channels.whatsapp.textChunkLimit)。 - チャネルチャンクモード:
*.chunkMode(lengthがデフォルト、newlineは長さチャンキング前に空行(段落境界)で分割)。 - Discordソフトキャップ:
channels.discord.maxLinesPerMessage(デフォルト17)で長い返信を分割しUIクリッピングを回避。
境界のセマンティクス:
text_end:chunkerが出力次第ブロックをストリーム。各text_endでフラッシュ。message_end:アシスタントメッセージが完了するまで待機してからバッファ出力をフラッシュ。
message_endでもバッファテキストがmaxCharsを超えるとchunkerが使用されるため、最終時に複数チャンクが出力される場合があります。
チャンキングアルゴリズム(low/highバウンド)
ブロックチャンキングはEmbeddedBlockChunkerで実装されています:
- Low バウンド: バッファが
minChars以上になるまで出力しない(強制時を除く)。 - High バウンド:
maxChars前での分割を優先。強制時はmaxCharsで分割。 - ブレーク優先度:
paragraph→newline→sentence→whitespace→ ハードブレーク。 - コードフェンス: フェンス内では分割しない。
maxCharsで強制分割する場合は、Markdownの妥当性を保つためフェンスをクローズ+再オープンする。
maxCharsはチャネルのtextChunkLimitにクランプされるため、チャネルごとの上限を超えることはありません。
コアレッシング(ストリーミングブロックのマージ)
ブロックストリーミングが有効な場合、OpenClawは送信前に連続するブロックチャンクをマージできます。「一行ごとのスパム」を減らしつつ、段階的な出力を提供します。
- コアレッシングはアイドルギャップ(
idleMs)を待ってからフラッシュする。 - バッファは
maxCharsで上限が設定され、超過するとフラッシュされる。 minCharsは十分なテキストが蓄積するまで小さなフラグメントの送信を防ぐ(最終フラッシュでは残りのテキストを常に送信)。- ジョイナーは
blockStreamingChunk.breakPreferenceから導出される(paragraph→\n\n、newline→\n、sentence→ スペース)。 - チャネルオーバーライドは
*.blockStreamingCoalesceで利用可能(アカウント別設定を含む)。 - Signal/Slack/Discordではデフォルトのコアレッシング
minCharsが1500に引き上げられる(オーバーライドしない限り)。
ブロック間のヒューマンライクなペーシング
ブロックストリーミング有効時に、ブロック返信間(最初のブロック以降)にランダム化された間を入れることができます。マルチバブルの応答がより自然に感じられます。
- 設定:
agents.defaults.humanDelay(エージェントごとにagents.list[].humanDelayでオーバーライド)。 - モード:
off(デフォルト)、natural(800-2500ms)、custom(minMs/maxMs)。 - ブロック返信のみに適用。最終返信やツールサマリーには適用されない。
「チャンクをストリームするか、全部まとめるか」
対応関係:
- チャンクをストリーム:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(逐次出力)。Telegram以外のチャネルでは*.blockStreaming: trueも必要。 - 全部まとめて最後にストリーム:
blockStreamingBreak: "message_end"(一度にフラッシュ、非常に長い場合は複数チャンクになる可能性あり)。 - ブロックストリーミングなし:
blockStreamingDefault: "off"(最終返信のみ)。
チャネルに関する注記: *.blockStreamingが明示的にtrueに設定されない限り、ブロックストリーミングは無効です。チャネルはブロック返信なしでもライブプレビュー(channels.<channel>.streaming)をストリーミングできます。
設定場所の注意:blockStreaming*のデフォルトはagents.defaults配下にあり、ルート設定直下ではありません。
プレビューストリーミングモード
正規キー:channels.<channel>.streaming
モード:
off:プレビューストリーミングを無効化。partial:最新テキストに置き換えられる単一プレビュー。block:チャンク化/追記ステップでプレビューを更新。progress:生成中はプログレス/ステータスプレビュー、完了時に最終回答。
チャネルマッピング
| Channel | off | partial | block | progress |
|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | maps to partial |
| Discord | ✅ | ✅ | ✅ | maps to partial |
| Slack | ✅ | ✅ | ✅ | ✅ |
Slack固有:
channels.slack.nativeStreamingはstreaming=partial時にSlackネイティブストリーミングAPI呼び出しを切り替える(デフォルト:true)。
レガシーキーのマイグレーション:
- Telegram:
streamMode+ ブーリアンstreamingがstreaming列挙型に自動マイグレーション。 - Discord:
streamMode+ ブーリアンstreamingがstreaming列挙型に自動マイグレーション。 - Slack:
streamModeがstreaming列挙型に自動マイグレーション。ブーリアンstreamingはnativeStreamingに自動マイグレーション。
ランタイム動作
Telegram:
- DMおよびグループ/トピックで
sendMessage+editMessageTextによるプレビュー更新を使用。 - Telegramのブロックストリーミングが明示的に有効な場合、二重ストリーミングを避けるためプレビューストリーミングはスキップされる。
/reasoning streamでリーズニングをプレビューに書き込める。
Discord:
- 送信+編集によるプレビューメッセージを使用。
blockモードはドラフトチャンキング(draftChunk)を使用。- Discordのブロックストリーミングが明示的に有効な場合、プレビューストリーミングはスキップされる。
Slack:
partialは利用可能な場合にSlackネイティブストリーミング(chat.startStream/append/stop)を使用できる。blockは追記スタイルのドラフトプレビューを使用。progressはステータスプレビューテキストを使用し、その後最終回答。