> ## Documentation Index
> Fetch the complete documentation index at: https://openclaw.veiseule.ai/llms.txt
> Use this file to discover all available pages before exploring further.

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

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

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

## Цели

* **Согласованность:** один шаг парсинга, несколько рендереров.
* **Безопасное разбиение на чанки:** разделение текста до рендеринга, чтобы
  встроенное форматирование никогда не разрывалось между чанками.
* **Соответствие каналу:** сопоставление одного и того же IR со Slack mrkdwn,
  Telegram HTML и диапазонами стилей Signal без повторного парсинга Markdown.

## Трубопровод

1. **Парсинг Markdown -> IR**
   * IR — это обычный текст плюс диапазоны стилей (жирный/курсив/зачёркнутый/код/спойлер) и диапазоны ссылок.
   * Смещения задаются в кодовых единицах UTF-16, чтобы диапазоны стилей Signal
     совпадали с его API.
   * Таблицы парсятся только тогда, когда канал явно включает преобразование таблиц.
2. **Разбиение IR на чанки (сначала формат)**
   * Разбиение на чанки выполняется по тексту IR до рендеринга.
   * Встроенное форматирование не разрывается между чанками; диапазоны нарезаются по чанкам.
3. **Рендеринг по каналам**
   * **Slack:** токены mrkdwn (жирный/курсив/зачёркнутый/код), ссылки как `<url|label>`.
   * **Telegram:** HTML-теги (`<b>`, `<i>`, `<s>`, `<code>`, `<pre><code>`, `<a href>`).
   * **Signal:** обычный текст + диапазоны `text-style`; ссылки становятся `label (url)`, если подпись отличается.

## Пример IR

Входной Markdown:

```markdown theme={"theme":{"light":"min-light","dark":"min-dark"}}
Hello **world** — see [docs](https://docs.openclaw.ai).
```

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

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "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`: отключить парсинг и преобразование таблиц; «сырой» текст таблицы проходит без изменений.

Ключи конфига:

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
channels:
  discord:
    markdown:
      tables: code
    accounts:
      work:
        markdown:
          tables: off
```

## Правила чанков

* Лимиты чанков задаются адаптерами каналов/конфигом и применяются к тексту IR.
* Кодовые блоки (fenced) сохраняются как единый блок с завершающим переводом строки,
  чтобы каналы корректно их рендерили.
* Префиксы списков и цитат являются частью текста IR, поэтому разбиение не
  происходит посередине префикса.
* Встроенные стили (жирный/курсив/зачёркнутый/встроенный код/спойлер) никогда не
  разрываются между чанками; рендерер заново открывает стили внутри каждого чанка.

Если вам нужно больше деталей о поведении разбиения на чанки между каналами, см. [Streaming + chunking](/concepts/streaming).

## Политика ссылок

* **Slack:** `[label](url)` -> `<url|label>`; «голые» URL остаются без изменений. Автоссылки отключены на этапе парсинга, чтобы избежать двойного линкования.
* **Telegram:** `[label](url)` -> `<a href="url">label</a>` (режим HTML-парсинга).
* **Signal:** `[label](url)` -> `label (url)`, если подпись не совпадает с URL.

## Спойлеры

Маркеры спойлеров (`||spoiler||`) парсятся только для Signal, где они сопоставляются
с диапазонами стиля SPOILER. Другие каналы трактуют их как обычный текст.

## Как добавить или обновить форматтер канала

1. **Парсить один раз:** используйте общий хелпер `markdownToIR(...)` с параметрами,
   подходящими для канала (autolink, стиль заголовков, префикс цитат).
2. **Рендерить:** реализуйте рендерер с `renderMarkdownWithMarkers(...)` и
   картой маркеров стилей (или диапазонами стилей Signal).
3. **Разбить на чанки:** вызовите `chunkMarkdownIR(...)` до рендеринга; отрендерьте каждый чанк.
4. **Подключить адаптер:** обновите исходящий адаптер канала, чтобы он использовал
   новый чанкёр и рендерер.
5. **Тестировать:** добавьте или обновите тесты форматирования и тест доставки,
   если канал использует разбиение на чанки.

## Распространенные горы

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