- 文本区块
- 小型上下文/页脚文本
- 分隔线
- 按钮
- 选择菜单
- 卡片标题和语气
components、Slack blocks、Telegram buttons、Teams card 或 Feishu card 之类的提供方原生字段。这些是由频道插件拥有的渲染器输出。
契约
插件作者从以下位置导入公开契约:action.type: "command"通过核心的命令路径运行原生斜杠命令。用于内置命令按钮和菜单。action.type: "callback"通过频道的交互路径传递不透明的插件数据。频道插件不得将回调数据重新解释为斜杠命令。value是旧版的不透明回调值。新控件应使用action,这样频道插件就能无需猜测文本即可映射命令和回调。url是链接按钮。它可以在没有value的情况下存在。webApp描述频道原生的 Web 应用按钮。Telegram 会将其渲染为web_app,且仅支持私聊。为了兼容性,web_app仍可在宽松 JSON 载荷中接受,但 TypeScript 生产者应使用webApp。label是必需项,并且也用于文本回退。style仅供参考。渲染器应将不支持的样式映射为安全默认值,而不是发送失败。priority是可选项。当频道声明动作限制且必须丢弃部分控件时,核心会优先保留更高优先级的按钮,并在相同优先级之间保留原始顺序。当所有控件都能容纳时,则保留作者编排的顺序。disabled是可选项。频道必须通过supportsDisabled显式启用;否则核心会将禁用控件降级为不可交互的回退文本。reusable是可选项。支持可复用原生回调的频道可以在一次成功交互后继续保留该动作。用于可重复或幂等的动作,例如刷新、查看详情或更多信息;对普通的一次性审批和破坏性动作则不要设置。
options[].action与按钮action具有相同的 command/callback 含义。options[].value是旧版的所选应用值。placeholder仅供参考,缺少原生选择支持的频道可以忽略它。- 如果频道不支持选择器,回退文本会列出这些标签。
生产者示例
简单卡片:渲染器契约
频道插件在其出站适配器上声明渲染支持:limits 描述了 core 在调用渲染器之前可以适配的通用边界:
核心渲染流程
当ReplyPayload 或消息动作包含 presentation 时,core 会:
- 规范化展示载荷。
- 解析目标频道的出站适配器。
- 读取
presentationCapabilities。 - 在适配器声明支持时,应用通用能力限制,例如动作数量、标签长度和选择项数量。
- 当适配器可以渲染该载荷时调用
renderPresentation。 - 当适配器缺失或无法渲染时回退为保守文本。
- 通过正常的频道投递路径发送结果载荷。
- 在首条消息成功发送后应用诸如
delivery.pin之类的投递元数据。
降级规则
展示必须能够安全地发送到受限频道。 回退文本包括:title作为第一行text区块作为普通段落context区块作为紧凑的上下文行divider区块作为视觉分隔符- 按钮标签,包括链接按钮的 URL
- 选择器选项标签
- 在禁用内联按钮的 Telegram 中会发送文本回退。
- 不支持选择器的频道会将选择项作为文本列出。
- 仅 URL 的按钮会变成原生链接按钮,或者回退为 URL 行。
- 可选的置顶失败不会导致已投递消息失败。
delivery.pin.required: true;如果请求置顶为必需,而频道无法将已发送消息置顶,则投递会报告失败。
提供方映射
当前内置渲染器:| 频道 | 原生渲染目标 | 说明 |
|---|---|---|
| Discord | 组件和组件容器 | 为现有的提供方原生载荷生产者保留旧的 channelData.discord.components,但新的共享发送应使用 presentation。 |
| Slack | Block Kit | 为现有的提供方原生载荷生产者保留旧的 channelData.slack.blocks,但新的共享发送应使用 presentation。 |
| Telegram | 文本加内联键盘 | 按钮/选择器要求目标表面具备内联按钮能力;否则使用文本回退。 |
| Mattermost | 文本加交互属性 | 其他区块会降级为文本。 |
| Microsoft Teams | 自适应卡片 | 当两者都提供时,纯 message 文本会与卡片一起包含。 |
| 飞书 | 交互式卡片 | 卡片头部可以使用 title;正文会避免重复该标题。 |
| 纯文本频道 | 文本回退 | 没有渲染器的频道仍会得到可读输出。 |
展示 vs 交互回复
InteractiveReply 是较早的内部子集,由审批和交互辅助工具使用。它支持:
- 文本
- 按钮
- 选择器
MessagePresentation 是规范的共享发送契约。它新增了:
- 标题
- 语气
- 上下文
- 分隔线
- 仅 URL 按钮
- 通过
ReplyPayload.delivery提供的通用投递元数据
openclaw/plugin-sdk/interactive-runtime 中的辅助函数:
MessagePresentation。现有的
interactive 载荷是 presentation 的已弃用子集;运行时
仍会为旧生产者保留支持。
SDK 中旧版 InteractiveReply* 类型和转换辅助函数已标记为
@deprecated:
InteractiveReply、InteractiveReplyBlock、InteractiveReplyButton、InteractiveReplyOption、InteractiveReplySelectBlock和InteractiveReplyTextBlocknormalizeInteractiveReply(...)hasInteractiveReplyBlocks(...)interactiveReplyToPresentation(...)presentationToInteractiveReply(...)presentationToInteractiveControlsReply(...)resolveInteractiveTextFallback(...)reduceInteractiveReply(...)
presentationToInteractiveReply(...) 和
presentationToInteractiveControlsReply(...) 仍可作为旧版频道实现的渲染
桥接函数使用。新的生产者代码不应调用它们;发送 presentation 并让 core/频道适配处理渲染。
审批辅助工具也有以 presentation 为优先的替代方案:
- 使用
buildApprovalPresentationFromActionDescriptors(...)代替buildApprovalInteractiveReplyFromActionDescriptors(...) - 使用
buildApprovalPresentation(...)代替buildApprovalInteractiveReply(...) - 使用
buildExecApprovalPresentation(...)代替buildExecApprovalInteractiveReply(...)
renderMessagePresentationFallbackText(...) 对于没有文本回退的
展示区块会返回空字符串,例如仅包含分隔线的展示。需要非空发送正文的传输层可以传入
emptyFallback,以在不改变默认回退
契约的情况下使用最小正文。
投递置顶
置顶属于投递行为,而不是展示。请使用delivery.pin,而不是诸如 channelData.telegram.pin 之类的提供方原生字段。
语义:
pin: true会置顶第一条成功投递的消息。pin.notify默认值为false。pin.required默认值为false。- 可选置顶失败会降级处理,并保留已发送消息。
- 必需置顶失败会导致投递失败。
- 分块消息会置顶第一块成功投递的内容,而不是尾块。
pin、unpin 和 pins 消息动作仍然存在,供支持这些操作的提供方在现有消息上使用。
插件作者检查清单
- 当通道可以渲染语义化呈现,或能够安全降级时,从
describeMessageTool(...)声明presentation。 - 在运行时 outbound adapter 中添加
presentationCapabilities。 - 在运行时代码中实现
renderPresentation,不要放在控制平面插件初始化代码中。 - 不要让原生 UI 库进入热路径的初始化/目录路径。
- 当已知时,在
presentationCapabilities.limits上声明通用能力限制。 - 在渲染器和测试中保留最终的平台限制。
- 为不支持的按钮、选择器、URL 按钮、标题/文本重复,以及同时发送
message和presentation的情况添加回退测试。 - 仅当提供方能够对已发送消息 id 进行置顶时,通过
deliveryCapabilities.pin和pinDeliveredMessage添加投递置顶支持。 - 不要通过共享的消息动作 schema 暴露新的提供方原生卡片/区块/组件/按钮字段。