Перейти до основного вмісту

Форматування Markdown

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

Цілі

  • Узгодженість: один крок парсингу, кілька рендерерів.
  • Безпечне розбиття на частини: розбивайте текст до рендерингу, щоб вбудоване форматування ніколи не ламалося між частинами.
  • Відповідність каналу: зіставляйте той самий IR зі Slack mrkdwn, Telegram HTML і діапазонами стилів Signal без повторного парсингу Markdown.

Конвеєр

  1. Парсинг Markdown -> IR
    • IR — це звичайний текст плюс діапазони стилів (bold/italic/strike/code/spoiler) і діапазони посилань.
    • Зміщення задаються в кодових одиницях UTF-16, щоб діапазони стилів Signal узгоджувалися з його API.
    • Таблиці парсяться лише тоді, коли канал вмикає перетворення таблиць.
  2. Розбиття IR на частини (спочатку формат)
    • Розбиття на частини відбувається над текстом IR до рендерингу.
    • Вбудоване форматування не розривається між частинами; діапазони обрізаються для кожної частини.
  3. Рендеринг для кожного каналу
    • Slack: токени mrkdwn (bold/italic/strike/code), посилання як <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, Microsoft Teams, Discord) досі використовують звичайний текст або власні правила форматування, із застосуванням перетворення таблиць Markdown перед розбиттям на частини, коли це ввімкнено.

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

Таблиці Markdown не підтримуються узгоджено в різних клієнтах чату. Використовуйте markdown.tables, щоб керувати перетворенням для кожного каналу (і для кожного облікового запису).
  • code: рендерити таблиці як блоки коду (типово для більшості каналів).
  • bullets: перетворювати кожен рядок на маркований список (типово для Signal + WhatsApp).
  • off: вимкнути парсинг і перетворення таблиць; сирий текст таблиці передається далі.
Ключі конфігурації:
channels:
  discord:
    markdown:
      tables: code
    accounts:
      work:
        markdown:
          tables: off

Правила розбиття на частини

  • Межі частин беруться з адаптерів/конфігурації каналу й застосовуються до тексту IR.
  • Огороджені блоки коду зберігаються як єдиний блок із кінцевим символом нового рядка, щоб канали коректно їх рендерили.
  • Префікси списків і blockquote є частиною тексту IR, тому розбиття на частини не відбувається посеред префікса.
  • Вбудовані стилі (bold/italic/strike/inline-code/spoiler) ніколи не розриваються між частинами; рендерер знову відкриває стилі всередині кожної частини.
Якщо вам потрібно більше інформації про поведінку розбиття на частини в різних каналах, див. Streaming + chunking.

Політика посилань

  • Slack: [label](url) -> <url|label>; прості URL залишаються як є. Autolink вимикається під час парсингу, щоб уникнути подвійного створення посилань.
  • Telegram: [label](url) -> <a href="url">label</a> (режим парсингу HTML).
  • Signal: [label](url) -> label (url), якщо мітка не збігається з URL.

Спойлери

Маркери спойлерів (||spoiler||) парсяться лише для Signal, де вони зіставляються з діапазонами стилю SPOILER. В інших каналах вони трактуються як звичайний текст.

Як додати або оновити форматувач каналу

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

Типові пастки

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