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

パイプライン

  1. Markdown を IR に解析 (markdownToIR) - プレーンテキストに加えてスタイルスパン (太字、斜体、取り消し線、コード、コードブロック、スポイラー、引用、 見出し 1-6) とリンクスパン。オフセットは UTF-16 コード単位なので、Signal のスタイル 範囲はその API と直接一致します。テーブルは、チャネルがテーブルモードを 選択した場合にのみ解析されます。
  2. IR をチャンク化 (chunkMarkdownIR / renderMarkdownIRChunksWithinLimit)
    • 分割はレンダリング前の IR テキスト上で行われるため、インラインスタイルと リンクは境界をまたいで壊れるのではなく、チャンクごとに切り出されます。
  3. チャネルごとにレンダリング (renderMarkdownWithMarkers) - スタイルマーカーマップが スパンをチャネルのネイティブマークアップに変換します。
チャネルレンダラー注記
Slackmrkdwn トークン (*bold*, _italic_, `code`, コードフェンス)リンクは <url|label> になります。二重リンク化を避けるため、解析時は autolink を無効化
TelegramHTML タグ (<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. チャネルに適したオプション (autolink, headingStyle, blockquotePrefix, tableMode) を渡して、 markdownToIR(...)1 回だけ解析します。
  2. renderMarkdownWithMarkers(...) とスタイルマーカーマップ (または Signal のようなトランスポート向けのカスタムスタイル範囲ロジック) で レンダリングします。
  3. 各チャンクをレンダリングする前に、chunkMarkdownIR(...) または renderMarkdownIRChunksWithinLimit(...)チャンク化します。
  4. 送信パスから新しいチャンク化処理とレンダラーを呼び出すように、 アダプターを接続します。
  5. チャネルがチャンク化する場合は、形式テストに加えて送信配信テストで テストします。

よくある落とし穴

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

関連

Streaming and chunking

送信ストリーミング動作、チャンク境界、チャネル固有の配信。

System prompt

注入されたワークスペースファイルを含め、会話の前にモデルが見る内容。