ストリーミング + チャンク化
OpenClaw には、分離された 2 つのストリーミングレイヤーがあります。- ブロックストリーミング(チャネル): アシスタントが書き込む間に、完了したブロックを送出します。これらは通常のチャネルメッセージであり、トークンデルタではありません。
- プレビューストリーミング(Telegram/Discord/Slack): 生成中に、一時的なプレビューメッセージを更新します。
ブロックストリーミング(チャネルメッセージ)
ブロックストリーミングは、利用可能になったアシスタント出力を粗いチャンクで送信します。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: アシスタントメッセージが完了するまで待機し、その後でバッファされた出力をフラッシュします。
message_end は、バッファされたテキストが maxChars を超える場合でも chunker を使用するため、最後に複数のチャンクを送出することがあります。
チャンク化アルゴリズム(低/高境界)
ブロックのチャンク化はEmbeddedBlockChunker によって実装されます。
- 低境界: バッファが
minChars以上になるまで送出しません(強制時を除く)。 - 高境界:
maxCharsより前での分割を優先し、強制時はmaxCharsで分割します。 - 優先ブレーク:
paragraph→newline→sentence→whitespace→ 強制ブレーク。 - コードフェンス: フェンス内では決して分割しません。
maxCharsで強制分割する場合は、Markdown を有効に保つためにフェンスを閉じて再度開きます。
maxChars はチャネルの textChunkLimit にクランプされるため、チャネルごとの上限を超えることはできません。
コアレスシング(ストリームされたブロックのマージ)
ブロックストリーミングが有効な場合、OpenClaw は送信前に連続するブロックチャンクをマージできます。これにより、段階的な出力を維持しつつ「1 行ずつのスパム」を減らせます。
- コアレスシングは、フラッシュ前にアイドルギャップ(
idleMs)を待機します。 - バッファは
maxCharsで上限設定されており、それを超えるとフラッシュされます。 minCharsにより、十分なテキストが蓄積されるまで小さな断片の送信を防ぎます(最終フラッシュでは残りのテキストを常に送信します)。- Joiner は
blockStreamingChunk.breakPreferenceから導出されます(paragraph→\n\n、newline→\n、sentence→ space)。 - チャネル上書きは
*.blockStreamingCoalesceで利用できます(アカウントごとの設定を含む)。 - デフォルトのコアレス
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.streaming.nativeTransportは、channels.slack.streaming.mode="partial"のときに Slack ネイティブストリーミング API 呼び出しを切り替えます(デフォルト:true)。- Slack ネイティブストリーミングと Slack アシスタントのスレッドステータスには返信スレッドの対象が必要です。トップレベル DM では、そのスレッド形式のプレビューは表示されません。
- Telegram:
streamModeと真偽値のstreamingは、自動的にstreamingenum に移行されます。 - Discord:
streamModeと真偽値のstreamingは、自動的にstreamingenum に移行されます。 - Slack:
streamModeは自動的にstreaming.modeに移行され、真偽値のstreamingは自動的にstreaming.modeとstreaming.nativeTransportに移行されます。レガシーのnativeStreamingは自動的にstreaming.nativeTransportに移行されます。
ランタイム動作
Telegram:- DM とグループ/トピックの両方で、
sendMessage+editMessageTextによるプレビュー更新を使用します。 - Telegram のブロックストリーミングが明示的に有効な場合、プレビューストリーミングはスキップされます(重複ストリーミングを避けるため)。
/reasoning streamは推論内容をプレビューに書き込めます。
- 送信 + 編集によるプレビューメッセージを使用します。
blockモードはドラフトのチャンク化(draftChunk)を使用します。- Discord のブロックストリーミングが明示的に有効な場合、プレビューストリーミングはスキップされます。
partialは、利用可能な場合に Slack ネイティブストリーミング(chat.startStream/append/stop)を使用できます。blockは追記形式のドラフトプレビューを使用します。progressはステータスプレビューテキストを使用し、その後に最終回答を表示します。