Markdown-Formatierung
OpenClaw formatiert ausgehendes Markdown, indem es vor dem Rendern kanalspezifischer Ausgabe in eine gemeinsame Zwischenrepräsentation (IR) konvertiert wird. Die IR hält den Quelltext unverändert und trägt gleichzeitig Stil-/Link-Spannen, sodass Chunking und Rendering kanalübergreifend konsistent bleiben.Ziele
- Konsistenz: ein Parse-Schritt, mehrere Renderer.
- Sicheres Chunking: Text vor dem Rendern aufteilen, sodass Inline-Formatierung niemals über Chunk-Grenzen hinweg bricht.
- Kanaltauglichkeit: dieselbe IR auf Slack mrkdwn, Telegram HTML und Signal-Stilbereiche abbilden, ohne Markdown erneut zu parsen.
Pipeline
- Markdown parsen -> IR
- Die IR besteht aus Klartext plus Stilspannen (fett/kursiv/durchgestrichen/Code/Spoiler) und Link-Spannen.
- Offsets sind UTF-16-Codeeinheiten, damit Signal-Stilbereiche mit seiner API übereinstimmen.
- Tabellen werden nur geparst, wenn ein Kanal die Tabellenkonvertierung aktiviert.
- IR chunken (format-first)
- Das Chunking erfolgt auf dem IR-Text vor dem Rendern.
- Inline-Formatierung wird nicht über Chunks hinweg geteilt; Spannen werden pro Chunk geschnitten.
- Pro Kanal rendern
- Slack: mrkdwn-Tokens (fett/kursiv/durchgestrichen/Code), Links als
<url|label>. - Telegram: HTML-Tags (
<b>,<i>,<s>,<code>,<pre><code>,<a href>). - Signal: Klartext +
text-style-Bereiche; Links werden zulabel (url), wenn sich das Label unterscheidet.
- Slack: mrkdwn-Tokens (fett/kursiv/durchgestrichen/Code), Links als
IR-Beispiel
Eingabe-Markdown:Wo es verwendet wird
- Slack-, Telegram- und Signal-Outbound-Adapter rendern aus der IR.
- Andere Kanäle (WhatsApp, iMessage, MS Teams, Discord) verwenden weiterhin Klartext oder ihre eigenen Formatierungsregeln; die Markdown-Tabellenkonvertierung wird – wenn aktiviert – vor dem Chunking angewendet.
Tabellenbehandlung
Markdown-Tabellen werden von Chat-Clients nicht einheitlich unterstützt. Verwenden Siemarkdown.tables, um die Konvertierung pro Kanal (und pro Account) zu steuern.
code: Tabellen als Codeblöcke rendern (Standard für die meisten Kanäle).bullets: Jede Zeile in Aufzählungspunkte umwandeln (Standard für Signal + WhatsApp).off: Tabellenparsing und -konvertierung deaktivieren; der rohe Tabellentext wird durchgereicht.
Chunking-Regeln
- Chunk-Limits stammen aus Kanaladaptern/-konfigurationen 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, sodass das Chunking nicht mitten im Präfix trennt.
- Inline-Stile (fett/kursiv/durchgestrichen/Inline-Code/Spoiler) werden niemals über Chunks hinweg geteilt; der Renderer öffnet Stile innerhalb jedes Chunks erneut.
Link-Richtlinie
- Slack:
[label](url)-><url|label>; nackte URLs bleiben nackt. Autolinking ist beim Parsen deaktiviert, um doppeltes Verlinken zu vermeiden. - Telegram:
[label](url)-><a href="url">label</a>(HTML-Parse-Modus). - Signal:
[label](url)->label (url), sofern das Label nicht der URL entspricht.
Spoiler
Spoiler-Markierungen (||spoiler||) werden nur für Signal geparst, wo sie auf
SPOILER-Stilbereiche abgebildet werden. Andere Kanäle behandeln sie als Klartext.
So fügen Sie einen Kanal-Formatter hinzu oder aktualisieren ihn
- Einmal parsen: Verwenden Sie den gemeinsamen
markdownToIR(...)-Helper mit kanalgerechten Optionen (Autolink, Überschriftenstil, Blockquote-Präfix). - Rendern: Implementieren Sie einen Renderer mit
renderMarkdownWithMarkers(...)und einer Stilmarker-Zuordnung (oder Signal-Stilbereichen). - Chunking: Rufen Sie
chunkMarkdownIR(...)vor dem Rendern auf; rendern Sie jeden Chunk. - Adapter verdrahten: Aktualisieren Sie den Kanal-Outbound-Adapter, um den neuen Chunker und Renderer zu verwenden.
- Testen: Fügen Sie Format-Tests hinzu oder aktualisieren Sie sie sowie einen Outbound-Zustelltest, falls der Kanal Chunking verwendet.
Häufige Stolperfallen
- Slack-Winkelklammer-Tokens (
<@U123>,<#C123>,<https://...>) müssen beibehalten werden; escapen Sie rohes HTML sicher. - Telegram-HTML erfordert das Escapen von Text außerhalb von Tags, um kaputtes Markup zu vermeiden.
- Signal-Stilbereiche hängen von UTF-16-Offets ab; verwenden Sie keine Codepoint-Offets.
- Behalten Sie abschließende Zeilenumbrüche für eingefasste Codeblöcke bei, damit schließende Marker in einer eigenen Zeile landen.