Skip to content

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 token(粗体/斜体/删除线/代码),链接为 <url|label>
    • Telegram:HTML 标签(<b><i><s><code><pre><code><a href>)。
    • Signal:纯文本 + text-style 范围;标签与 URL 不同时,链接渲染为 label (url)

IR 示例

输入 Markdown:

markdown
Hello **world** — see [docs](https://docs.openclaw.ai).

IR(示意):

json
{
  "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:禁用表格解析和转换,原始表格文本直接透传。

配置示例:

yaml
channels:
  discord:
    markdown:
      tables: code
    accounts:
      work:
        markdown:
          tables: off

分块规则

  • 分块上限来自渠道适配器/配置,应用于 IR 文本。
  • 代码围栏作为整体保留,末尾追加换行,确保渠道正确渲染。
  • 列表前缀和引用前缀是 IR 文本的一部分,分块不会从前缀中间断开。
  • 内联样式(粗体/斜体/删除线/内联代码/剧透)永远不会跨块断裂;渲染器会在每个块内重新打开样式。

关于跨渠道分块行为的更多内容,见 Streaming + chunking

链接策略

  • 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 的角括号 token(<@U123><#C123><https://...>)必须原样保留;对原始 HTML 进行安全转义。
  • Telegram HTML 要求对标签外的文本进行转义,避免标记损坏。
  • Signal 样式范围依赖 UTF-16 偏移量,不要使用代码点偏移。
  • 保留代码围栏的末尾换行,确保关闭标记独占一行。