Concept internals

Markdown の書式設定

OpenClaw は、チャンネル固有の出力をレンダリングする前に、送信 Markdown を共有の中間表現 (IR)へ変換します。IR はプレーンテキストとスタイル/リンクのスパンを保持するため、 1 回の解析ですべてのチャンネルに対応でき、チャンク分割によってスパン途中の 書式が分断されることもありません。

パイプライン

  1. Markdown を IR に解析markdownToIR)- プレーンテキストに加えて、スタイルスパン (太字、斜体、取り消し線、コード、コードブロック、スポイラー、引用、 見出し 1~6)とリンクスパンを生成します。オフセットは UTF-16 コード単位であるため、 Signal のスタイル範囲をその API と直接整合させられます。テーブルは、チャンネルが テーブルモードを有効にした場合にのみ解析されます。
  2. IR をチャンク分割chunkMarkdownIR / renderMarkdownIRChunksWithinLimit
    • 分割はレンダリング前の IR テキストに対して行われるため、インラインスタイルと リンクは境界をまたいで壊れるのではなく、チャンクごとに切り分けられます。
  3. チャンネルごとにレンダリングrenderMarkdownWithMarkers)- スタイルマーカーの マップにより、スパンをチャンネル固有のマークアップへ変換します。
チャンネル レンダラー 備考
Slack mrkdwn トークン(*太字*_斜体_`コード`、コードフェンス) リンクは <url|label> になります。二重リンクを避けるため、解析時は自動リンクを無効にします
Telegram HTML タグ(<b><i><s><code><pre><code><a href><tg-spoiler> richMessages が有効な場合は、リッチメッセージのテーブルと見出し(<h1><h6>)にも対応します
Signal プレーンテキスト + text-style 範囲 ラベルが URL と異なる場合、リンクは label (url) としてレンダリングされます
Discord、WhatsApp、iMessage、Microsoft Teams、その他のチャンネル プレーンテキスト IR ベースのスタイルはありません。Markdown テーブル変換は引き続き convertMarkdownTables により実行されます

IR の例

入力 Markdown: OC_I18N_900000 IR(概略): OC_I18N_900001

テーブルの処理

markdown.tables は、チャンネルごと、必要に応じてアカウントごとに、 チャンネルが Markdown テーブルを変換する方法を制御します。

モード 動作
code コードブロック内に整列済み ASCII テーブルとしてレンダリングします(フォールバックの既定値)
bullets 各行を label: value の箇条書きへ変換します
block トランスポートが対応している場合はネイティブテーブルを維持し、それ以外は code にフォールバックします
off テーブル解析を無効にし、生のテーブルテキストを変更せずに通過させます

チャンネル別 Plugin の既定値:Signal、WhatsApp、Matrix の既定値は bullets、Mattermost の既定値は off、Telegram の既定値は block です (アカウントで richMessages が有効でない限り、code として解決されます)。 明示的な Plugin の既定値がないチャンネルは、code にフォールバックします。 OC_I18N_900002

チャンク分割の規則

  • チャンク制限はチャンネルアダプター/設定から取得され、レンダリング済み出力ではなく IR テキストに適用されます。
  • フェンス付きコードブロックは、末尾の改行を含む 1 つのブロックとして維持されるため、 チャンネルは閉じフェンスを正しくレンダリングできます。
  • リストと引用の接頭辞は IR テキストの一部であるため、チャンク分割によって 接頭辞の途中で分断されることはありません。
  • インラインスタイルがチャンク間で分断されることはありません。レンダラーは、 次のチャンクの先頭で開いていたスタイルを再度開始します。

チャンネル間のチャンク境界と配信動作については、 ストリーミングとチャンク分割を参照してください。

リンクポリシー

  • Slack: [label](url) -> <url|label>。裸の URL はそのまま維持されます。
  • Telegram: [label](url) -> <a href="url">label</a>(HTML 解析モード)。
  • Signal: ラベルがすでに URL と一致している場合を除き、 [label](url) -> label (url) になります。

スポイラー

スポイラーマーカー(||spoiler||)は、Signal では SPOILER スタイル範囲に、Telegram では <tg-spoiler> に対応付けて解析されます。 その他のチャンネルでは、||...|| はプレーンテキストとして扱われます。

チャンネルフォーマッターの追加または更新

  1. 一度だけ解析:チャンネルに適したオプション (autolinkheadingStyleblockquotePrefixtableMode)を渡して、 markdownToIR(...) を使用します。
  2. レンダリングrenderMarkdownWithMarkers(...) とスタイルマーカーのマップ (または Signal のようなトランスポート向けのカスタムスタイル範囲ロジック)を使用します。
  3. チャンク分割:各チャンクをレンダリングする前に、chunkMarkdownIR(...) または renderMarkdownIRChunksWithinLimit(...) を使用します。
  4. アダプターを接続:送信処理経路から新しいチャンク分割処理とレンダラーを 呼び出すようにします。
  5. テスト:書式テストを行い、チャンネルがチャンク分割する場合は 送信配信テストも実施します。

よくある注意点

  • Slack の山括弧トークン(<@U123><#C123><https://...>)は、 エスケープ後も維持する必要があります。生の HTML は引き続き安全に エスケープする必要があります。
  • Telegram HTML では、マークアップの破損を避けるため、タグ外のテキストを エスケープする必要があります。
  • Signal のスタイル範囲では、コードポイントのオフセットではなく、 UTF-16 オフセットを使用します。
  • 閉じマーカーが独立した行に配置されるように、フェンス付きコードブロックの 末尾の改行を維持してください。

関連項目

Was this useful?
On this page

On this page