Streaming + Chunking
OpenClaw hat zwei separate Streaming-Ebenen:
- Block-Streaming (Channels): Sendet fertige Blöcke, sobald der Assistent sie schreibt. Das sind normale Channel-Nachrichten (keine Token-Deltas).
- Token-artiges Streaming (nur Telegram): Aktualisiert eine Draft-Blase mit Teiltext während der Generierung; die finale Nachricht wird am Ende gesendet.
Es gibt kein echtes Token-Streaming zu externen Channel-Nachrichten. Telegram Draft-Streaming ist die einzige Oberfläche mit Teilausgabe.
Block-Streaming (Channel-Nachrichten)
Block-Streaming sendet die Ausgabe des Assistenten in groben Blöcken, sobald sie verfügbar ist.
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)
Legende:
text_delta/events: Model-Stream-Events (können bei nicht-streamenden Modellen spärlich sein).chunker:EmbeddedBlockChunkerwendet min/max-Grenzen + Break-Präferenz an.channel send: tatsächlich ausgehende Nachrichten (Block-Antworten).
Steuerung:
agents.defaults.blockStreamingDefault:"on"/"off"(Standard: off).- Channel-Overrides:
*.blockStreaming(und Account-spezifische Varianten) um"on"/"off"pro Channel zu erzwingen. agents.defaults.blockStreamingBreak:"text_end"oder"message_end".agents.defaults.blockStreamingChunk:{ minChars, maxChars, breakPreference? }.agents.defaults.blockStreamingCoalesce:{ minChars?, maxChars?, idleMs? }(gestreamte Blöcke vor dem Senden zusammenführen).- Channel-Hardcap:
*.textChunkLimit(z.B.channels.whatsapp.textChunkLimit). - Channel-Chunk-Modus:
*.chunkMode(lengthStandard,newlinetrennt an Leerzeilen (Absatzgrenzen) vor dem Längen-Chunking). - Discord-Softcap:
channels.discord.maxLinesPerMessage(Standard: 17) teilt hohe Antworten auf, um UI-Clipping zu vermeiden.
Grenz-Semantik:
text_end: Blöcke streamen, sobald der Chunker sie ausgibt; bei jedemtext_endflushen.message_end: Warten bis die Assistenten-Nachricht fertig ist, dann gepufferte Ausgabe flushen.
message_end nutzt trotzdem den Chunker, wenn der gepufferte Text maxChars überschreitet, sodass am Ende mehrere Chunks ausgegeben werden können.
Chunking-Algorithmus (Low/High Bounds)
Block-Chunking wird von EmbeddedBlockChunker implementiert:
- Low Bound: Nicht ausgeben, bis Buffer >=
minChars(außer erzwungen). - High Bound: Bevorzugt Splits vor
maxChars; wenn erzwungen, Split beimaxChars. - Break-Präferenz:
paragraph→newline→sentence→whitespace→ Hard Break. - Code-Fences: Niemals innerhalb von Fences splitten; wenn bei
maxCharserzwungen, Fence schließen + wieder öffnen, um Markdown valide zu halten.
maxChars wird auf das Channel-textChunkLimit begrenzt, sodass du die Channel-Caps nicht überschreiten kannst.
Coalescing (gestreamte Blöcke zusammenführen)
Wenn Block-Streaming aktiviert ist, kann OpenClaw aufeinanderfolgende Block-Chunks zusammenführen, bevor sie gesendet werden. Das reduziert “Einzeiler-Spam” und liefert trotzdem progressive Ausgabe.
- Coalescing wartet auf Idle-Gaps (
idleMs) vor dem Flushen. - Buffer sind durch
maxCharsbegrenzt und flushen, wenn sie es überschreiten. minCharsverhindert, dass winzige Fragmente gesendet werden, bis genug Text angesammelt ist (finaler Flush sendet immer den restlichen Text).- Der Joiner wird von
blockStreamingChunk.breakPreferenceabgeleitet (paragraph→\n\n,newline→\n,sentence→ Leerzeichen). - Channel-Overrides sind über
*.blockStreamingCoalesceverfügbar (inklusive Account-spezifischer Configs). - Standard-Coalesce
minCharswird auf 1500 für Signal/Slack/Discord erhöht, sofern nicht überschrieben.
Menschenähnliches Pacing zwischen Blöcken
Wenn Block-Streaming aktiviert ist, kannst du eine zufällige Pause zwischen Block-Antworten hinzufügen (nach dem ersten Block). Das lässt Multi-Bubble-Antworten natürlicher wirken.
- Config:
agents.defaults.humanDelay(Override pro Agent viaagents.list[].humanDelay). - Modi:
off(Standard),natural(800–2500ms),custom(minMs/maxMs). - Gilt nur für Block-Antworten, nicht für finale Antworten oder Tool-Zusammenfassungen.
”Chunks streamen oder alles”
Das entspricht:
- Chunks streamen:
blockStreamingDefault: "on"+blockStreamingBreak: "text_end"(ausgeben während du schreibst). Nicht-Telegram-Channels brauchen auch*.blockStreaming: true. - Alles am Ende streamen:
blockStreamingBreak: "message_end"(einmal flushen, möglicherweise mehrere Chunks wenn sehr lang). - Kein Block-Streaming:
blockStreamingDefault: "off"(nur finale Antwort).
Channel-Hinweis: Für Nicht-Telegram-Channels ist Block-Streaming aus, außer *.blockStreaming ist explizit auf true gesetzt. Telegram kann Drafts streamen (channels.telegram.streamMode) ohne Block-Antworten.
Config-Erinnerung: Die blockStreaming*-Defaults liegen unter agents.defaults, nicht in der Root-Config.
Telegram Draft-Streaming (Token-artig)
Telegram ist der einzige Channel mit Draft-Streaming:
- Nutzt Bot API
sendMessageDraftin privaten Chats mit Topics. channels.telegram.streamMode: "partial" | "block" | "off".partial: Draft-Updates mit dem neuesten Stream-Text.block: Draft-Updates in Chunk-Blöcken (gleiche Chunker-Regeln).off: Kein Draft-Streaming.
- Draft-Chunk-Config (nur für
streamMode: "block"):channels.telegram.draftChunk(Defaults:minChars: 200,maxChars: 800). - Draft-Streaming ist getrennt von Block-Streaming; Block-Antworten sind standardmäßig aus und werden nur durch
*.blockStreaming: trueauf Nicht-Telegram-Channels aktiviert. - Die finale Antwort ist weiterhin eine normale Nachricht.
/reasoning streamschreibt Reasoning in die Draft-Blase (nur Telegram).
Wenn Draft-Streaming aktiv ist, deaktiviert OpenClaw Block-Streaming für diese Antwort, um Doppel-Streaming zu vermeiden.
Telegram (private + topics)
└─ sendMessageDraft (draft bubble)
├─ streamMode=partial → update latest text
└─ streamMode=block → chunker updates draft
└─ final reply → normal message
Legende:
sendMessageDraft: Telegram Draft-Blase (keine echte Nachricht).final reply: normaler Telegram-Nachrichtenversand.