Concept internals
Форматування Markdown
OpenClaw форматує вихідний Markdown, перетворюючи його на спільне проміжне представлення (IR) перед рендерингом виводу, специфічного для каналу. IR зберігає вихідний текст незмінним і водночас переносить діапазони стилів/посилань, щоб розбиття на фрагменти й рендеринг залишалися узгодженими між каналами.
Цілі
- Узгодженість: один етап розбору, кілька рендерерів.
- Безпечне розбиття на фрагменти: розділяйте текст перед рендерингом, щоб вбудоване форматування ніколи не ламалося між фрагментами.
- Відповідність каналу: зіставляйте той самий IR зі Slack mrkdwn, Telegram HTML і діапазонами стилів Signal без повторного розбору Markdown.
Конвеєр
- Розбір Markdown -> IR
- IR — це звичайний текст плюс діапазони стилів (жирний/курсив/закреслений/код/спойлер) і діапазони посилань.
- Зміщення задаються в кодових одиницях UTF-16, щоб діапазони стилів Signal узгоджувалися з його API.
- Таблиці розбираються лише тоді, коли канал увімкнув перетворення таблиць.
- Розбиття IR на фрагменти (спочатку форматування)
- Розбиття на фрагменти відбувається в тексті IR перед рендерингом.
- Вбудоване форматування не розривається між фрагментами; діапазони нарізаються для кожного фрагмента.
- Рендеринг для кожного каналу
- Slack: токени mrkdwn (жирний/курсив/закреслений/код), посилання як
<url|label>. - Telegram: теги HTML (
<b>,<i>,<s>,<code>,<pre><code>,<a href>). - Signal: звичайний текст + діапазони
text-style; посилання стаютьlabel (url), коли мітка відрізняється.
- Slack: токени mrkdwn (жирний/курсив/закреслений/код), посилання як
Приклад IR
Вхідний Markdown:
Hello **world** - see [docs](https://docs.openclaw.ai).
IR (схематично):
{
"text": "Hello world - see docs.",
"styles": [{ "start": 6, "end": 11, "style": "bold" }],
"links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]
}
Де це використовується
- Вихідні адаптери Slack, Telegram і Signal виконують рендеринг з IR.
- Інші канали (WhatsApp, iMessage, Microsoft Teams, Discord) досі використовують звичайний текст або власні правила форматування, із перетворенням таблиць Markdown, застосованим перед розбиттям на фрагменти, коли його ввімкнено.
Обробка таблиць
Таблиці Markdown не підтримуються узгоджено в усіх чат-клієнтах. Використовуйте
markdown.tables, щоб керувати перетворенням для кожного каналу (і для кожного облікового запису).
code: рендерить таблиці як блоки коду (типово для більшості каналів).bullets: перетворює кожен рядок на марковані пункти (типово для Signal + WhatsApp).off: вимикає розбір і перетворення таблиць; необроблений текст таблиці передається далі.
Ключі конфігурації:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
Правила розбиття на фрагменти
- Обмеження фрагментів надходять з адаптерів/конфігурації каналів і застосовуються до тексту IR.
- Огорожі коду зберігаються як єдиний блок із завершальним символом нового рядка, щоб канали рендерили їх правильно.
- Префікси списків і префікси блокових цитат є частиною тексту IR, тому розбиття на фрагменти не розриває їх посередині.
- Вбудовані стилі (жирний/курсив/закреслений/вбудований код/спойлер) ніколи не розриваються між фрагментами; рендерер повторно відкриває стилі всередині кожного фрагмента.
Якщо вам потрібно більше інформації про поведінку розбиття на фрагменти між каналами, див. Потокове передавання + розбиття на фрагменти.
Політика посилань
- Slack:
[label](url)-><url|label>; голі URL залишаються голими. Автопосилання вимкнено під час розбору, щоб уникнути подвійного створення посилань. - Telegram:
[label](url)-><a href="url">label</a>(режим розбору HTML). - Signal:
[label](url)->label (url), якщо мітка не збігається з URL.
Спойлери
Маркери спойлерів (||spoiler||) розбираються лише для Signal, де вони зіставляються з
діапазонами стилю SPOILER. Інші канали трактують їх як звичайний текст.
Як додати або оновити форматер каналу
- Розберіть один раз: використовуйте спільний помічник
markdownToIR(...)з параметрами, доречними для каналу (автопосилання, стиль заголовків, префікс блокової цитати). - Виконайте рендеринг: реалізуйте рендерер із
renderMarkdownWithMarkers(...)і мапою маркерів стилів (або діапазонами стилів Signal). - Розбийте на фрагменти: викличте
chunkMarkdownIR(...)перед рендерингом; рендеріть кожен фрагмент. - Під’єднайте адаптер: оновіть вихідний адаптер каналу, щоб він використовував новий засіб розбиття на фрагменти та рендерер.
- Протестуйте: додайте або оновіть тести форматування та тест вихідної доставки, якщо канал використовує розбиття на фрагменти.
Поширені підводні камені
- Токени Slack у кутових дужках (
<@U123>,<#C123>,<https://...>) мають зберігатися; безпечно екрануйте необроблений HTML. - HTML у Telegram вимагає екранування тексту поза тегами, щоб уникнути зламаної розмітки.
- Діапазони стилів Signal залежать від зміщень UTF-16; не використовуйте зміщення за кодовими точками.
- Зберігайте завершальні символи нового рядка для огороджених блоків коду, щоб закривальні маркери потрапляли на власний рядок.