Потоковая передача и разбиение на блоки
В OpenClaw есть два отдельных уровня потоковой передачи:
- Потоковая передача блоков (каналы): отправка завершённых блоков по мере их написания ассистентом. Это обычные сообщения канала (не дельты токенов).
- Потоковый предварительный просмотр (Telegram/Discord/Slack): обновление временного сообщения предварительного просмотра во время генерации.
На данный момент нет настоящей потоковой передачи дельт токенов в сообщения каналов. Потоковый предварительный просмотр основан на сообщениях (отправка + правки/дополнения).
Потоковая передача блоков (сообщения канала)
Потоковая передача блоков отправляет вывод ассистента крупными фрагментами по мере их появления.
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"(по умолчанию 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) разбивает длинные ответы, чтобы избежать обрезки в интерфейсе.
Семантика границ:
text_end: потоковая передача блоков, как только их отправляет chunker; сброс буфера при каждомtext_end.message_end: ожидание завершения сообщения ассистента, затем сброс буферизированного вывода.
message_end всё равно использует chunker, если буферизированный текст превышает maxChars, поэтому в конце может быть отправлено несколько фрагментов.
Алгоритм разбиения на блоки (нижняя/верхняя границы)
Разбиение на блоки реализовано в EmbeddedBlockChunker:
- Нижняя граница: не отправлять, пока буфер не станет >=
minChars(если не принудительно). - Верхняя граница: предпочитать разрывы до
maxChars; если принудительно, разбивать наmaxChars. - Предпочтение разрыва:
paragraph→newline→sentence→whitespace→ жёсткий разрыв. - Блоки кода: никогда не разбивать внутри блоков кода; при принудительном разрыве на
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: предварительный просмотр прогресса/статуса во время генерации, финальный ответ по завершении.
Соответствие каналам
| Канал | off | partial | block | progress |
|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | соответствует partial |
| Discord | ✅ | ✅ | ✅ | соответствует partial |
| Slack | ✅ | ✅ | ✅ | ✅ |
Только Slack:
channels.slack.nativeStreamingпереключает использование нативных API-вызовов потоковой передачи Slack, когдаstreaming=partial(по умолчанию:true).
Миграция устаревших ключей:
- Telegram:
streamMode+ булевоstreamingавтоматически мигрируют в перечислениеstreaming. - Discord:
streamMode+ булевоstreamingавтоматически мигрируют в перечислениеstreaming. - Slack:
streamModeавтоматически мигрирует в перечислениеstreaming; булевоstreamingавтоматически мигрирует вnativeStreaming.
Поведение во время выполнения
Telegram:
- Использует Bot API
sendMessageDraftв личных сообщениях, когда доступно, иsendMessage+editMessageTextдля обновлений предварительного просмотра в группах/топиках. - Потоковый предварительный просмотр пропускается, когда потоковая передача блоков в Telegram явно включена (чтобы избежать двойной потоковой передачи).
/reasoning streamможет записывать рассуждения в предварительный просмотр.
Discord:
- Использует отправку и редактирование сообщений предварительного просмотра.
- Режим
blockиспользует разбиение на черновики (draftChunk). - Потоковый предварительный просмотр пропускается, когда потоковая передача блоков в Discord явно включена.
Slack:
partialможет использовать нативную потоковую передачу Slack (chat.startStream/append/stop), когда доступно.blockиспользует предварительный просмотр черновиков с дополнениями.progressиспользует текст предварительного просмотра статуса, затем финальный ответ.