Concept internals
Markdown-opmaak
OpenClaw zet uitgaande Markdown om in een gedeelde tussenrepresentatie (IR) voordat kanaalspecifieke uitvoer wordt gerenderd. De IR bevat platte tekst plus stijl-/linkbereiken, zodat één parseerstap elk kanaal bedient en het opdelen in chunks de opmaak nooit midden in een bereik splitst.
Pijplijn
- Markdown naar IR parsen (
markdownToIR) - platte tekst plus stijlbereiken (vet, cursief, doorgestreept, code, codeblok, spoiler, blokcitaat, kop 1-6) en linkbereiken. Offsets zijn UTF-16-code-eenheden, zodat de stijlbereiken van Signal rechtstreeks aansluiten op de API. Tabellen worden alleen geparseerd wanneer het kanaal een tabelmodus inschakelt. - De IR opdelen in chunks (
chunkMarkdownIR/renderMarkdownIRChunksWithinLimit)- het splitsen gebeurt vóór het renderen op de IR-tekst, zodat inline stijlen en links per chunk worden opgesplitst in plaats van over een grens heen te breken.
- Per kanaal renderen (
renderMarkdownWithMarkers) - een toewijzing van stijlmarkeringen zet bereiken om in de eigen opmaak van het kanaal.
| Kanaal | Renderer | Opmerkingen |
|---|---|---|
| Slack | mrkdwn-tokens (*bold*, _italic_, `code`, code fences) |
Links worden <url|label>; autolink is tijdens het parsen uitgeschakeld om dubbele links te voorkomen |
| Telegram | HTML-tags (<b>, <i>, <s>, <code>, <pre><code>, <a href>, <tg-spoiler>) |
Ondersteunt ook tabellen en koppen in uitgebreide berichten (<h1>-<h6>) wanneer richMessages is ingeschakeld |
| Signal | platte tekst + text-style-bereiken |
Links worden gerenderd als label (url) wanneer het label afwijkt van de URL |
| Discord, WhatsApp, iMessage, Microsoft Teams en andere kanalen | platte tekst | Geen op IR gebaseerde opmaak; conversie van Markdown-tabellen wordt nog steeds uitgevoerd via convertMarkdownTables |
IR-voorbeeld
Markdown-invoer:
Hallo **wereld** - bekijk de [documentatie](https://docs.openclaw.ai).IR (schematisch):
{ "text": "Hallo wereld - bekijk de documentatie.", "styles": [{ "start": 6, "end": 12, "style": "bold" }], "links": [{ "start": 27, "end": 39, "href": "https://docs.openclaw.ai" }]}Tabelverwerking
markdown.tables bepaalt hoe een kanaal Markdown-tabellen converteert, per
kanaal en optioneel per account:
| Modus | Gedrag |
|---|---|
code |
Renderen als een uitgelijnde ASCII-tabel in een codeblok (standaardterugvaloptie) |
bullets |
Elke rij omzetten in label: value-opsommingstekens |
block |
Eigen tabellen behouden waar het transport ze ondersteunt; anders terugvallen op code |
off |
Het parsen van tabellen uitschakelen; onbewerkte tabeltekst wordt ongewijzigd doorgegeven |
Standaardwaarden van plugins per kanaal: Signal, WhatsApp en Matrix gebruiken standaard
bullets; Mattermost gebruikt standaard off; Telegram gebruikt standaard block (wat
wordt omgezet in code, tenzij richMessages voor het account is ingeschakeld). Elk
kanaal zonder een expliciete standaardwaarde van de plugin valt terug op code.
channels: discord: markdown: tables: code accounts: work: markdown: tables: offRegels voor het opdelen in chunks
- Chunklimieten zijn afkomstig van kanaaladapters/configuratie en gelden voor IR-tekst, niet voor gerenderde uitvoer.
- Omheinde codeblokken worden als één blok behouden met een afsluitende nieuwe regel, zodat kanalen de afsluitende omheining correct renderen.
- Voorvoegsels van lijsten en blokcitaten maken deel uit van de IR-tekst, zodat het opdelen in chunks nooit midden in een voorvoegsel splitst.
- Inline stijlen worden nooit over chunks gesplitst; de renderer heropent een geopende stijl aan het begin van de volgende chunk.
Zie Streaming en opdelen in chunks voor chunkgrenzen en aflevergedrag voor verschillende kanalen.
Linkbeleid
- Slack:
[label](url)-><url|label>; kale URL's blijven kaal. - Telegram:
[label](url)-><a href="url">label</a>(HTML-parseermodus). - Signal:
[label](url)->label (url), tenzij het label al overeenkomt met de URL.
Spoilers
Spoilermarkeringen (||spoiler||) worden geparseerd voor Signal (toegewezen aan
SPOILER-stijlbereiken) en Telegram (toegewezen aan <tg-spoiler>). Andere kanalen behandelen
||...|| als platte tekst.
Een kanaalformatter toevoegen of bijwerken
- Eenmaal parsen met
markdownToIR(...), met voor het kanaal geschikte opties (autolink,headingStyle,blockquotePrefix,tableMode). - Renderen met
renderMarkdownWithMarkers(...)en een toewijzing van stijlmarkeringen (of aangepaste stijlbereiklogica voor transportsystemen zoals Signal). - Opdelen in chunks met
chunkMarkdownIR(...)ofrenderMarkdownIRChunksWithinLimit(...)voordat elke chunk wordt gerenderd. - De adapter koppelen zodat deze de nieuwe chunker en renderer aanroept vanuit het uitgaande verzendpad.
- Testen met opmaaktests plus een test voor uitgaande aflevering als het kanaal chunks gebruikt.
Veelvoorkomende valkuilen
- Slack-tokens met punthaken (
<@U123>,<#C123>,<https://...>) moeten het escapen overleven; onbewerkte HTML moet nog steeds veilig worden geëscapet. - Voor Telegram-HTML moet tekst buiten tags worden geëscapet om gebroken opmaak te voorkomen.
- Signal-stijlbereiken gebruiken UTF-16-offsets, geen codepuntafwijkingen.
- Behoud afsluitende nieuwe regels bij omheinde codeblokken, zodat de afsluitende markering op een eigen regel terechtkomt.