Concept internals
Markdown-Formatierung
OpenClaw formatiert ausgehendes Markdown, indem es vor dem Rendern kanalspezifischer Ausgaben in eine gemeinsame Zwischenrepräsentation (IR) konvertiert wird. Die IR hält den Quelltext unverändert und führt gleichzeitig Stil- und Link-Spans mit, damit Segmentierung und Rendering kanalübergreifend konsistent bleiben.
Ziele
- Konsistenz: ein Parsing-Schritt, mehrere Renderer.
- Sichere Segmentierung: Text vor dem Rendering aufteilen, damit Inline-Formatierung nie über Segmente hinweg bricht.
- Kanaleignung: dieselbe IR Slack mrkdwn, Telegram HTML und Signal Stilbereichen zuordnen, ohne Markdown erneut zu parsen.
Pipeline
- Markdown parsen -> IR
- IR ist reiner Text plus Stil-Spans (bold/italic/strike/code/spoiler) und Link-Spans.
- Offsets sind UTF-16-Codeeinheiten, damit Signal-Stilbereiche mit der API übereinstimmen.
- Tabellen werden nur geparst, wenn ein Kanal die Tabellenkonvertierung aktiviert.
- IR segmentieren (Format zuerst)
- Die Segmentierung erfolgt auf dem IR-Text vor dem Rendering.
- Inline-Formatierung wird nicht über Segmente hinweg geteilt; Spans werden pro Segment zugeschnitten.
- Pro Kanal rendern
- Slack: mrkdwn-Token (bold/italic/strike/code), Links als
<url|label>. - Telegram: HTML-Tags (
<b>,<i>,<s>,<code>,<pre><code>,<a href>). - Signal: reiner Text +
text-style-Bereiche; Links werden zulabel (url), wenn das Label abweicht.
- Slack: mrkdwn-Token (bold/italic/strike/code), Links als
IR-Beispiel
Eingabe-Markdown:
Hello **world** - see [docs](https://docs.openclaw.ai).
IR (schematisch):
{
"text": "Hello world - see docs.",
"styles": [{ "start": 6, "end": 11, "style": "bold" }],
"links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]
}
Wo sie verwendet wird
- Ausgehende Adapter für Slack, Telegram und Signal rendern aus der IR.
- Andere Kanäle (WhatsApp, iMessage, Microsoft Teams, Discord) verwenden weiterhin reinen Text oder eigene Formatierungsregeln, wobei die Markdown-Tabellenkonvertierung bei Aktivierung vor der Segmentierung angewendet wird.
Tabellenbehandlung
Markdown-Tabellen werden nicht von allen Chat-Clients einheitlich unterstützt. Verwenden Sie
markdown.tables, um die Konvertierung pro Kanal (und pro Konto) zu steuern.
code: Tabellen als Codeblöcke rendern (Standard für die meisten Kanäle).bullets: jede Zeile in Aufzählungspunkte konvertieren (Standard für Signal + WhatsApp).off: Tabellen-Parsing und -Konvertierung deaktivieren; roher Tabellentext wird unverändert weitergereicht.
Konfigurationsschlüssel:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
Segmentierungsregeln
- Segmentgrenzen stammen aus Kanaladaptern bzw. der Konfiguration und werden auf den IR-Text angewendet.
- Code-Fences werden als einzelner Block mit nachgestelltem Zeilenumbruch beibehalten, damit Kanäle sie korrekt rendern.
- Listenpräfixe und Blockquote-Präfixe sind Teil des IR-Texts, daher teilt die Segmentierung nicht mitten im Präfix.
- Inline-Stile (bold/italic/strike/inline-code/spoiler) werden nie über Segmente hinweg geteilt; der Renderer öffnet Stile innerhalb jedes Segments erneut.
Wenn Sie mehr über das Segmentierungsverhalten kanalübergreifend benötigen, siehe Streaming + Segmentierung.
Link-Richtlinie
- Slack:
[label](url)-><url|label>; reine URLs bleiben unverändert. Autolink ist während des Parsings deaktiviert, um doppelte Verlinkung zu vermeiden. - Telegram:
[label](url)-><a href="url">label</a>(HTML-Parse-Modus). - Signal:
[label](url)->label (url), außer das Label entspricht der URL.
Spoiler
Spoiler-Marker (||spoiler||) werden nur für Signal geparst, wo sie
SPOILER-Stilbereichen zugeordnet werden. Andere Kanäle behandeln sie als reinen Text.
Kanal-Formatter hinzufügen oder aktualisieren
- Einmal parsen: Verwenden Sie den gemeinsamen
markdownToIR(...)-Helper mit kanalgeeigneten Optionen (Autolink, Überschriftenstil, Blockquote-Präfix). - Rendern: Implementieren Sie einen Renderer mit
renderMarkdownWithMarkers(...)und einer Stilmarker-Zuordnung (oder Signal-Stilbereichen). - Segmentieren: Rufen Sie
chunkMarkdownIR(...)vor dem Rendering auf; rendern Sie jedes Segment. - Adapter verdrahten: Aktualisieren Sie den ausgehenden Kanaladapter, damit er den neuen Segmentierer und Renderer verwendet.
- Testen: Fügen Sie Formatierungstests und einen Test für ausgehende Zustellung hinzu oder aktualisieren Sie sie, wenn der Kanal Segmentierung verwendet.
Häufige Fallstricke
- Slack-Token in spitzen Klammern (
<@U123>,<#C123>,<https://...>) müssen beibehalten werden; escapen Sie rohes HTML sicher. - Telegram HTML erfordert das Escaping von Text außerhalb von Tags, um fehlerhaftes Markup zu vermeiden.
- Signal-Stilbereiche hängen von UTF-16-Offsets ab; verwenden Sie keine Codepoint-Offsets.
- Behalten Sie nachgestellte Zeilenumbrüche für eingezäunte Codeblöcke bei, damit Abschlussmarker in ihrer eigenen Zeile stehen.