Messages and delivery
ストリーミングとチャンク分割
OpenClaw には独立した 2 つのストリーミングレイヤーがあり、現在、チャンネルメッセージへの真の トークン差分ストリーミングはありません。
- ブロックストリーミング(チャンネル): アシスタントが書き込む際に、完成したブロックを 送信します。これらは通常のチャンネルメッセージであり、トークン差分ではありません。
- プレビューストリーミング(Telegram/Discord/Slack/Matrix/Mattermost/MS Teams): 生成中に一時的なプレビューメッセージを更新します(送信 + 編集/追記)。
Control UI の起動ステータス
chat.send がアクティブな実行を確認すると、アシスタントのテキストやツールの動作が表示される前に、Gateway は型付きの
大まかな起動ステータスを送信できます。Control UI はこのステータスを作業中インジケーターの横に表示し、
ワークスペースの準備、環境のプロビジョニング、コンテキストの準備、
モデルの起動という各段階を示します。
最初のアシスタント差分またはツール開始によって、その実行の起動ステータスは完全に置き換えられます。 ツールがオペレーターの操作を待っている間は、承認ステータスが優先されます。 ワークツリーの作成と最初のクラウドディスパッチはチャット実行が存在する前に行われるため、 それらの実行前 RPC 進行状況は実行の起動ステータスとして表示されません。 環境のプロビジョニングがここに表示されるのは、アクティブな実行が回収済みワーカーを再プロビジョニングする場合のみです。
ブロックストリーミング(チャンネルメッセージ)
ブロックストリーミングは、アシスタントの出力を利用可能になり次第、大まかなチャンク単位で送信します。
モデル出力 └─ 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? }(送信前にストリーミングされたブロックを統合) |
- |
*.streaming.block.enabled(チャンネルオーバーライド) |
true / false、チャンネルごと(およびアカウントごと)にブロックストリーミングを強制 |
- |
*.textChunkLimit(例:channels.whatsapp.textChunkLimit) |
数値、ハード上限 | 4000 |
*.streaming.chunkMode |
"length" / "newline" |
"length" |
channels.discord.maxLinesPerMessage |
UI でのクリッピングを避けるため、縦長の返信を分割する行数のソフト上限 | 17 |
streaming.chunkMode: "newline" は、テキストが上限を超えて
長さによるチャンク分割へフォールバックする前に、各改行ではなく空行(段落境界)で分割します。
バンドルされたチャンネルでは、これらのオーバーライドを
channels.<id>.streaming.{chunkMode,block.enabled,block.coalesce} と記述します。フラットな
*.chunkMode / *.blockStreaming / *.blockStreamingCoalesce という記述は、
すべてのバンドルされたチャンネルでレガシーです。openclaw doctor --fix はこれらを
ネスト形式へ移行し、チャンネルスキーマはこれらを拒否します。フラットな記述を引き続き使用する外部 SDK Plugin の
設定は、次のリリース系列まで非推奨のフォールバック(実行時警告あり)によって
動作し続けます。
blockStreamingBreak の境界セマンティクス:
text_end:チャンカーが出力するとすぐにブロックをストリーミングし、各text_endでフラッシュします。message_end:アシスタントメッセージが完了するまで待機してから、バッファ済みの 出力をフラッシュします。バッファ済みテキストがmaxCharsを超える場合は引き続きチャンカーを使用するため、 最後に複数のチャンクを送信することがあります。
ブロックストリーミングでのメディア配信
ストリーミングメディアでは、mediaUrl や
mediaUrls などの構造化ペイロードフィールドを使用する必要があります。ストリーミングされたテキストは添付コマンドとして解析されません。ブロック
ストリーミングがメディアを早期に送信すると、OpenClaw はそのターンでの配信を記憶します。
最終アシスタントペイロードで同じメディア URL が繰り返された場合、添付ファイルを再送信する代わりに、
最終配信から重複メディアを除去します。
完全に重複する最終ペイロードは抑制されます。最終ペイロードが、すでにストリーミングされたメディアの前後に 異なるテキストを追加する場合、OpenClaw はメディアを一度だけ配信したまま、 新しいテキストを送信します。これにより、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-> 空白。 - チャンネルオーバーライドは
*.streaming.block.coalesceから利用できます( アカウントごとの設定を含む)。 - Discord、Signal、Slack は、オーバーライドされない限り、デフォルトで
{ minChars: 1500, idleMs: 1000 }に統合します。
ブロック間の人間らしい間隔
ブロックストリーミングが有効な場合、複数の吹き出しに分かれた応答をより自然に感じられるよう、 最初のブロックの後に、ブロック返信間へランダムな一時停止を追加します。
agents.defaults.humanDelay.mode |
動作 |
|---|---|
off(デフォルト) |
一時停止なし |
natural |
800-2500ms のランダムな一時停止 |
custom |
minMs/maxMs |
エージェントごとに agents.entries.*.humanDelay でオーバーライドします。ブロック
返信にのみ適用され、最終返信やツールの要約には適用されません。
「チャンクをストリーミングするか、すべて送信するか」
- チャンクをストリーミング:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(生成に合わせて送信)。Telegram 以外のチャンネルでは*.streaming.block.enabled: trueも必要です。 - 最後にすべてをストリーミング:
blockStreamingBreak: "message_end"( 一度フラッシュしますが、非常に長い場合は複数のチャンクになる可能性があります)。 - ブロックストリーミングなし:
blockStreamingDefault: "off"(最終返信のみ)。
*.streaming.block.enabled が明示的に true に設定されていない限り、
ブロックストリーミングは無効です(例外:QQ Bot には streaming.block キーがなく、
channels.qqbot.streaming.mode が "off" でない限りブロック返信をストリーミングします)。チャンネルは、ブロック
返信なしでライブプレビュー(channels.<channel>.streaming.mode)を
ストリーミングできます。blockStreaming* のデフォルトは設定ルートではなく、agents.defaults 配下にあります。
プレビューストリーミングモード
標準キー:channels.<channel>.streaming(ネストされた { mode, ... }。レガシーな
トップレベルの真偽値/文字列形式は openclaw doctor --fix によって書き換えられます)。
| モード | 動作 |
|---|---|
off |
プレビューストリーミングを無効化 |
partial |
単一のプレビューを最新のテキストで置き換え |
block |
チャンク分割/追記の各段階でプレビューを更新 |
progress |
生成中は進行状況/ステータスをプレビューし、完了時に最終回答を表示 |
streaming.mode: "block" は、Discord や Telegram などの編集可能な
チャンネル向けのプレビューストリーミングモードです。それだけでは、これらのチャンネルでの
ブロック配信は有効になりません。通常のブロック返信には streaming.block.enabled を使用します。
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)に書き換えられる。ランタイムでは読み取られない |
| Matrix | スカラー/ブール値 streaming |
openclaw doctor --fix によって streaming.mode(Matrix の "quiet" モードを含む)に書き換えられる。ランタイムでは読み取られない |
| Feishu | ブール値 streaming |
openclaw doctor --fix によって streaming.mode に書き換えられる。ランタイムでは読み取られない |
| QQ Bot | ブール値 streaming、streaming.c2cStreamApi |
openclaw doctor --fix によって streaming.mode(ブール値/c2cStreamApi 形式の場合は 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モードでは、思考と部分的な返信テキストを単一のドラフトプレビュー投稿にストリーミングし、最終回答を安全に送信できる時点でその場で確定する。progressモードでは、思考とツールのアクティビティを単一のステータスプレビューにストリーミングし、最終回答を安全に送信できる時点でその場で確定する。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"である。このポリシーは、Discord、Matrix、Microsoft Teams、Mattermost、Slack のドラフトプレビュー、Telegram など、OpenClaw のコンパクト進捗レンダラーを使用するドラフト/進捗チャンネルで共有される。プレビュー編集を完全に無効にするには、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- モデルによるツール使用前のコメンタリー(「確認してから...します」のような短い説明)を、進捗ドラフトのツール行と交互に表示する。進捗モードの Discord と Telegram では、このオプションのレーンが無効でも、同じプリアンブルがステータス見出しとして使用される。他のチャンネルでは、既存の進捗動作が維持される。進捗ドラフトを参照。
{ "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" } } } }}関連項目
- メッセージライフサイクルのリファクタリング - 共有プレビュー、編集、ストリーム、確定処理の設計対象
- 進捗ドラフト - 長時間のターン中に更新される、表示可能な作業進行中メッセージ
- メッセージ - メッセージのライフサイクルと配信
- 再試行 - 配信失敗時の再試行動作
- チャンネル - チャンネルごとのストリーミング対応