Streaming + chunking
OpenClaw には、別個のストリーミングレイヤーが 2 つあります:- ブロックストリーミング(チャネル): assistant の書き込みに合わせて、完了したブロックを発行します。これらは通常のチャネルメッセージであり、トークン差分ではありません。
- プレビューストリーミング(Telegram/Discord/Slack): 生成中に一時的なプレビューメッセージを更新します。
ブロックストリーミング(チャネルメッセージ)
ブロックストリーミングは、assistant の出力が利用可能になるにつれて粗いチャンクで送信します。text_delta/events: モデルのストリームイベント(ストリーミング非対応モデルではまばらな場合があります)。chunker: 最小/最大境界 + 分割優先を適用するEmbeddedBlockChunker。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: assistant メッセージが完了するまで待機し、その後でバッファされた出力をフラッシュします。
message_end でも、バッファされたテキストが maxChars を超える場合は chunker が使われるため、最後に複数チャンクを発行することがあります。
チャンク化アルゴリズム(下限/上限)
ブロックのチャンク化はEmbeddedBlockChunker によって実装されています:
- 下限: バッファが
minChars以上になるまで発行しません(強制時を除く)。 - 上限:
maxCharsの前で分割することを優先します。強制時はmaxCharsで分割します。 - 分割優先:
paragraph→newline→sentence→whitespace→ 強制分割。 - コードフェンス: フェンス内では分割しません。
maxCharsで強制分割する場合は、Markdown の妥当性を保つためにフェンスを閉じて再度開きます。
maxChars はチャネルの textChunkLimit にクランプされるため、チャネルごとの上限を超えることはできません。
Coalescing(ストリーミングブロックの結合)
ブロックストリーミングが有効な場合、OpenClaw は連続するブロックチャンクを結合 してから送信できます。これにより、進行状況を段階的に提供しつつ 「1 行ごとのスパム」を減らせます。- Coalescing は、フラッシュ前にアイドルギャップ(
idleMs)を待ちます。 - バッファは
maxCharsで上限管理され、それを超えるとフラッシュされます。 minCharsは、十分なテキストがたまるまで小さな断片が送信されるのを防ぎます (最終フラッシュでは残りのテキストを常に送信します)。- Joiner は
blockStreamingChunk.breakPreferenceから導出されます (paragraph→\n\n、newline→\n、sentence→ 空白)。 - チャネルごとのオーバーライドは
*.blockStreamingCoalesceで利用できます(アカウントごとの設定を含む)。 - デフォルトの coalesce
minCharsは、上書きされない限り Signal/Slack/Discord では 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"(最後に 1 回フラッシュ。ただし非常に長い場合は複数チャンクになることがあります)。 - ブロックストリーミングなし:
blockStreamingDefault: "off"(最終返信のみ)。
*.blockStreaming が明示的に true に設定されていない限り off です。チャネルはブロック返信なしでもライブプレビュー(channels.<channel>.streaming)をストリームできます。
設定場所の注意: blockStreaming* のデフォルトは、ルート設定ではなく
agents.defaults の下にあります。
プレビューストリーミングモード
正式なキー:channels.<channel>.streaming
モード:
off: プレビューストリーミングを無効化。partial: 最新のテキストで置き換えられる単一プレビュー。block: チャンク化/追記ステップでプレビューを更新。progress: 生成中は進行状況/ステータスのプレビューを表示し、完了時に最終回答を表示。
チャネル対応
| Channel | off | partial | block | progress |
|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | partial に対応 |
| Discord | ✅ | ✅ | ✅ | partial に対応 |
| Slack | ✅ | ✅ | ✅ | ✅ |
channels.slack.nativeStreamingは、streaming=partialのときに Slack ネイティブストリーミング API 呼び出しを切り替えます(デフォルト:true)。
- Telegram:
streamMode+ 真偽値のstreamingは自動的にstreamingenum に移行されます。 - Discord:
streamMode+ 真偽値のstreamingは自動的にstreamingenum に移行されます。 - Slack:
streamModeは自動的にstreamingenum に移行されます。真偽値のstreamingは自動的にnativeStreamingに移行されます。
実行時の動作
Telegram:- DM とグループ/トピック全体で、
sendMessage+editMessageTextのプレビュー更新を使います。 - Telegram のブロックストリーミングが明示的に有効な場合、プレビューストリーミングはスキップされます(重複ストリーミングを避けるため)。
/reasoning streamは推論をプレビューに書き込めます。
- 送信 + 編集のプレビューメッセージを使います。
blockモードはドラフトチャンク化(draftChunk)を使います。- Discord のブロックストリーミングが明示的に有効な場合、プレビューストリーミングはスキップされます。
partialは、利用可能な場合、Slack ネイティブストリーミング(chat.startStream/append/stop)を使えます。blockは追記スタイルのドラフトプレビューを使います。progressはステータスプレビューテキストを使い、その後で最終回答を表示します。