스트리밍 + 청킹
OpenClaw에는 서로 분리된 두 개의 스트리밍 계층이 있습니다:- 블록 스트리밍(채널): assistant가 작성하는 동안 완료된 블록을 전송합니다. 이는 일반 채널 메시지이며(토큰 델타 아님).
- 미리보기 스트리밍(Telegram/Discord/Slack): 생성 중 임시 미리보기 메시지를 업데이트합니다.
블록 스트리밍(채널 메시지)
블록 스트리밍은 assistant 출력이 준비되는 대로 거친 청크 단위로 전송합니다.text_delta/events: 모델 스트림 이벤트(비스트리밍 모델에서는 드물 수 있음).chunker: 최소/최대 경계 + 분할 선호도를 적용하는EmbeddedBlockChunker.channel send: 실제 발신 메시지(블록 답장).
agents.defaults.blockStreamingDefault:"on"/"off"(기본값 꺼짐).- 채널 재정의: 채널별로
"on"/"off"를 강제하는*.blockStreaming(및 계정별 변형). 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: chunker가 방출하는 즉시 스트림 블록을 전송하고 각text_end에서 flush합니다.message_end: assistant 메시지가 끝날 때까지 기다린 뒤 버퍼된 출력을 flush합니다.
message_end도 버퍼된 텍스트가 maxChars를 초과하면 여전히 chunker를 사용하므로 마지막에 여러 청크를 방출할 수 있습니다.
청킹 알고리즘(하한/상한)
블록 청킹은EmbeddedBlockChunker로 구현됩니다:
- 하한: 버퍼가
minChars이상이 되기 전에는 방출하지 않습니다(강제되는 경우 제외). - 상한: 가능하면
maxChars전에 분할합니다. 강제되는 경우maxChars에서 분할합니다. - 분할 선호도:
paragraph→newline→sentence→whitespace→ 강제 분할. - 코드 펜스: 펜스 내부에서는 절대 분할하지 않습니다.
maxChars에서 강제 분할될 때는 Markdown 유효성을 유지하기 위해 펜스를 닫고 다시 엽니다.
maxChars는 채널 textChunkLimit로 제한되므로 채널별 상한을 초과할 수 없습니다.
병합(coalescing, 스트리밍된 블록 병합)
블록 스트리밍이 활성화되면 OpenClaw는 연속된 블록 청크를 병합한 후 전송할 수 있습니다. 이렇게 하면 진행형 출력을 유지하면서도 “한 줄짜리 스팸”을 줄일 수 있습니다.- 병합은 flush 전에 유휴 간격(
idleMs)을 기다립니다. - 버퍼는
maxChars로 제한되며, 이를 초과하면 flush됩니다. minChars는 충분한 텍스트가 누적될 때까지 작은 조각이 전송되지 않도록 합니다 (최종 flush는 항상 남은 텍스트를 전송).- 결합자는
blockStreamingChunk.breakPreference에서 파생됩니다 (paragraph→\n\n,newline→\n,sentence→ 공백). *.blockStreamingCoalesce를 통한 채널 재정의도 사용할 수 있습니다(계정별 config 포함).- 재정의되지 않은 경우 Signal/Slack/Discord의 기본 coalesce
minChars는 1500으로 올라갑니다.
블록 간 사람 같은 페이싱
블록 스트리밍이 활성화되면 블록 답장 사이에 무작위 일시 정지를 추가할 수 있습니다 (첫 번째 블록 이후). 이렇게 하면 여러 버블로 나뉜 응답이 더 자연스럽게 느껴집니다.- config:
agents.defaults.humanDelay(에이전트별 재정의:agents.list[].humanDelay). - 모드:
off(기본값),natural(800–2500ms),custom(minMs/maxMs). - 블록 답장에만 적용되며, 최종 답장이나 도구 요약에는 적용되지 않습니다.
”청크로 스트리밍할지 전부 보낼지”
이는 다음에 매핑됩니다:- 청크 스트리밍:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(작성하면서 전송). Telegram이 아닌 채널은*.blockStreaming: true도 필요합니다. - 마지막에 전부 스트리밍:
blockStreamingBreak: "message_end"(한 번 flush, 매우 길면 여러 청크 가능). - 블록 스트리밍 없음:
blockStreamingDefault: "off"(최종 답장만 전송).
*.blockStreaming이
명시적으로 true로 설정되지 않으면 비활성화됩니다. 채널은 블록 답장 없이도
실시간 미리보기(channels.<channel>.streaming)를 스트리밍할 수 있습니다.
config 위치 참고: blockStreaming* 기본값은 루트 config가 아니라
agents.defaults 아래에 있습니다.
미리보기 스트리밍 모드
정식 키:channels.<channel>.streaming
모드:
off: 미리보기 스트리밍 비활성화.partial: 최신 텍스트로 교체되는 단일 미리보기.block: 청크/추가 단계로 업데이트되는 미리보기.progress: 생성 중 진행/상태 미리보기, 완료 시 최종 답변.
채널 매핑
| 채널 | off | partial | block | progress |
|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | partial로 매핑 |
| Discord | ✅ | ✅ | ✅ | partial로 매핑 |
| Slack | ✅ | ✅ | ✅ | ✅ |
channels.slack.nativeStreaming은streaming=partial일 때 Slack 기본 스트리밍 API 호출을 전환합니다(기본값:true).
- Telegram:
streamMode+ 불리언streaming은 자동으로streamingenum으로 마이그레이션됩니다. - Discord:
streamMode+ 불리언streaming은 자동으로streamingenum으로 마이그레이션됩니다. - Slack:
streamMode는 자동으로streamingenum으로 마이그레이션되며, 불리언streaming은 자동으로nativeStreaming으로 마이그레이션됩니다.
런타임 동작
Telegram:- DM과 그룹/토픽 전반에서
sendMessage+editMessageText미리보기 업데이트를 사용합니다. - Telegram 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍은 건너뜁니다(이중 스트리밍 방지).
/reasoning stream은 reasoning을 미리보기에 쓸 수 있습니다.
- 전송 + 편집 미리보기 메시지를 사용합니다.
block모드는 초안 청킹(draftChunk)을 사용합니다.- Discord 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍은 건너뜁니다.
partial은 사용 가능한 경우 Slack 기본 스트리밍(chat.startStream/append/stop)을 사용할 수 있습니다.block은 추가형 초안 미리보기를 사용합니다.progress는 상태 미리보기 텍스트를 사용한 뒤 완료 시 최종 답변을 전송합니다.