このページの内容
このページの内容
Plugin internals
メッセージ表示
メッセージプレゼンテーションは、リッチな送信チャット UI のための OpenClaw 共通コントラクトです。 これにより、エージェント、CLI コマンド、承認フロー、plugins はメッセージの意図を一度記述するだけで済み、各チャネル plugin が可能な限り最適なネイティブ形式でレンダリングします。
テキストセクション、小さなコンテキスト/フッターテキスト、区切り線、チャート、テーブル、ボタン、選択メニュー、カードのタイトル/トーンなど、移植可能なメッセージ UI にはプレゼンテーションを使用します。
Discord components、Slack
blocks、Telegram buttons、Teams card、Feishu card など、プロバイダー固有の新しいフィールドを共有メッセージツールに追加しないでください。これらはチャネル plugin が所有するレンダラー出力です。
コントラクト
Plugin の作成者は、次の場所から公開コントラクトをインポートします。
形式:
ボタンのセマンティクス:
action.type: "command"は、コアのコマンドパスを通じてネイティブのスラッシュコマンドを実行します。 組み込みのコマンドボタンとメニューにはこれを使用します。action.type: "callback"は、チャネルのインタラクションパスを通じて不透明な plugin データを伝達します。 チャネル plugins は、コールバックデータをスラッシュコマンドとして再解釈してはなりません。action.type: "approval"は、単一の永続的なオペレーター承認、その明示的なexecまたはpluginの種別、および要求された判断を識別します。チャネル plugins は、そのアクションをトランスポート専用のコールバックにエンコードし、承認サービスを通じて解決します。/approveコマンドテキストを解析したり、ID から種別を推測したりしてはなりません。action.type: "question"は、実行時に作成された有効なask_user質問に対する単一の選択肢を識別します。approvalと同様、これは OpenClaw ランタイムアクションです。エージェントと plugins は質問 ID を生成してはなりません。Telegram、Discord、Slack はこれをトランスポート専用のネイティブコールバックにマッピングし、Gateway を通じて選択を解決します。質問が回答済み、期限切れ、またはキャンセル済みになると、これらのチャネルは配信済みメッセージを編集し、そのアクションを削除して、最終ステータスを追記します。WhatsApp、Signal、iMessage は、最大 4 つの単一選択肢を1️⃣から4️⃣のリアクションとしてレンダリングします。その他の形式の質問はラベルテキストにフォールバックし、ユーザーはプレーンテキストの返信で回答できます。action.type: "url"は通常のリンクを開きます。action.type: "web-app"はチャネルネイティブの Web アプリを起動します。URL ベースのアプリにはurlを、起動メカニズムをチャネルが所有する OpenClaw ホスト型ウィジェットにはwidgetIdを設定します。少なくとも一方が必要です。両方が存在する場合、チャネルはネイティブのホスト型ウィジェット起動を優先し、そのメカニズムを使用できない場所では URL を使用できます。valueは、従来の不透明なコールバック値です。新しいコントロールではactionを使用し、チャネル plugins がテキストから推測せずにコマンドとコールバックをマッピングできるようにしてください。url、webApp、web_appは、非推奨の境界入力として引き続き受け入れられます。 ノーマライザーはこれらのフィールドを保持するため、レンダラーはリリース済みの従来のセマンティクスと明示的に型付けされたアクションを区別できます。新しい生成元ではactionを使用してください。labelは必須であり、テキストフォールバックでも使用されます。styleは参考情報です。レンダラーは未対応のスタイルを安全なデフォルトにマッピングし、送信を失敗させないようにする必要があります。priorityは任意です。チャネルがアクション数の上限を通知しており、コントロールを削除する必要がある場合、コアは優先度の高いボタンを先に保持し、優先度が同じボタン間では元の順序を維持します。すべてのコントロールが収まる場合、作成時の順序が維持されます。disabledは任意です。チャネルはsupportsDisabledで明示的に対応を宣言する必要があります。それ以外の場合、コアは無効化されたコントロールを非インタラクティブなフォールバックテキストに変換します。無効化されたボタンは、commandアクションを持つ場合でも、フォールバックテキストでは常にラベルのみでレンダリングされます。reusableは任意です。再利用可能なネイティブコールバックに対応するチャネルは、インタラクションが成功した後もアクションを利用可能な状態に保つことができます。更新、調査、詳細表示など、反復可能または冪等なアクションに使用してください。通常の一度限りの承認や破壊的アクションでは設定しないでください。
選択のセマンティクス:
options[].actionはcommandまたはcallbackのみを受け入れます。承認アクションとリンクアクションはボタン専用です。options[].valueは、従来の選択済みアプリケーション値です。placeholderは参考情報であり、ネイティブの選択機能に対応していないチャネルでは無視される場合があります。- チャネルが選択機能に対応していない場合、フォールバックテキストにラベルの一覧が表示されます。
チャートのセマンティクス:
pieには正のセグメント値が必要です。bar、area、lineは、単一の順序付きcategories配列を使用します。各系列は、カテゴリごとに有限値を同じ順序でちょうど 1 つ指定します。- カテゴリラベルと系列名は一意でなければなりません。無効または不完全なチャートブロックは、データを暗黙に変更するのではなく、正規化時に削除されます。
- ネイティブのチャートレンダリングは、
presentationCapabilities.chartsを通じて明示的に有効化します。 その他のチャネルには、チャートタイトル、軸、カテゴリ、系列、値が決定論的なテキストとして提供されます。これはアクセシビリティ用のフォールバックでもあります。
テーブルのセマンティクス:
-
captionは必須の短い見出しです。headersには、一意で空でない列ラベルを少なくとも 1 つ含める必要があります。 -
rowsには少なくとも 1 行を含める必要があります。各行はヘッダーごとにちょうど 1 つのセルを持ち、各セルは空でない文字列または有限数でなければなりません。 -
rowHeaderColumnIndexは、ネイティブレンダラーがセルを行ヘッダーとして公開する列を識別する、任意のゼロベースインデックスです。 -
テーブルの正規化は不可分に行われます。キャプション、ヘッダー、行幅、セル、または行ヘッダーインデックスが無効な場合、データを切り詰めたり修復したりせず、テーブルブロック全体が削除されます。
-
ネイティブのテーブルレンダリングは、
presentationCapabilities.tablesを通じて明示的に有効化します。 その他のチャネルには、キャプションとすべての行が決定論的な線形テキストとして提供され、内部の空白はまとめられます。text
独立した report 判別子はありません。title、
tone、text、context、chart、table、およびアクションブロックからレポートを構成します。これにより、各ブロックを独立してレンダリングでき、レポート全体にも同じ決定論的なテキストフォールバックが提供されます。
生成例
シンプルなカード:
URL のみのリンクボタン:
Telegram Mini App ボタン:
選択メニュー:
チャート:
テーブルレポート:
CLI 送信:
ピン留め配信:
明示的な JSON を使用したピン留め配信:
レンダラーのコントラクト
チャンネル Plugin は、送信アダプターでレンダリング対応を宣言します:
ケイパビリティの真偽値は、レンダラーがインタラクティブにできるものを示します。オプションの
limits は、レンダラーを呼び出す前にコアが適合させられる汎用エンベロープを示します:
コアはレンダリング前にセマンティックコントロールへ汎用制限を適用します。ネイティブブロック数、カードサイズ、URL 制限、および汎用コントラクトでは表現できないプロバイダー固有の仕様に対する最終的な検証と切り詰めは、引き続きレンダラーが担当します。制限によってブロックからすべてのコントロールが削除された場合、配信メッセージに表示可能なフォールバックが残るよう、コアはラベルを非インタラクティブなコンテキストテキストとして保持します。
コアのレンダリングフロー
CLI と標準メッセージアクションが使用する正規の送信パスでは、コアは次の処理を行います:
- プレゼンテーションペイロードを正規化します。
- 対象チャンネルの送信アダプターを解決します。
presentationCapabilitiesを読み取ります。- アダプターが宣言している場合、アクション数、ラベル長、選択肢数などの汎用ケイパビリティ制限を適用します。アダプターがそれぞれ
charts: trueまたはtables: trueを明示的に宣言していない限り、グラフブロックとテーブルブロックは決定論的なテキストになります。 - アダプターがペイロードをレンダリングできる場合、
renderPresentationを呼び出します。 - アダプターが存在しない、またはレンダリングできない場合は、保守的なテキストへフォールバックします。
- 生成されたペイロードを通常のチャンネル配信パスで送信します。
- 最初のメッセージが正常に送信された後、
delivery.pinなどの配信メタデータを適用します。
ReplyPayloadを直接使用するチャンネルローカルの返信またはプレビュー経路は、その正規パスに入るか、ペイロードをプレーンテキスト/メディアへ投影する前に同じプレゼンテーションフォールバックを実体化する必要があります。
プロデューサーがチャンネルに依存しない状態を維持できるよう、フォールバック動作はコアが担当します。ネイティブレンダリングとインタラクション処理はチャンネル Plugin が担当します。
デグラデーションルール
プレゼンテーションは、機能が制限されたチャンネルにも安全に送信できる必要があります。
フォールバックテキストには次のものが含まれます:
titleを最初の行として表示textブロックを通常の段落として表示contextブロックを簡潔なコンテキスト行として表示dividerブロックを視覚的な区切りとして表示- リンクボタンの URL を含むボタンラベル
- 選択肢のラベル
- グラフのタイトル、種類、軸、カテゴリ、系列、値
- テーブルのキャプション、ヘッダー、すべての行の値
ボタン値のフォールバック表示
チャンネルがインタラクティブコントロールをレンダリングできない場合、ボタンと選択値はプレーンテキストへフォールバックします。このフォールバック動作は、不透明なコールバックデータを非公開に保ちながら、使いやすさを維持します:
command型のアクションはlabel: `command`としてレンダリングされるため、ユーザーはコマンドをコピーし、チャンネル入力で手動実行できます。callback型のアクションと従来のvalueフィールドは、ラベルのみでレンダリングされます。不透明なコールバック値はフォールバックテキストに公開されません。approval型のアクションは、ラベルのみでレンダリングされます。承認 ID と判断結果はトランスポートデータであり、汎用スカラーヘルパーやフォールバックテキストを通じて公開されません。urlアクション、URL を持つweb-appアクション、および非推奨のurl/webApp/web_app入力では、URL がユーザー向けであるため、ボタンラベルとともに URL テキストがレンダリングされます。ホスト型ウィジェット専用のアクションは、ネイティブのウィジェット起動機能がないチャンネルではラベルのみでレンダリングされます。- 選択肢はラベルのみでレンダリングされます。基になる選択値はフォールバックテキストに公開されません。
フォールバック UI に手動コマンドの案内を追加するチャンネルアダプター(Feishu のドキュメントコメント手順など)は、フォールバックレンダラーが使用するものと同じプレゼンテーションブロックからコマンドの存在チェックを導出する必要があります。これにより、手動コマンドが実際に表示される場合にのみ案内テキストが表示されます。
未対応のネイティブコントロールは、送信全体を失敗させるのではなくデグレードする必要があります。 例:
- インラインボタンが無効な Telegram は、テキストフォールバックを送信します。
- 選択機能に対応していないチャンネルでは、選択肢をテキストとして一覧表示します。
- ネイティブのグラフ機能に対応していないチャンネルでは、グラフデータをテキストとして一覧表示します。
- ネイティブのテーブル機能に対応していないチャンネルでは、すべてのテーブル行をテキストとして一覧表示します。
- URL 専用ボタンは、ネイティブリンクボタンまたはフォールバック URL 行のいずれかになります。
- オプションのピン留めが失敗しても、配信済みメッセージは失敗扱いになりません。
主な例外は delivery.pin.required: true です。ピン留めが必須として要求され、チャンネルが送信済みメッセージをピン留めできない場合、配信は失敗を報告します。
プロバイダーのマッピング
現在バンドルされているレンダラー:
| チャンネル | ネイティブのレンダリング先 | 注記 |
|---|---|---|
| Discord | コンポーネントとコンポーネントコンテナ | 既存のプロバイダーネイティブなペイロードプロデューサー向けに従来の channelData.discord.components を維持しますが、新しい共有送信では presentation を使用する必要があります。 |
| Feishu | インタラクティブカード | カードヘッダーでは title を使用できます。本文ではそのタイトルの重複を避けます。 |
| Matrix | テキストフォールバックと構造化イベントフィールド | ボタン/選択は対応済みとして宣言されますが、現在はすべてのブロックがネイティブのインタラクティブウィジェットではなく、com.openclaw.presentation イベントフィールドに格納された renderMessagePresentationFallbackText 出力としてレンダリングされます。 |
| Mattermost | テキストとインタラクティブプロパティ | 選択と区切りには対応していません。これらのブロックはテキストにデグレードします。 |
| Microsoft Teams | Adaptive Cards | 両方が指定されている場合、プレーンな message テキストがカードとともに含まれます。選択、スタイル、無効状態には対応していません。 |
| Slack | Block Kit | chart をネイティブの data_visualization として、table をネイティブの data_table としてレンダリングします。従来の channelData.slack.blocks を維持しますが、新しい共有送信では presentation を使用する必要があります。 |
| Telegram | テキストとインラインキーボード | ボタン/選択には、対象サーフェスのインラインボタン機能が必要です。それ以外の場合はテキストフォールバックが使用されます。 |
| プレーンチャンネル | テキストフォールバック | レンダラーのないチャンネルでも、読みやすい出力が得られます。 |
プロバイダーネイティブなペイロードとの互換性は、既存の返信プロデューサー向けの移行上の便宜です。新しい共有ネイティブフィールドを追加する理由にはなりません。
プレゼンテーションと InteractiveReply の比較
InteractiveReply は、承認およびインタラクションヘルパーで使用される旧来の内部サブセットです。次のものに対応します:
- テキスト
- ボタン
- 選択
MessagePresentation は、正規の共有送信コントラクトです。次のものを追加します:
- タイトル
- トーン
- コンテキスト
- 区切り
- グラフ
- テーブル
- URL 専用ボタン
ReplyPayload.deliveryを介した汎用配信メタデータ
旧来のコードを橋渡しする場合は、openclaw/plugin-sdk/interactive-runtime のヘルパーを使用します:
新しいコードでは、MessagePresentation を直接受け入れるか生成する必要があります。既存の
interactive ペイロードは、presentation の非推奨サブセットです。旧来のプロデューサー向けのランタイム対応は維持されます。
知っておくべき非推奨ではないヘルパー:
normalizeMessagePresentation(raw)/hasMessagePresentationBlocks(value)型指定のないペイロード(たとえば、CLI の--presentationフラグからの JSON)を検証および型変換してMessagePresentationにします。isMessagePresentationInteractiveBlock(block)はブロックをbuttons|select共用体型に絞り込みます。resolveMessagePresentationButtonAction(button)とresolveMessagePresentationOptionAction(option)は、非推奨の境界フィールドを受け入れながら、 正規の型付きアクションを返します。明示的なactionが 常に優先されます。resolveMessagePresentationActionValue(action)/resolveMessagePresentationControlValue(control)は、コマンド/コールバックの スカラー値のみを読み取ります。スカラーでない正規アクションが従来のシャドウvalueにフォールスルーすることはないため、承認 ID とリンク先は型付きのまま維持されます。renderMessagePresentationChartFallbackText(block)/renderMessagePresentationTableFallbackText(block)は、構造化データブロックを 1 つずつ、 チャネル固有のフォールバックパス向けに決定論的なテキストとしてレンダリングします。
従来の InteractiveReply* 型と変換ヘルパーは、SDK で
@deprecated としてマークされています。
InteractiveReply、InteractiveReplyBlock、InteractiveReplyButton、およびInteractiveReplyOptionnormalizeInteractiveReply(...)hasInteractiveReplyBlocks(...)interactiveReplyToPresentation(...)presentationToInteractiveReply(...)presentationToInteractiveControlsReply(...)resolveInteractiveTextFallback(...)reduceInteractiveReply(...)
presentationToInteractiveReply(...) と
presentationToInteractiveControlsReply(...) は、従来のチャネル実装向けのレンダラーブリッジとして
引き続き利用できます。新しい生成側コードではこれらを呼び出さず、
presentation を送信し、コア/チャネルの適応処理にレンダリングを任せてください。
承認ヘルパーにも、プレゼンテーション優先の代替があります。
buildApprovalInteractiveReply(...)の代わりにbuildApprovalPresentation(...)を使用してくださいbuildExecApprovalInteractiveReply(...)の代わりにbuildExecApprovalPresentation(...)を使用してください
リリース済みのこれらのビルダーは、Plugin の互換性を保つため、引き続きコマンドを基盤としています。永続的な承認種別を所有する Gateway
および同梱チャネルのコードでは、
buildTypedApprovalPresentation(...)、
buildTypedExecApprovalPendingReplyPayload(...)、または
buildTypedPluginApprovalPendingReplyPayload(...) を使用してください。これにより、トランスポートは /approve テキストから意味を推測するのではなく、
明示的な approval アクションを受け取ります。
renderMessagePresentationFallbackText(...) は、区切り線のみの
プレゼンテーションなど、テキストのフォールバックがないプレゼンテーションブロックに対して空文字列を返します。
空でない送信本文を必要とするトランスポートは、emptyFallback を渡すことで、
デフォルトのフォールバック契約を変更せずに最小限の本文を使用できます。
配信時のピン留め
ピン留めはプレゼンテーションではなく、配信の動作です。channelData.telegram.pin のような
プロバイダー固有のフィールドではなく、delivery.pin を使用してください。
セマンティクス:
pin: trueは、最初に正常配信されたメッセージをピン留めします。pin.notifyのデフォルトはfalseです。pin.requiredのデフォルトはfalseです。- 任意指定のピン留めが失敗した場合は処理を縮退させ、送信済みメッセージをそのまま維持します。
- 必須のピン留めが失敗した場合は、配信を失敗させます。
- 分割されたメッセージでは、末尾のチャンクではなく、最初に配信されたチャンクをピン留めします。
既存メッセージに対する手動の pin、unpin、および pins メッセージアクションは、プロバイダーがそれらの操作をサポートしている場合、引き続き利用できます。
Plugin 作成者向けチェックリスト
- チャネルがセマンティックなプレゼンテーションをレンダリングできるか、安全に縮退できる場合は、
describeMessageTool(...)からpresentationを宣言します。 - ランタイムのアウトバウンドアダプターに
presentationCapabilitiesを追加します。 - コントロールプレーンの Plugin セットアップコードではなく、ランタイムコードに
renderPresentationを実装します。 - ネイティブ UI ライブラリを、高頻度で実行されるセットアップ/カタログパスに含めないでください。
- 汎用的な機能制限が判明している場合は、
presentationCapabilities.limitsで宣言します。 - 最終的なプラットフォーム制限をレンダラーとテストで維持します。
- 未対応のグラフ、表、ボタン、選択項目、URL
ボタン、タイトル/テキストの重複、および
messageとpresentationが混在する 送信に対するフォールバックテストを追加します。 - プロバイダーが送信済みメッセージ ID をピン留めできる場合にのみ、
deliveryCapabilities.pinとpinDeliveredMessageを通じて配信時のピン留めをサポートします。 - 新しいプロバイダー固有のカード/ブロック/コンポーネント/ボタンのフィールドを、 共有メッセージアクションスキーマを通じて公開しないでください。