Messages and delivery

Потоковая передача и разбиение на фрагменты

OpenClaw имеет два отдельных слоя потоковой передачи:

  • Потоковая передача блоков (каналы): отправляет завершенные блоки по мере написания ответа ассистентом. Это обычные сообщения канала (не дельты токенов).
  • Потоковый предпросмотр (Telegram/Discord/Slack): обновляет временное сообщение предпросмотра во время генерации.

Сегодня настоящей потоковой передачи дельт токенов в сообщения каналов нет. Потоковый предпросмотр основан на сообщениях (отправка + правки/добавления).

Потоковая передача блоков (сообщения каналов)

Потоковая передача блоков отправляет вывод ассистента крупными фрагментами по мере их появления.

Code
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, применяющий минимальные/максимальные границы + предпочтение разрыва.
  • channel send: фактические исходящие сообщения (ответы блоками).

Элементы управления:

  • agents.defaults.blockStreamingDefault: "on"/"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: передавать блоки потоком сразу после их выдачи фрагментатором; сбрасывать буфер при каждом text_end.
  • message_end: ждать завершения сообщения ассистента, затем сбросить буферизованный вывод.

message_end все равно использует фрагментатор, если буферизованный текст превышает maxChars, поэтому в конце он может выдать несколько фрагментов.

Доставка медиа при потоковой передаче блоков

Потоковые медиа должны использовать структурированные поля полезной нагрузки, такие как mediaUrl или mediaUrls; потоковый текст не разбирается как команда вложения. Когда потоковая передача блоков отправляет медиа заранее, OpenClaw запоминает эту доставку для текущего обращения. Если финальная полезная нагрузка ассистента повторяет тот же URL медиа, финальная доставка удаляет дублирующее медиа вместо повторной отправки вложения.

Точные дубликаты финальных полезных нагрузок подавляются. Если финальная полезная нагрузка добавляет отличающийся текст вокруг медиа, которое уже было передано потоком, OpenClaw все равно отправляет новый текст, сохраняя однократную доставку медиа. Это предотвращает дублирование голосовых заметок или файлов в каналах, таких как Telegram.

Алгоритм фрагментации (нижние/верхние границы)

Фрагментация блоков реализована в EmbeddedBlockChunker:

  • Нижняя граница: не выдавать, пока буфер >= minChars (если не принудительно).
  • Верхняя граница: предпочитать разбиения до maxChars; если принудительно, разбивать на maxChars.
  • Предпочтение разрыва: paragraphnewlinesentencewhitespace → жесткий разрыв.
  • Блоки кода: никогда не разбивать внутри блоков; при принудительном разбиении на maxChars закрывать + заново открывать блок, чтобы Markdown оставался корректным.

maxChars ограничивается значением канала textChunkLimit, поэтому превысить лимиты конкретного канала нельзя.

Объединение (слияние потоковых блоков)

Когда потоковая передача блоков включена, OpenClaw может объединять последовательные фрагменты блоков перед их отправкой. Это снижает «спам одиночными строками», но сохраняет постепенный вывод.

  • Объединение ждет периоды простоя (idleMs) перед сбросом.
  • Буферы ограничены maxChars и будут сброшены при превышении.
  • minChars не дает отправлять крошечные фрагменты, пока не накопится достаточно текста (финальный сброс всегда отправляет оставшийся текст).
  • Соединитель выводится из blockStreamingChunk.breakPreference (paragraph\n\n, newline\n, sentence → пробел).
  • Переопределения каналов доступны через *.blockStreamingCoalesce (включая конфигурации для отдельных аккаунтов).
  • Значение minChars по умолчанию для объединения повышается до 1500 для Signal/Slack/Discord, если не переопределено.

Человеческий темп между блоками

Когда потоковая передача блоков включена, можно добавить случайную паузу между ответами блоками (после первого блока). Это делает ответы из нескольких сообщений более естественными.

  • Конфигурация: agents.defaults.humanDelay (переопределяется для каждого агента через agents.list[].humanDelay).
  • Режимы: off (по умолчанию), natural (800-2500 мс), 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: предпросмотр прогресса/статуса во время генерации, финальный ответ по завершении.

streaming.mode: "block" — это режим потокового предпросмотра для каналов с поддержкой редактирования, таких как Discord и Telegram. Он не включает там доставку блоков в канал. Используйте streaming.block.enabled или устаревший ключ канала blockStreaming, когда нужны обычные ответы блоками. Microsoft Teams — исключение: у него нет транспорта блочного чернового предпросмотра, поэтому streaming.mode: "block" в Teams сопоставляется с доставкой блоков, а не с нативной частичной/прогресс-потоковой передачей.

