Форматирование 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), если подпись отличается.
Пример 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, MS Teams, Discord) по-прежнему используют обычный текст или собственные правила форматирования; при включении преобразование таблиц Markdown применяется до разбиения на чанки.
Обработка таблиц¶
Таблицы Markdown поддерживаются чат-клиентами непоследовательно. Используйте
markdown.tables для управления преобразованием по каналам (и по аккаунтам).
code: рендерить таблицы как блоки кода (по умолчанию для большинства каналов).bullets: преобразовывать каждую строку в маркеры списка (по умолчанию для Signal + WhatsApp).off: отключить парсинг и преобразование таблиц; «сырой» текст таблицы проходит без изменений.
Ключи конфига:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
Правила чанков¶
- Лимиты чанков задаются адаптерами каналов/конфигом и применяются к тексту IR.
- Кодовые блоки (fenced) сохраняются как единый блок с завершающим переводом строки, чтобы каналы корректно их рендерили.
- Префиксы списков и цитат являются частью текста IR, поэтому разбиение не происходит посередине префикса.
- Встроенные стили (жирный/курсив/зачёркнутый/встроенный код/спойлер) никогда не разрываются между чанками; рендерер заново открывает стили внутри каждого чанка.
Если вам нужно больше деталей о поведении разбиения на чанки между каналами, см. Streaming + chunking.
Политика ссылок¶
- 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(...)с параметрами, подходящими для канала (autolink, стиль заголовков, префикс цитат). - Рендерить: реализуйте рендерер с
renderMarkdownWithMarkers(...)и картой маркеров стилей (или диапазонами стилей Signal). - Разбить на чанки: вызовите
chunkMarkdownIR(...)до рендеринга; отрендерьте каждый чанк. - Подключить адаптер: обновите исходящий адаптер канала, чтобы он использовал новый чанкёр и рендерер.
- Тестировать: добавьте или обновите тесты форматирования и тест доставки, если канал использует разбиение на чанки.
Распространенные горы¶
- Угловые токены Slack (
<@U123>,<#C123>,<https://...>) необходимо сохранять; безопасно экранируйте «сырой» HTML. - Telegram HTML требует экранирования текста вне тегов, чтобы избежать поломки разметки.
- Диапазоны стилей Signal зависят от смещений UTF-16; не используйте смещения по кодовым точкам.
- Сохраняйте завершающие переводы строк для ограждённых блоков кода, чтобы закрывающие маркеры располагались на собственной строке.