Streaming + chunking
OpenClaw có hai lớp “streaming” riêng biệt:
- Block streaming (channels): phát ra các block hoàn chỉnh khi assistant đang viết. Đây là các tin nhắn channel bình thường (không phải token delta).
- Token-ish streaming (chỉ Telegram): cập nhật draft bubble với văn bản một phần trong khi đang tạo; tin nhắn cuối cùng được gửi khi kết thúc.
Hiện tại không có token streaming thực sự đến các tin nhắn channel bên ngoài. Draft streaming của Telegram là bề mặt partial-stream duy nhất.
Block streaming (tin nhắn channel)
Block streaming gửi output của assistant theo các chunk lớn khi chúng sẵn sàng.
Model output
└─ text_delta/events
├─ (blockStreamingBreak=text_end)
│ └─ chunker phát ra blocks khi buffer tăng
└─ (blockStreamingBreak=message_end)
└─ chunker flush tại message_end
└─ channel send (block replies)
Chú thích:
text_delta/events: các sự kiện stream từ model (có thể thưa thớt với các model không streaming).chunker:EmbeddedBlockChunkeráp dụng giới hạn min/max + break preference.channel send: các tin nhắn gửi đi thực tế (block replies).
Các tùy chọn điều khiển:
agents.defaults.blockStreamingDefault:"on"/"off"(mặc định off).- Channel overrides:
*.blockStreaming(và các biến thể per-account) để bắt buộc"on"/"off"cho từng channel. agents.defaults.blockStreamingBreak:"text_end"hoặc"message_end".agents.defaults.blockStreamingChunk:{ minChars, maxChars, breakPreference? }.agents.defaults.blockStreamingCoalesce:{ minChars?, maxChars?, idleMs? }(gộp các block đã stream trước khi gửi).- Channel hard cap:
*.textChunkLimit(ví dụ:channels.whatsapp.textChunkLimit). - Channel chunk mode:
*.chunkMode(lengthmặc định,newlinetách theo dòng trống (ranh giới đoạn văn) trước khi chunking theo độ dài). - Discord soft cap:
channels.discord.maxLinesPerMessage(mặc định 17) tách các reply dài để tránh bị cắt UI.
Ngữ nghĩa ranh giới:
text_end: stream các block ngay khi chunker phát ra; flush tại mỗitext_end.message_end: đợi cho đến khi tin nhắn assistant kết thúc, sau đó flush output đã buffer.
message_end vẫn dùng chunker nếu văn bản đã buffer vượt quá maxChars, nên nó có thể phát ra nhiều chunk ở cuối.
Thuật toán chunking (giới hạn thấp/cao)
Block chunking được triển khai bởi EmbeddedBlockChunker:
- Giới hạn thấp: không phát ra cho đến khi buffer >=
minChars(trừ khi bị bắt buộc). - Giới hạn cao: ưu tiên tách trước
maxChars; nếu bị bắt buộc, tách tạimaxChars. - Break preference:
paragraph→newline→sentence→whitespace→ hard break. - Code fences: không bao giờ tách bên trong fence; khi bị bắt buộc tại
maxChars, đóng + mở lại fence để giữ Markdown hợp lệ.
maxChars được giới hạn theo textChunkLimit của channel, nên các bạn không thể vượt quá giới hạn per-channel.
Coalescing (gộp các block đã stream)
Khi block streaming được bật, OpenClaw có thể gộp các block chunk liên tiếp trước khi gửi chúng đi. Điều này giảm “spam từng dòng” trong khi vẫn cung cấp output dần dần.
- Coalescing đợi các khoảng trống idle (
idleMs) trước khi flush. - Buffer được giới hạn bởi
maxCharsvà sẽ flush nếu vượt quá. minCharsngăn các fragment nhỏ được gửi cho đến khi đủ văn bản tích lũy (flush cuối cùng luôn gửi văn bản còn lại).- Joiner được lấy từ
blockStreamingChunk.breakPreference(paragraph→\n\n,newline→\n,sentence→ space). - Channel overrides có sẵn qua
*.blockStreamingCoalesce(bao gồm cả config per-account). minCharsmặc định của coalesce được tăng lên 1500 cho Signal/Slack/Discord trừ khi bị override.
Nhịp độ giống người giữa các block
Khi block streaming được bật, các bạn có thể thêm tạm dừng ngẫu nhiên giữa các block reply (sau block đầu tiên). Điều này làm cho các response nhiều bubble cảm thấy tự nhiên hơn.
- Config:
agents.defaults.humanDelay(override per agent quaagents.list[].humanDelay). - Modes:
off(mặc định),natural(800–2500ms),custom(minMs/maxMs). - Chỉ áp dụng cho block replies, không phải final replies hoặc tool summaries.
”Stream chunks hoặc tất cả”
Điều này tương ứng với:
- Stream chunks:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(phát ra khi đang chạy). Các channel không phải Telegram cũng cần*.blockStreaming: true. - Stream tất cả ở cuối:
blockStreamingBreak: "message_end"(flush một lần, có thể nhiều chunk nếu rất dài). - Không block streaming:
blockStreamingDefault: "off"(chỉ final reply).
Lưu ý về channel: Đối với các channel không phải Telegram, block streaming tắt trừ khi *.blockStreaming được đặt rõ ràng thành true. Telegram có thể stream draft (channels.telegram.streamMode) mà không cần block replies.
Nhắc nhở về vị trí config: các giá trị mặc định blockStreaming* nằm dưới agents.defaults, không phải root config.
Telegram draft streaming (token-ish)
Telegram là channel duy nhất có draft streaming:
- Dùng Bot API
sendMessageDrafttrong private chat với topics. channels.telegram.streamMode: "partial" | "block" | "off".partial: draft cập nhật với văn bản stream mới nhất.block: draft cập nhật theo các block đã chunk (cùng quy tắc chunker).off: không có draft streaming.
- Draft chunk config (chỉ cho
streamMode: "block"):channels.telegram.draftChunk(mặc định:minChars: 200,maxChars: 800). - Draft streaming tách biệt với block streaming; block replies tắt mặc định và chỉ được bật bởi
*.blockStreaming: truetrên các channel không phải Telegram. - Final reply vẫn là tin nhắn bình thường.
/reasoning streamghi reasoning vào draft bubble (chỉ Telegram).
Khi draft streaming đang hoạt động, OpenClaw tắt block streaming cho reply đó để tránh double-streaming.
Telegram (private + topics)
└─ sendMessageDraft (draft bubble)
├─ streamMode=partial → cập nhật văn bản mới nhất
└─ streamMode=block → chunker cập nhật draft
└─ final reply → tin nhắn bình thường
Chú thích:
sendMessageDraft: Telegram draft bubble (không phải tin nhắn thực).final reply: gửi tin nhắn Telegram bình thường.