Сопоставление каналов

Канал off partial block progress
Telegram редактируемый черновик прогресса
Discord редактируемый черновик прогресса
Slack
Mattermost
MS Teams нативный поток прогресса

Только Slack:

  • channels.slack.streaming.nativeTransport переключает вызовы нативного API потоковой передачи Slack, когда channels.slack.streaming.mode="partial" (по умолчанию: true).
  • Нативная потоковая передача Slack и статус треда ассистента Slack требуют целевой тред ответа. DM верхнего уровня не показывают такой предпросмотр в стиле треда, но все равно могут использовать черновые публикации предпросмотра Slack и правки.

Миграция устаревших ключей:

  • Telegram: устаревший streamMode и скалярные/булевы значения streaming обнаруживаются и мигрируются путями совместимости doctor/config в streaming.mode.
  • Discord: streamMode + булево streaming остаются runtime-псевдонимами для enum streaming; запустите openclaw doctor --fix, чтобы переписать сохраненную конфигурацию.
  • Slack: streamMode остается runtime-псевдонимом для streaming.mode; булево streaming остается runtime-псевдонимом для streaming.mode плюс streaming.nativeTransport; устаревший nativeStreaming остается runtime-псевдонимом для streaming.nativeTransport. Запустите openclaw doctor --fix, чтобы переписать сохраненную конфигурацию.

Поведение во время выполнения

Telegram:

  • Использует обновления предпросмотра через sendMessage + editMessageText в DM и группах/темах.
  • Короткие начальные предпросмотры все еще дебаунсятся для UX push-уведомлений, но теперь Telegram материализует их после ограниченной задержки, чтобы активные запуски не оставались визуально безмолвными.
  • Финальный текст редактирует активный предпросмотр на месте; длинные финалы повторно используют это сообщение для первого фрагмента и отправляют только оставшиеся фрагменты.
  • Режим block переносит предпросмотр в новое сообщение на streaming.preview.chunk.maxChars (по умолчанию 800, ограничено лимитом редактирования Telegram 4096); другие режимы увеличивают один предпросмотр до 4096 символов.
  • Режим progress держит прогресс инструментов в редактируемом черновике статуса, материализует метку статуса, когда потоковая передача ответа активна, но строка инструмента еще недоступна, очищает этот черновик по завершении и отправляет финальный ответ через обычную доставку.
  • Если финальная правка завершается ошибкой до подтверждения завершенного текста, OpenClaw использует обычную финальную доставку и очищает устаревший предпросмотр.
  • Потоковый предпросмотр пропускается, когда потоковая передача блоков Telegram явно включена (чтобы избежать двойной потоковой передачи).
  • /reasoning stream может записывать рассуждение во временный предпросмотр, который удаляется после финальной доставки.

Discord:

  • Использует отправку + редактирование сообщений предпросмотра.
  • Режим block использует фрагментацию черновика (draftChunk).
  • Потоковый предпросмотр пропускается, когда потоковая передача блоков Discord явно включена.
  • Финальные полезные нагрузки с медиа, ошибками и явными ответами отменяют ожидающие предпросмотры без сброса нового черновика, затем используют обычную доставку.

Slack:

  • partial может использовать нативную потоковую передачу Slack (chat.startStream/append/stop), когда она доступна.
  • block использует черновые предпросмотры в стиле добавления.
  • progress использует текст предпросмотра статуса, затем финальный ответ.
  • DM верхнего уровня без треда ответа используют черновые публикации предпросмотра и правки вместо нативной потоковой передачи Slack.
  • Нативная и черновая потоковая передача предпросмотра подавляют ответы блоками для текущего обращения, поэтому ответ Slack передается потоком только одним путем доставки.
  • Финальные полезные нагрузки с медиа/ошибками и финалы прогресса не создают одноразовые черновые сообщения; только текстовые/блочные финалы, которые могут редактировать предпросмотр, сбрасывают ожидающий черновой текст.

Mattermost:

  • Передает размышления, активность инструментов и частичный текст ответа потоком в один черновой пост предпросмотра, который финализируется на месте, когда финальный ответ безопасно отправлять.
  • Откатывается к отправке нового финального поста, если пост предпросмотра был удален или иначе недоступен во время финализации.
  • Финальные полезные нагрузки с медиа/ошибками отменяют ожидающие обновления предпросмотра перед обычной доставкой вместо сброса временного поста предпросмотра.

