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

# Форматування 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, Microsoft Teams, Discord) все ще використовують звичайний текст або
  власні правила форматування, із перетворенням таблиць Markdown перед
  розбиттям на фрагменти, коли це ввімкнено.

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

Таблиці Markdown не підтримуються узгоджено в усіх чат-клієнтах. Використовуйте
`markdown.tables`, щоб керувати перетворенням для кожного каналу (і кожного облікового запису).

* `code`: рендерити таблиці як блоки коду (типово для більшості каналів).
* `bullets`: перетворювати кожен рядок на марковані пункти (типово для Matrix, Signal і WhatsApp).
* `off`: вимкнути парсинг і перетворення таблиць; необроблений текст таблиці проходить без змін.

Ключі конфігурації:

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

## Правила розбиття на фрагменти

* Обмеження фрагментів надходять з адаптерів/конфігурації каналу й застосовуються до тексту IR.
* Блоки коду зберігаються як єдиний блок із кінцевим символом нового рядка, щоб канали
  рендерили їх коректно.
* Префікси списків і префікси блокових цитат є частиною тексту IR, тому розбиття
  не розділяє їх посередині префікса.
* Вбудовані стилі (жирний/курсив/закреслений/вбудований код/спойлер) ніколи не розриваються між
  фрагментами; рендерер повторно відкриває стилі всередині кожного фрагмента.

Якщо потрібно більше інформації про поведінку розбиття на фрагменти між каналами, див.
[Стримінг + розбиття на фрагменти](/uk/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(...)` з відповідними для каналу
   параметрами (автопосилання, стиль заголовків, префікс блокової цитати).
2. **Рендерити:** реалізуйте рендерер із `renderMarkdownWithMarkers(...)` і
   мапою маркерів стилів (або діапазонами стилів Signal).
3. **Розбити на фрагменти:** викличте `chunkMarkdownIR(...)` перед рендерингом; рендеріть кожен фрагмент.
4. **Під’єднати адаптер:** оновіть вихідний адаптер каналу, щоб він використовував новий механізм розбиття
   і рендерер.
5. **Протестувати:** додайте або оновіть тести форматування й тест вихідної доставки, якщо
   канал використовує розбиття на фрагменти.

## Поширені помилки

* Токени Slack у кутових дужках (`<@U123>`, `<#C123>`, `<https://...>`) потрібно
  зберігати; безпечно екрануйте необроблений HTML.
* Telegram HTML вимагає екранування тексту поза тегами, щоб уникнути зламаної розмітки.
* Діапазони стилів Signal залежать від зміщень UTF-16; не використовуйте зміщення за кодовими точками.
* Зберігайте кінцеві символи нового рядка для блоків коду з огорожами, щоб закривальні маркери були
  на окремому рядку.

## Пов’язане

<CardGroup cols={2}>
  <Card title="Стримінг і розбиття на фрагменти" href="/uk/concepts/streaming" icon="bars-staggered">
    Поведінка вихідного стримінгу, межі фрагментів і канально-специфічна доставка.
  </Card>

  <Card title="Системний prompt" href="/uk/concepts/system-prompt" icon="message-lines">
    Що модель бачить перед розмовою, включно з впровадженими файлами робочої області.
  </Card>
</CardGroup>
