Concept internals

Форматирование Markdown

OpenClaw преобразует исходящий Markdown в общее промежуточное представление (IR) перед формированием вывода для конкретного канала. IR хранит обычный текст вместе с диапазонами стилей и ссылок, поэтому один этап синтаксического анализа обслуживает все каналы, а разбиение на фрагменты никогда не разделяет форматирование внутри диапазона.

Конвейер

  1. Преобразование Markdown в IR (markdownToIR) — обычный текст и диапазоны стилей (полужирный, курсив, зачёркнутый, код, блок кода, спойлер, цитата, заголовок 1-6), а также диапазоны ссылок. Смещения измеряются в кодовых единицах UTF-16, поэтому диапазоны стилей Signal напрямую соответствуют его API. Таблицы анализируются только тогда, когда канал включает один из режимов таблиц.
  2. Разбиение IR на фрагменты (chunkMarkdownIR / renderMarkdownIRChunksWithinLimit)
    • разбиение выполняется по тексту IR перед формированием вывода, поэтому встроенные стили и ссылки разделяются по фрагментам, а не обрываются на границе.
  3. Формирование вывода для каждого канала (renderMarkdownWithMarkers) — карта маркеров стилей преобразует диапазоны во встроенную разметку канала.
Канал Средство формирования вывода Примечания
Slack токены mrkdwn (*bold*, _italic_, `code`, ограждения кода) Ссылки преобразуются в <url|label>; автоматическое распознавание ссылок отключено при анализе во избежание дублирования ссылок
Telegram HTML-теги (<b>, <i>, <s>, <code>, <pre><code>, <a href>, <tg-spoiler>) Также поддерживает таблицы и заголовки форматированных сообщений (<h1>-<h6>), когда включён richMessages
Signal обычный текст + диапазоны text-style Ссылки формируются как label (url), когда подпись отличается от URL
Discord, WhatsApp, iMessage, Microsoft Teams и другие каналы обычный текст Стилизация на основе IR отсутствует; преобразование таблиц Markdown по-прежнему выполняется через convertMarkdownTables

Пример IR

Входной Markdown:

markdown
Привет, **мир**! См. [документацию](https://docs.openclaw.ai).

IR (схематично):

json
{  "text": "Привет, мир! См. документацию.",  "styles": [{ "start": 6, "end": 11, "style": "bold" }],  "links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]}

Обработка таблиц

markdown.tables определяет, как канал преобразует таблицы Markdown, отдельно для каждого канала и при необходимости для каждой учётной записи:

Режим Поведение
code Формировать выровненную ASCII-таблицу внутри блока кода (режим по умолчанию при откате)
bullets Преобразовывать каждую строку в пункты маркированного списка label: value
block Сохранять нативные таблицы, если транспорт их поддерживает; иначе переходить к code
off Отключить анализ таблиц; исходный текст таблицы передаётся без изменений

Значения плагинов по умолчанию для каналов: Signal, WhatsApp и Matrix по умолчанию используют bullets; Mattermost — off; Telegram — block (который разрешается в code, если для учётной записи не включён richMessages). Любой канал без явно заданного значения плагина по умолчанию переходит к code.

yaml
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) и Telegram (преобразуются в <tg-spoiler>). Другие каналы обрабатывают ||...|| как обычный текст.

Добавление или обновление средства форматирования канала

  1. Выполните анализ один раз с помощью markdownToIR(...), передав подходящие для канала параметры (autolink, headingStyle, blockquotePrefix, tableMode).
  2. Сформируйте вывод с помощью renderMarkdownWithMarkers(...) и карты маркеров стилей (либо пользовательской логики диапазонов стилей для таких транспортов, как Signal).
  3. Разбейте на фрагменты с помощью chunkMarkdownIR(...) или renderMarkdownIRChunksWithinLimit(...) перед формированием каждого фрагмента.
  4. Подключите адаптер, чтобы новый механизм разбиения и средство формирования вывода вызывались из пути отправки исходящих сообщений.
  5. Протестируйте с помощью тестов форматирования и теста исходящей доставки, если канал разбивает сообщения на фрагменты.

Распространённые ошибки

  • Токены Slack в угловых скобках (<@U123>, <#C123>, <https://...>) должны сохраняться при экранировании; необработанный HTML по-прежнему необходимо безопасно экранировать.
  • Для HTML в Telegram необходимо экранировать текст за пределами тегов, чтобы избежать повреждения разметки.
  • Диапазоны стилей Signal используют смещения UTF-16, а не смещения по кодовым точкам.
  • Сохраняйте завершающие переводы строк в ограждённых блоках кода, чтобы закрывающий маркер располагался на отдельной строке.

Связанные материалы

Was this useful?
On this page

On this page