Messages and delivery
ストリーミングとチャンク分割
OpenClaw には独立した 2 つのストリーミング層があり、現在、チャンネルメッセージへの真のトークン差分ストリーミングはありません。
- ブロックストリーミング(チャンネル): アシスタントが書き込むにつれて、完成したブロックを送信します。これらは通常のチャンネルメッセージであり、トークン差分ではありません。
- プレビューストリーミング(Telegram/Discord/Slack/Matrix/Mattermost/MS Teams): 生成中に一時的なプレビューメッセージを更新します(送信 + 編集/追記)。
ブロックストリーミング(チャンネルメッセージ)
ブロックストリーミングは、アシスタントの出力が利用可能になるにつれて、大まかなチャンク単位で送信します。
モデル出力 └─ text_delta/イベント ├─ (blockStreamingBreak=text_end) │ └─ バッファの増加に応じてチャンク処理がブロックを出力 └─ (blockStreamingBreak=message_end) └─ message_end でチャンク処理がフラッシュ └─ チャンネル送信(ブロック返信)text_delta/events:モデルのストリームイベント(非ストリーミングモデルでは疎になる場合があります)。chunker:最小/最大境界と分割設定を適用するEmbeddedBlockChunker。channel send:実際に送信されるメッセージ(ブロック返信)。
制御項目(特記がない限り、すべて agents.defaults の配下):
| キー | 値 / 形式 | デフォルト |
|---|---|---|
blockStreamingDefault |
"on" / "off" |
"off" |
blockStreamingBreak |
"text_end" / "message_end" |
- |
blockStreamingChunk |
{ minChars, maxChars, breakPreference? } |
- |
blockStreamingCoalesce |
{ minChars?, maxChars?, idleMs? }(送信前にストリーミングされたブロックを結合) |
- |
*.blockStreaming(チャンネル単位の上書き) |
true / false、チャンネル単位(およびアカウント単位)でブロックストリーミングを強制 |
- |
*.textChunkLimit(例:channels.whatsapp.textChunkLimit) |
数値、ハード上限 | 4000 |
*.chunkMode |
"length" / "newline" |
"length" |
channels.discord.maxLinesPerMessage |
数値、UI での切り落としを避けるため長い返信を分割する行数のソフト上限 | 17 |
chunkMode: "newline" は、すべての改行ではなく空行(段落の境界)で分割し、テキストが上限を超えた場合は長さによるチャンク分割にフォールバックします。
ネストされた streaming 設定を持つチャンネル(Telegram、Discord、Slack、iMessage、Microsoft Teams)では、これらの上書きを channels.<id>.streaming.{chunkMode,block.enabled,block.coalesce} と記述します。ネストされた設定を持たないチャンネル(Signal、IRC、Google Chat、WhatsApp、Mattermost など)には、フラットな *.chunkMode / *.blockStreaming / *.blockStreamingCoalesce の記述を適用します。ネストされたストリーミング設定を持つチャンネルに残っている古いフラットキーは、openclaw doctor --fix によって移行され、実行時には読み取られません。
blockStreamingBreak の境界セマンティクス:
text_end:チャンク処理が出力した時点でブロックをストリーミングし、各text_endでフラッシュします。message_end:アシスタントのメッセージが完了するまで待ってから、バッファリングされた出力をフラッシュします。バッファリングされたテキストがmaxCharsを超える場合は引き続きチャンク処理を使用するため、最後に複数のチャンクを送信できます。
ブロックストリーミングでのメディア配信
メディアのストリーミングには、mediaUrl や mediaUrls などの構造化ペイロードフィールドを使用する必要があります。ストリーミングされたテキストは添付コマンドとして解析されません。ブロックストリーミングでメディアを先に送信すると、OpenClaw はそのターンについて配信済みであることを記憶します。アシスタントの最終ペイロードで同じメディア URL が繰り返された場合、添付ファイルを再送信する代わりに、最終配信から重複するメディアを除去します。
完全に重複する最終ペイロードは抑制されます。最終ペイロードで、すでにストリーミングされたメディアの前後に異なるテキストが追加されている場合、OpenClaw はメディアの配信を 1 回に保ちながら、新しいテキストを送信します。これにより、Telegram などのチャンネルで音声メモやファイルが重複することを防ぎます。
チャンク分割アルゴリズム(下限/上限)
ブロックのチャンク分割は EmbeddedBlockChunker によって実装されています。
- 下限: バッファが
minChars以上になるまで出力しません(強制された場合を除く)。 - 上限:
maxCharsより前での分割を優先します。強制された場合はmaxCharsで分割します。 - 分割設定の優先順:
paragraph->newline->sentence-> 空白 -> 強制分割。 - コードフェンス: フェンス内では決して分割しません。
maxCharsで強制的に分割する場合は、Markdown の有効性を保つためにフェンスを閉じてから再度開きます。
maxChars はチャンネルの textChunkLimit を上限として制限されるため、チャンネルごとの上限を超えることはできません。
結合(ストリーミングされたブロックの統合)
ブロックストリーミングが有効な場合、OpenClaw は送信前に連続するブロックチャンクを結合できます。これにより、段階的な出力を提供しながら、1 行ずつ大量に送信されることを抑えます。
- 結合では、フラッシュする前にアイドル間隔(
idleMs)を待ちます。 - バッファは
maxCharsで上限が設定され、それを超えるとフラッシュされます。 minCharsにより、十分なテキストが蓄積されるまで小さな断片は送信されません (最終フラッシュでは残りのテキストが常に送信されます)。- 結合文字は
blockStreamingChunk.breakPreferenceから決定されます:paragraph->\n\n、newline->\n、sentence-> スペース。 *.blockStreamingCoalesceでチャンネルごとのオーバーライドを使用できます(アカウントごとの 設定を含む)。- Discord、Signal、Slackでは、オーバーライドされない限り、デフォルトの結合設定は
{ minChars: 1500, idleMs: 1000 }です。
ブロック間の人間らしい間隔
ブロックストリーミングが有効な場合、複数の吹き出しで構成される応答がより自然に感じられるように、 最初のブロック以降の各ブロック応答の間にランダムな一時停止を追加します。
agents.defaults.humanDelay.mode |
動作 |
|---|---|
off(デフォルト) |
一時停止なし |
natural |
800-2500msのランダムな一時停止 |
custom |
minMs/maxMs |
エージェントごとにagents.list[].humanDelayでオーバーライドできます。ブロック
応答にのみ適用され、最終応答やツールの要約には適用されません。
「チャンクをストリーミングするか、すべてをまとめて送信するか」
- チャンクをストリーミング:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(生成に合わせて送信)。Telegram以外のチャンネルでは*.blockStreaming: trueも必要です。 - 最後にすべてをストリーミング:
blockStreamingBreak: "message_end"(1回 フラッシュしますが、非常に長い場合は複数のチャンクになることがあります)。 - ブロックストリーミングなし:
blockStreamingDefault: "off"(最終応答のみ)。
*.blockStreamingが明示的にtrueに設定されていない限り、ブロックストリーミングは
オフです。チャンネルは、ブロック応答を使用せずにライブプレビュー
(channels.<channel>.streaming)をストリーミングできます。blockStreaming*のデフォルトは
設定ルートではなくagents.defaultsにあります。
プレビューストリーミングモード
正規キー:channels.<channel>.streaming(ネストされた{ mode, ... }。従来の
トップレベルの真偽値/文字列形式はopenclaw doctor --fixによって書き換えられます)。
| モード | 動作 |
|---|---|
off |
プレビューストリーミングを無効化 |
partial |
単一のプレビューを最新のテキストで置換 |
block |
チャンク化/追記の段階ごとにプレビューを更新 |
progress |
生成中は進捗/ステータスをプレビューし、完了時に最終回答を表示 |
streaming.mode: "block"は、DiscordやTelegramなど、編集に対応する
チャンネル向けのプレビューストリーミングモードです。これだけでは、それらのチャンネルでの
ブロック配信は有効になりません。通常のブロック応答にはstreaming.block.enabledを使用します
(ネストされたstreaming設定がないチャンネルでは、代わりにフラットなblockStreaming
キーを使用します)。Microsoft Teamsは
例外です。ドラフトプレビュー用のブロック転送がないため、streaming.mode: "block"ではネイティブストリーミングが完全に無効になり、応答はネイティブの部分/進捗ストリーミングではなく、
通常のブロック配信として送られます。Mattermostも
異なります。blockモードでは、完了済みテキストと
ツールアクティビティのブロックの間でプレビューを切り替えるため、以前のブロックは
編集可能な1つのドラフト内で上書きされず、個別の投稿として表示されたままになります。
チャンネル対応表
| チャンネル | off |
partial |
block |
progress |
|---|---|---|---|---|
| Telegram | 対応 | 対応 | 対応 | 編集可能な進捗ドラフト |
| Discord | 対応 | 対応 | 対応 | 編集可能な進捗ドラフト |
| Slack | 対応 | 対応 | 対応 | 対応 |
| Mattermost | 対応 | 対応 | 対応 | 対応 |
| MS Teams | 対応 | 対応 | 対応 | ネイティブ進捗ストリーム |
プレビューチャンク設定(streaming.preview.chunk.*。たとえば
channels.discord.streamingまたはchannels.telegram.streaming配下)のデフォルトは
minChars: 200、maxChars: 800(チャンネルのtextChunkLimitを上限として制限)、
breakPreference: "paragraph"です。
Slackのみ:
channels.slack.streaming.nativeTransportは、channels.slack.streaming.mode="partial"の場合にSlackのネイティブストリーミングAPI 呼び出し(chat.startStream/chat.appendStream/chat.stopStream)を切り替えます (デフォルト:true)。- SlackのネイティブストリーミングとSlackアシスタントのスレッドステータスには、応答先として スレッドが必要です。トップレベルのDMではそのスレッド形式のプレビューは表示されませんが、 Slackのドラフトプレビュー投稿と編集は引き続き使用できます。
従来キーの移行
| チャンネル | 従来のキー | 状態 |
|---|---|---|
| Telegram | streamMode、スカラー/真偽値のstreaming |
openclaw doctor --fixによってstreaming.modeに書き換えられます。実行時には読み取られません |
| Discord | streamMode、真偽値のstreaming |
openclaw doctor --fixによってstreaming.modeに書き換えられます。実行時には読み取られません |
| Slack | streamMode、真偽値のstreaming、従来のnativeStreaming |
openclaw doctor --fixによってstreaming.mode(真偽値/従来形式ではstreaming.nativeTransportも)に書き換えられます。実行時には読み取られません |
実行時の動作
Telegram
- DM およびグループ/トピック全体で、
sendMessage+editMessageTextによるプレビュー更新を使用します。最終テキストは、アクティブなプレビューをその場で編集します。Telegram の一時的な30秒間の「入力中」下書き(sendMessageDraft)は、回答のストリーミングには使用されません。 - 短い初期プレビューでは、プッシュ通知の UX のために引き続きデバウンスを行いますが、アクティブな実行が視覚的に無反応のままにならないよう、上限のある遅延後に表示します。
- 長い最終回答では、最初のチャンクにプレビューメッセージを再利用し、残りのチャンクだけを送信します。
blockモードでは、streaming.preview.chunk.maxChars(デフォルトは800、Telegram の4096文字の編集上限が最大値)に達すると、プレビューを新しいメッセージへ切り替えます。その他のモードでは、1つのプレビューを最大4096文字まで拡張します。progressモードでは、ツールの進捗を編集可能なステータス下書きに保持します。回答のストリーミングがアクティブでも、まだツール行がない場合はステータスラベルを表示し、完了時に下書きを消去して、通常の配信で最終回答を送信します。- 完了したテキストが確認される前に最終編集が失敗した場合、OpenClaw は通常の最終配信を使用し、古いプレビューを削除します。
- 二重ストリーミングを避けるため、Telegram のブロックストリーミングが明示的に有効な場合、プレビューストリーミングはスキップされます。
/reasoning streamは推論を一時的なプレビューへ書き込み、最終配信後にそのプレビューを削除できます。- Telegram の選択引用返信は例外です。
replyToModeが"off"ではなく、選択された引用テキストが存在する場合、OpenClaw はそのターンの回答プレビューストリームをスキップします(最終回答はネイティブの引用返信パスを経由する必要があります)。そのため、ツール進捗のプレビュー行は表示できません。選択された引用テキストがない現在のメッセージへの返信では、引き続きプレビューストリーミングを使用します。詳細は Telegram チャンネルのドキュメント を参照してください。
Discord
- 送信と編集によるプレビューメッセージを使用します。
blockモードでは、下書きのチャンク分割(draftChunk)を使用します。- Discord のブロックストリーミングが明示的に有効な場合、プレビューストリーミングはスキップされます。
progressモードでは、小さな-#アクティビティ受領情報(思考/ツール呼び出しの回数と経過時間)を最終回答に追加し、その回答の配信後にステータス下書きを削除します。これにより、混雑したチャンネルでも返信の上に孤立したツールログが残りません。エラーの最終回答では、失敗したターンの記録として下書きを保持します。- 最終メディア、エラー、明示的な返信ペイロードでは、新しい下書きをフラッシュせずに保留中のプレビューをキャンセルし、その後、通常の配信を使用します。
Slack
partialでは、利用可能な場合に Slack のネイティブストリーミング(chat.startStream/append/stop)を使用できます。blockでは、追記形式の下書きプレビューを使用します。progressでは、ステータスのプレビューテキストを表示してから、最終回答を送信します。- 返信スレッドのないトップレベル DM では、Slack のネイティブストリーミングではなく、下書きプレビューの投稿と編集を使用します。
- ネイティブおよび下書きのプレビューストリーミングでは、そのターンのブロック返信を抑制するため、Slack の返信は1つの配信パスだけでストリーミングされます。
- 最終メディア/エラーのペイロードおよび進捗の最終回答では、使い捨ての下書きメッセージを作成しません。保留中の下書きテキストをフラッシュするのは、プレビューを編集できるテキスト/ブロックの最終回答だけです。
Mattermost
partialモードでは、思考と部分的な返信テキストを1つの下書きプレビュー投稿へストリーミングし、最終回答を安全に送信できる時点でその場で確定します。progressモードでは、思考とツールアクティビティを1つのステータスプレビューへストリーミングし、最終回答を安全に送信できる時点でその場で確定します。blockモードでは、完成したテキストの投稿とツールアクティビティの投稿を切り替えます。並列および連続するツール更新は、現在のツールアクティビティ投稿を共有します。- 確定時にプレビュー投稿が削除されているか、その他の理由で利用できない場合は、新しい最終投稿の送信にフォールバックします。
- 最終メディア/エラーのペイロードでは、一時的なプレビュー投稿をフラッシュする代わりに、通常の配信前に保留中のプレビュー更新をキャンセルします。
Matrix
- 最終テキストがプレビューイベントを再利用できる場合、下書きプレビューをその場で確定します。
- メディアのみ、エラー、返信先不一致の最終回答では、通常の配信前に保留中のプレビュー更新をキャンセルします。すでに表示されている古いプレビューは墨消しされます。
ツール進捗のプレビュー更新
プレビューストリーミングには、ツール進捗の更新も含めることができます。これは、「Web を検索中」「ファイルを読み取り中」「ツールを呼び出し中」のような短いステータス行で、ツールの実行中に、最終返信より先に同じプレビューメッセージ内へ表示されます。Codex app-server モードでは、Codex の前置き/解説メッセージも同じプレビューパスを使用するため、「確認しています...」のような短い進捗メモを、最終回答の一部にせず編集可能な下書きへストリーミングできます。これにより、複数ステップのツールターンが、最初の思考プレビューから最終回答まで無反応に見えず、視覚的に動き続けます。
長時間実行されるツールは、結果を返す前に型付きの進捗を出力する場合があります。たとえば、web_fetch は開始時に5秒のタイマーを設定します。フェッチがまだ保留中であれば、プレビューに Fetching page content... と表示されます。それまでにフェッチが完了またはキャンセルされた場合、進捗行は出力されません。後続の最終ツール結果は、通常どおりモデルへ配信されます。
サポートされる対象:
- Discord、Slack、Telegram、Matrix では、プレビューストリーミングがアクティブな場合、デフォルトでツール進捗と Codex の前置き更新をライブプレビューの編集へストリーミングします。Microsoft Teams は、個人チャットでネイティブの進捗ストリームを使用します。
- Telegram では
v2026.4.22以降、ツール進捗のプレビュー更新が有効な状態でリリースされています。有効なままにすることで、そのリリース済みの動作が維持されます。 - Mattermost では、
partialおよびprogressモードでツールアクティビティを1つのプレビュー投稿へまとめます。blockモードでは、テキストブロック間の1つのツールアクティビティ投稿へまとめます(前述を参照)。 - ツール進捗の編集は、アクティブなプレビューストリーミングモードに従います。プレビューストリーミングが
offの場合、またはブロックストリーミングがメッセージを引き継いだ場合はスキップされます。Telegram では、streaming.mode: "off"は最終回答のみを意味します。一般的な進捗メッセージも、独立したステータスメッセージとして配信されるのではなく抑制されますが、承認プロンプト、メディアペイロード、エラーは引き続き通常どおりルーティングされます。 - プレビューストリーミングを維持しながらツール進捗行を非表示にするには、そのチャンネルの
streaming.preview.toolProgressをfalseに設定します(デフォルトはtrue)。コマンド/実行テキストを非表示にしつつツール進捗行を表示するには、streaming.preview.commandTextを"status"に設定するか、streaming.progress.commandTextを"status"に設定します。リリース済みの動作を維持するため、デフォルトは"raw"です。このポリシーは、OpenClaw のコンパクト進捗レンダラーを使用する下書き/進捗チャンネルで共有されます。これには Discord、Matrix、Microsoft Teams、Mattermost、Slack の下書きプレビュー、Telegram が含まれます。プレビュー編集を完全に無効にするには、streaming.modeをoffに設定します。
進捗下書きのレンダリング
進捗モードの下書き(streaming.progress.*)には上限があり、チャンネルごとに設定できます。
| キー | デフォルト | 動作 |
|---|---|---|
streaming.progress.maxLines |
8 |
下書きラベルの下に保持するコンパクト進捗行の最大数 |
streaming.progress.maxLineChars |
120 |
切り詰め前のコンパクト行ごとの最大文字数(単語境界を考慮) |
streaming.progress.label |
"auto" |
下書きタイトル。カスタム文字列、または非表示にする false |
streaming.progress.labels |
組み込みプール | label: "auto" の場合に使用されるラベル候補 |
解説進捗レーン
ツール進捗に加えて、コンパクト進捗レンダラーは下書きにもう1つのレーンを表示できます。
streaming.progress.commentary- モデルのツール実行前の解説(「確認してから...します」のような短い説明)を、進捗下書き内のツール行と交互に表示します。
{ "channels": { "discord": { "streaming": { "mode": "progress", "progress": { "commentary": true } } } }}進捗行を表示したまま、未加工のコマンド/実行テキストを非表示にします。
{ "channels": { "telegram": { "streaming": { "mode": "partial", "preview": { "toolProgress": true, "commandText": "status" } } } }}同じ形式を、別のコンパクト進捗チャンネルのキー配下で使用します。たとえば、channels.discord、channels.matrix、channels.msteams、channels.mattermost、または Slack の下書きプレビューです。進捗下書きモードでは、同じポリシーを streaming.progress 配下に配置します。
{ "channels": { "telegram": { "streaming": { "mode": "progress", "progress": { "toolProgress": true, "commandText": "status" } } } }}関連項目
- メッセージライフサイクルのリファクタリング - 共有プレビュー、編集、ストリーム、確定処理の設計目標
- 進捗下書き - 長いターン中に更新される、表示可能な作業中メッセージ
- メッセージ - メッセージのライフサイクルと配信
- 再試行 - 配信失敗時の再試行動作
- チャンネル - チャンネルごとのストリーミングサポート