Matrix:

  • Черновые предпросмотры финализируются на месте, когда финальный текст может повторно использовать событие предпросмотра.
  • Финалы только с медиа, ошибки и финалы с несовпадением цели ответа отменяют ожидающие обновления предпросмотра перед обычной доставкой; уже видимый устаревший предпросмотр редактируется как удаленный.

Обновления предпросмотра прогресса инструментов

Потоковый предпросмотр также может включать обновления прогресса инструментов — короткие строки статуса вроде «поиск в интернете», «чтение файла» или «вызов инструмента», которые появляются в том же сообщении предпросмотра во время работы инструментов, до финального ответа. В режиме Codex app-server сообщения преамбулы/комментариев Codex используют тот же путь предпросмотра, поэтому короткие заметки прогресса вроде «Я проверяю...» могут передаваться в редактируемый черновик, не становясь частью финального ответа. Это поддерживает визуальную активность многошаговых обращений с инструментами, а не тишину между первым предпросмотром размышления и финальным ответом.

Долго работающие инструменты могут выдавать типизированный прогресс до возврата результата. Например, web_fetch запускает пятисекундный таймер при старте: если выборка все еще ожидается, предпросмотр может показать Fetching page content...; если выборка завершается или отменяется раньше, строка прогресса не выдается. Последующий финальный результат инструмента все равно доставляется модели обычным образом.

Поддерживаемые поверхности:

  • Discord, Slack, Telegram и Matrix по умолчанию передают прогресс инструментов и обновления преамбулы Codex в живую правку предпросмотра, когда активна потоковая передача предпросмотра. Microsoft Teams использует собственный поток прогресса в личных чатах.
  • Telegram поставляется с включенными обновлениями предпросмотра прогресса инструментов начиная с v2026.4.22; сохранение их включенными сохраняет это выпущенное поведение.
  • Mattermost уже сворачивает активность инструментов в единственную публикацию чернового предпросмотра (см. выше).
  • Правки прогресса инструментов следуют активному режиму потоковой передачи предпросмотра; они пропускаются, когда потоковая передача предпросмотра имеет значение off или когда блочная потоковая передача уже взяла сообщение на себя. В Telegram streaming.mode: "off" означает только финальный ответ: общий шум прогресса также подавляется, а не доставляется как отдельные статусные сообщения, тогда как запросы подтверждения, медиаданные и ошибки по-прежнему маршрутизируются обычным образом.
  • Чтобы сохранить потоковую передачу предпросмотра, но скрыть строки прогресса инструментов, задайте streaming.preview.toolProgress в false для этого канала. Чтобы оставить строки прогресса инструментов видимыми, скрыв текст команд/выполнения, задайте streaming.preview.commandText в "status" или streaming.progress.commandText в "status"; значение по умолчанию — "raw", чтобы сохранить выпущенное поведение. Эта политика общая для каналов черновиков/прогресса, которые используют компактный рендерер прогресса OpenClaw, включая Discord, Matrix, Microsoft Teams, Mattermost, черновые предпросмотры Slack и Telegram. Чтобы полностью отключить правки предпросмотра, задайте streaming.mode в off.
  • Ответы Telegram с выбранной цитатой являются исключением: когда replyToMode не равно "off" и присутствует текст выбранной цитаты, OpenClaw пропускает поток предпросмотра ответа для этого хода, поэтому строки предпросмотра прогресса инструментов не могут отобразиться. Ответы на текущее сообщение без текста выбранной цитаты по-прежнему сохраняют потоковую передачу предпросмотра. Подробности см. в документации канала Telegram.

Полоса прогресса комментариев

Помимо прогресса инструментов, компактный рендерер прогресса может показывать в черновике еще одну полосу:

  • streaming.progress.commentary — рендерить комментарий модели перед инструментом (💬) — краткое повествование «Я проверю… затем…» — вперемешку со строками инструментов в черновике прогресса.
json
{  "channels": {    "discord": {      "streaming": { "mode": "progress", "progress": { "commentary": true } }    }  }}

Оставить строки прогресса видимыми, но скрыть необработанный текст команд/выполнения:

json
{  "channels": {    "telegram": {      "streaming": {        "mode": "partial",        "preview": {          "toolProgress": true,          "commandText": "status"        }      }    }  }}

Используйте ту же форму под ключом другого канала компактного прогресса, например channels.discord, channels.matrix, channels.msteams, channels.mattermost или черновых предпросмотров Slack. Для режима черновика прогресса поместите ту же политику в streaming.progress:

json
{  "channels": {    "telegram": {      "streaming": {        "mode": "progress",        "progress": {          "toolProgress": true,          "commandText": "status"        }      }    }  }}

Связанные материалы

Was this useful?
On this page

On this page