Форматирование Markdown
OpenClaw форматирует исходящий Markdown, преобразуя его в общее промежуточное представление (IR) перед рендерингом специфичного для канала вывода. IR сохраняет исходный текст неизменным, но содержит информацию о стилях и ссылках, что позволяет чанкингу и рендерингу оставаться согласованными между каналами.
Цели
- Согласованность: один этап парсинга, несколько рендереров.
- Безопасный чанкинг: разделение текста перед рендерингом, чтобы inline-форматирование никогда не разрывалось между чанками.
- Адаптация к каналу: преобразование одного и того же IR в Slack mrkdwn, Telegram HTML и диапазоны стилей Signal без повторного парсинга Markdown.
Конвейер обработки
- Парсинг Markdown -> IR
- IR — это обычный текст плюс диапазоны стилей (жирный/курсив/зачеркивание/код/спойлер) и диапазоны ссылок.
- Смещения указаны в единицах кода UTF-16, чтобы диапазоны стилей Signal соответствовали его API.
- Таблицы парсятся только если канал явно включает их конвертацию.
- Чанкинг IR (форматирование первично)
- Чанкинг происходит на тексте IR перед рендерингом.
- Inline-форматирование не разрывается между чанками; диапазоны стилей разделяются для каждого чанка.
- Рендеринг для каждого канала
- Slack: токены mrkdwn (жирный/курсив/зачеркивание/код), ссылки как
<url|label>. - Telegram: HTML-теги (
<b>,<i>,<s>,<code>,<pre><code>,<a href>). - Signal: обычный текст + диапазоны
text-style; ссылки преобразуются вlabel (url), если метка отличается от 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, MS Teams, Discord) по-прежнему используют обычный текст или свои собственные правила форматирования, с конвертацией таблиц Markdown, применяемой перед чанкингом, если она включена.
Обработка таблиц
Таблицы Markdown не поддерживаются единообразно во всех чат-клиентах. Используйте markdown.tables для управления конвертацией для каждого канала (и для каждого аккаунта).
code: рендерить таблицы как блоки кода (по умолчанию для большинства каналов).bullets: преобразовывать каждую строку в маркированный список (по умолчанию для Signal и WhatsApp).off: отключить парсинг и конвертацию таблиц; исходный текст таблицы передается как есть.
Ключи конфигурации:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
Правила чанкинга
- Лимиты чанков задаются адаптерами каналов/конфигурацией и применяются к тексту IR.
- Блоки кода (code fences) сохраняются как единый блок с завершающим переводом строки, чтобы каналы корректно их рендерили.
- Префиксы списков и цитат являются частью текста IR, поэтому чанкинг не разрывает их посередине.
- Inline-стили (жирный/курсив/зачеркивание/inline-код/спойлер) никогда не разрываются между чанками; рендерер заново открывает стили внутри каждого чанка.
Если вам нужно больше информации о поведении чанкинга в разных каналах, см. Стриминг + чанкинг.
Политика ссылок
- 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; не используйте смещения в кодовых точках.
- Сохраняйте завершающие переводы строк для блоков кода (fenced code blocks), чтобы закрывающие маркеры оставались на отдельной строке.