Concept internals
Formatowanie Markdown
OpenClaw formatuje wychodzący Markdown, konwertując go na wspólną pośrednią reprezentację (IR) przed renderowaniem danych wyjściowych specyficznych dla kanału. IR zachowuje tekst źródłowy bez zmian, jednocześnie przenosząc zakresy stylów/linków, aby dzielenie na fragmenty i renderowanie mogły pozostać spójne między kanałami.
Cele
- Spójność: jeden etap parsowania, wiele rendererów.
- Bezpieczne dzielenie na fragmenty: dziel tekst przed renderowaniem, aby formatowanie liniowe nigdy nie przerywało się między fragmentami.
- Dopasowanie do kanału: mapuj to samo IR na Slack mrkdwn, HTML Telegram i zakresy stylów Signal bez ponownego parsowania Markdown.
Potok
- Parsuj Markdown -> IR
- IR to zwykły tekst oraz zakresy stylów (pogrubienie/kursywa/przekreślenie/kod/spoiler) i zakresy linków.
- Przesunięcia są jednostkami kodu UTF-16, aby zakresy stylów Signal były zgodne z jego API.
- Tabele są parsowane tylko wtedy, gdy kanał włącza konwersję tabel.
- Dziel IR na fragmenty (najpierw formatowanie)
- Dzielenie na fragmenty odbywa się na tekście IR przed renderowaniem.
- Formatowanie liniowe nie jest dzielone między fragmentami; zakresy są wycinane dla każdego fragmentu.
- Renderuj dla kanału
- Slack: tokeny mrkdwn (pogrubienie/kursywa/przekreślenie/kod), linki jako
<url|label>. - Telegram: tagi HTML (
<b>,<i>,<s>,<code>,<pre><code>,<a href>). - Signal: zwykły tekst + zakresy
text-style; linki stają sięlabel (url), gdy etykieta się różni.
- Slack: tokeny mrkdwn (pogrubienie/kursywa/przekreślenie/kod), linki jako
Przykład IR
Wejściowy Markdown:
Hello **world** - see [docs](https://docs.openclaw.ai).
IR (schematycznie):
{
"text": "Hello world - see docs.",
"styles": [{ "start": 6, "end": 11, "style": "bold" }],
"links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]
}
Gdzie jest używane
- Adaptery wychodzące Slack, Telegram i Signal renderują z IR.
- Inne kanały (WhatsApp, iMessage, Microsoft Teams, Discord) nadal używają zwykłego tekstu lub własnych reguł formatowania, z konwersją tabel Markdown stosowaną przed dzieleniem na fragmenty, gdy jest włączona.
Obsługa tabel
Tabele Markdown nie są spójnie obsługiwane przez klientów czatu. Użyj
markdown.tables, aby kontrolować konwersję dla każdego kanału (i konta).
code: renderuj tabele jako bloki kodu (domyślnie dla większości kanałów).bullets: konwertuj każdy wiersz na punkty listy (domyślnie dla Signal + WhatsApp).off: wyłącz parsowanie i konwersję tabel; surowy tekst tabeli przechodzi dalej.
Klucze konfiguracji:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
Reguły dzielenia na fragmenty
- Limity fragmentów pochodzą z adapterów/konfiguracji kanałów i są stosowane do tekstu IR.
- Ogrodzenia kodu są zachowywane jako pojedynczy blok z końcowym znakiem nowej linii, aby kanały renderowały je poprawnie.
- Prefiksy list i prefiksy cytatów blokowych są częścią tekstu IR, więc dzielenie na fragmenty nie rozdziela ich w środku prefiksu.
- Style liniowe (pogrubienie/kursywa/przekreślenie/kod liniowy/spoiler) nigdy nie są dzielone między fragmentami; renderer ponownie otwiera style wewnątrz każdego fragmentu.
Jeśli potrzebujesz więcej informacji o zachowaniu dzielenia na fragmenty między kanałami, zobacz Strumieniowanie + dzielenie na fragmenty.
Zasady linków
- Slack:
[label](url)-><url|label>; gołe adresy URL pozostają gołe. Autolink jest wyłączony podczas parsowania, aby uniknąć podwójnego linkowania. - Telegram:
[label](url)-><a href="url">label</a>(tryb parsowania HTML). - Signal:
[label](url)->label (url), chyba że etykieta pasuje do adresu URL.
Spoilery
Znaczniki spoilerów (||spoiler||) są parsowane tylko dla Signal, gdzie są mapowane na
zakresy stylu SPOILER. Inne kanały traktują je jako zwykły tekst.
Jak dodać lub zaktualizować formatter kanału
- Parsuj raz: użyj wspólnego helpera
markdownToIR(...)z opcjami odpowiednimi dla kanału (autolink, styl nagłówków, prefiks cytatu blokowego). - Renderuj: zaimplementuj renderer z
renderMarkdownWithMarkers(...)i mapą znaczników stylów (lub zakresami stylów Signal). - Dziel na fragmenty: wywołaj
chunkMarkdownIR(...)przed renderowaniem; renderuj każdy fragment. - Podłącz adapter: zaktualizuj adapter wychodzący kanału, aby używał nowego mechanizmu dzielenia na fragmenty i renderera.
- Testuj: dodaj lub zaktualizuj testy formatowania oraz test dostarczania wychodzącego, jeśli kanał używa dzielenia na fragmenty.
Typowe pułapki
- Tokeny Slack w nawiasach ostrych (
<@U123>,<#C123>,<https://...>) muszą być zachowane; bezpiecznie escapuj surowy HTML. - HTML Telegram wymaga escapowania tekstu poza tagami, aby uniknąć uszkodzonego znacznikowania.
- Zakresy stylów Signal zależą od przesunięć UTF-16; nie używaj przesunięć punktów kodowych.
- Zachowuj końcowe znaki nowej linii dla ogrodzonych bloków kodu, aby znaczniki zamykające trafiały do własnej linii.