Markdown 格式化
OpenClaw 透過先將對外的 Markdown 轉換為共用的中介表示(IR),再渲染成各通道專屬的輸出格式。IR 在保留原始文字內容的同時,攜帶樣式/連結的跨度資訊,讓分塊與渲染能在各通道間保持一致。 The IR keeps the source text intact while carrying style/link spans so chunking and rendering can stay consistent across channels. The IR keeps the source text intact while carrying style/link spans so chunking and rendering can stay consistent across channels.目標
- 一致性: 一次解析,多個渲染器。
- 安全分塊: 在渲染之前先切分文字,確保行內格式不會跨分塊被破壞。
- 通道適配: 將相同的 IR 對應到 Slack mrkdwn、Telegram HTML 與 Signal 樣式範圍,而不需重新解析 Markdown。
管線流程
- 解析 Markdown -> IR
- IR 是純文字加上樣式跨度(粗體/斜體/刪除線/程式碼/劇透)與連結跨度。
- 位移量使用 UTF-16 程式碼單位,確保 Signal 樣式範圍能與其 API 對齊。
- Tables are parsed only when a channel opts into table conversion.
- 分塊 IR(先格式化)
- 分塊發生在渲染之前,直接作用於 IR 文字。
- 行內格式不會跨分塊切割;跨度會依分塊被裁切。
- 依通道渲染
- Slack: mrkdwn 標記(粗體/斜體/刪除線/程式碼),連結渲染為
<url|label>。 - Telegram: HTML 標籤(
<b>、<i>、<s>、<code>、<pre><code>、<a href>)。 - Signal: 純文字 +
text-style範圍;當標籤與 URL 不同時,連結會變成label (url)。
- Slack: mrkdwn 標記(粗體/斜體/刪除線/程式碼),連結渲染為
IR 範例
輸入的 Markdown:使用位置
- Slack、Telegram 與 Signal 的對外適配器皆從 IR 進行渲染。
- 其他通道(WhatsApp、iMessage、MS Teams、Discord)仍使用純文字或各自的格式規則;當啟用時,Markdown 表格轉換會在分塊之前套用。
Table handling
Markdown 表格在各聊天客戶端中的支援並不一致。請使用markdown.tables 來控制各通道(以及各帳戶)的轉換行為。 Use
markdown.tables to control conversion per channel (and per account). Use
markdown.tables to control conversion per channel (and per account).
code: render tables as code blocks (default for most channels).bullets:將每一列轉換為項目符號清單(Signal + WhatsApp 的預設)。off:停用表格解析與轉換;原始表格文字直接傳遞。
分塊規則
- 分塊上限來自通道適配器/設定,並套用於 IR 文字。
- Code fences are preserved as a single block with a trailing newline so channels render them correctly.
- 清單前綴與引用區塊前綴屬於 IR 文字的一部分,因此分塊不會在前綴中途切割。
- 行內樣式(粗體/斜體/刪除線/行內程式碼/劇透)永遠不會跨分塊切割;渲染器會在每個分塊內重新開啟樣式。
連結政策
- Slack:
[label](url)-><url|label>;裸露 URL 保持原樣。解析時會停用自動連結,以避免重複建立連結。 Autolink is disabled during parse to avoid double-linking. Autolink is disabled during parse to avoid double-linking. - Telegram:
[label](url)-><a href="url">label</a>(HTML 解析模式)。 - Signal:
[label](url)->label (url),除非標籤與 URL 相同。
劇透
Spoiler markers (||spoiler||) are parsed only for Signal, where they map to
SPOILER style ranges. Other channels treat them as plain text.
如何新增或更新通道格式化器
- 只解析一次: 使用共用的
markdownToIR(...)輔助函式,並設定符合通道需求的選項(自動連結、標題樣式、引用區塊前綴)。 - 渲染: 以
renderMarkdownWithMarkers(...)實作渲染器,並提供樣式標記對應(或 Signal 的樣式範圍)。 - 分塊: 在渲染之前呼叫
chunkMarkdownIR(...);逐一渲染每個分塊。 - 串接適配器: 更新通道的對外適配器,使用新的分塊器與渲染器。
- 測試: 新增或更新格式測試;若該通道使用分塊,請加入對外傳送測試。
常見陷阱
- Slack 的角括號標記(
<@U123>、<#C123>、<https://...>)必須被保留;請安全地跳脫原始 HTML。 - Telegram 的 HTML 需要對標籤外的文字進行跳脫,以避免標記損壞。
- Signal 的樣式範圍依賴 UTF-16 位移量;請勿使用程式碼點位移。
- Preserve trailing newlines for fenced code blocks so closing markers land on their own line.