Markdown-Formatierung
OpenClaw formatiert ausgehendes Markdown, indem es in eine gemeinsame Zwischendarstellung (IR) konvertiert wird, bevor die kanalspezifische Ausgabe gerendert wird. Die IR behaelt den Quelltext intakt und traegt Style-/Link-Spans, damit Chunking und Rendering kanaluebergreifend konsistent bleiben.
Ziele
- Konsistenz: ein Parse-Schritt, mehrere Renderer.
- Sicheres Chunking: Text vor dem Rendering aufteilen, damit Inline-Formatierung nie ueber Chunk-Grenzen bricht.
- Kanalanpassung: dieselbe IR auf Slack-mrkdwn, Telegram-HTML und Signal-Style-Ranges abbilden, ohne Markdown erneut zu parsen.
Pipeline
- Markdown -> IR parsen
- Die IR ist Klartext plus Style-Spans (fett/kursiv/durchgestrichen/Code/Spoiler) und Link-Spans.
- Offsets sind UTF-16-Code-Units, damit Signal-Style-Ranges mit seiner API uebereinstimmen.
- Tabellen werden nur geparst, wenn ein Kanal die Tabellenkonvertierung aktiviert hat.
- IR chunken (Format zuerst)
- Chunking geschieht am IR-Text vor dem Rendering.
- Inline-Formatierung wird nicht ueber Chunks aufgeteilt; Spans 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-Ranges; Links werden zulabel (url), wenn sich Label und URL unterscheiden.
- Slack: mrkdwn-Tokens (fett/kursiv/durchgestrichen/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" }]
}
Einsatzorte
- Die ausgehenden Adapter fuer Slack, Telegram und Signal rendern aus der IR.
- Andere Kanaele (WhatsApp, iMessage, MS Teams, Discord) verwenden weiterhin Klartext oder eigene Formatierungsregeln, wobei Markdown-Tabellenkonvertierung vor dem Chunking angewandt wird, wenn aktiviert.
Tabellenbehandlung
Markdown-Tabellen werden nicht einheitlich von allen Chat-Clients unterstuetzt. Verwende
markdown.tables, um die Konvertierung pro Kanal (und pro Account) zu steuern.
code: Tabellen als Code-Bloecke rendern (Standard fuer die meisten Kanaele).bullets: jede Zeile in Aufzaehlungspunkte umwandeln (Standard fuer Signal und WhatsApp).off: Tabellen-Parsing und -Konvertierung deaktivieren; der rohe Tabellentext wird durchgereicht.
Konfigurations-Schluessel:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
Chunking-Regeln
- Chunk-Limits kommen von den Kanal-Adaptern/der Konfiguration und werden auf den IR-Text angewandt.
- Code-Fences werden als einzelner Block mit abschliessendem Newline beibehalten, damit Kanaele sie korrekt rendern.
- Listen-Praefixe und Blockquote-Praefixe sind Teil des IR-Textes, sodass Chunking nicht mitten im Praefix trennt.
- Inline-Styles (fett/kursiv/durchgestrichen/Inline-Code/Spoiler) werden nie ueber Chunks aufgeteilt; der Renderer oeffnet Styles innerhalb jedes Chunks neu.
Wenn du mehr ueber das Chunking-Verhalten kanaluebergreifend wissen moechtest, siehe Streaming und Chunking.
Link-Policy
- Slack:
[label](/docs/concepts/url)-><url|label>; nackte URLs bleiben nackt. Autolink wird beim Parsen deaktiviert, um Doppel-Verlinkung zu vermeiden. - Telegram:
[label](/docs/concepts/url)-><a href="url">label</a>(HTML-Parse-Modus). - Signal:
[label](/docs/concepts/url)->label (url), es sei denn, Label und URL stimmen ueberein.
Spoiler
Spoiler-Marker (||spoiler||) werden nur fuer Signal geparst, wo sie auf
SPOILER-Style-Ranges abgebildet werden. Andere Kanaele behandeln sie als Klartext.
Einen Kanal-Formatter hinzufuegen oder aktualisieren
- Einmal parsen: Verwende den gemeinsamen
markdownToIR(...)-Helper mit kanalgerechten Optionen (Autolink, Heading-Style, Blockquote-Praefix). - Rendern: Implementiere einen Renderer mit
renderMarkdownWithMarkers(...)und einer Style-Marker-Map (oder Signal-Style-Ranges). - Chunken: Rufe
chunkMarkdownIR(...)vor dem Rendering auf; rendere jeden Chunk. - Adapter verdrahten: Aktualisiere den ausgehenden Kanal-Adapter fuer den neuen Chunker und Renderer.
- Testen: Fuege Format-Tests und einen ausgehenden Zustellungs-Test hinzu oder aktualisiere sie, wenn der Kanal Chunking nutzt.
Haeufige Stolperfallen
- Slack-Winkelklammer-Tokens (
<@U123>,<#C123>,<https://...>) muessen erhalten bleiben; rohes HTML sicher escapen. - Telegram-HTML erfordert Escaping von Text ausserhalb von Tags, um kaputtes Markup zu vermeiden.
- Signal-Style-Ranges haengen von UTF-16-Offsets ab; verwende keine Code-Point-Offsets.
- Bewahre abschliessende Newlines fuer Fenced-Code-Bloecke, damit Schlussmarker auf einer eigenen Zeile landen.