渠道界面
渠道插件所拥有的接口面:会话绑定回调、消息工具 schema、目标解析、基于配置的目录,以及只读账户检查。本文是插件架构内部实现指南的一部分。
会话绑定回调¶
绑定会话的插件可以在审批被处理时做出响应。
使用 api.onConversationBindingResolved(...) 在绑定请求被批准或拒绝后接收回调:
export default {
id: "my-plugin",
register(api) {
api.onConversationBindingResolved(async (event) => {
if (event.status === "approved") {
// A binding now exists for this plugin + conversation.
console.log(event.binding?.conversationId);
return;
}
// The request was denied; clear any local pending state.
console.log(event.request.conversation.conversationId);
});
},
};
回调载荷字段:
status:"approved"或"denied"decision:"allow-once"、"allow-always"或"deny"binding:已批准请求的已解析绑定request:原始请求摘要、分离提示、发送者 id 和会话元数据
此回调仅用于通知。它不会改变谁被允许绑定会话,并且会在核心审批处理完成后运行。
消息工具 schema¶
插件应负责渠道特定的 describeMessageTool(...) schema 贡献,涵盖诸如 reaction(表情回应)、read(已读)和 poll(投票)等非消息原语。共享的发送呈现应使用通用的 MessagePresentation 契约,而不是提供方原生的按钮、组件、块或卡片字段。有关契约、回退规则、提供方映射和插件作者清单,请参阅消息呈现。
提供方原生的 schema 扩展需要维护者的明确批准、渠道自有的解析、记录在案的跨渠道行为,以及 MessagePresentation 无法表达的能力。Discord components 是已批准的内置例外,用于其高级 Components V2 布局。
支持发送的插件通过消息能力(message capabilities)声明它们可以渲染的内容:
presentation:用于语义呈现块(text、context、divider、chart、table、buttons、select)delivery-pin:用于置顶投递(pinned-delivery)请求
核心(Core)决定是以原生方式渲染呈现,还是将其降级为文本。不要从通用消息工具中暴露未经批准的提供方原生 UI 逃生舱口。为旧版原生 schema 提供的已弃用 SDK 辅助函数仍继续导出,供现有第三方插件使用,但新插件不应使用它们。
渠道目标解析¶
渠道插件应负责渠道特定的目标语义。保持共享的出站主机(outbound host)的通用性,并使用消息适配器接口面来承载提供方规则:
messaging.inferTargetChatType({ to }):决定规范化目标在目录查找之前应被视作direct、group还是channel。隐式的所有者心跳投递需要这种直接分类;否则,Gateway 状态会报告waiting for route。messaging.targetResolver.looksLikeId(raw, normalized):告知核心某个输入是否应直接跳到类似 id 的解析,而不是进行目录搜索。messaging.targetResolver.reservedLiterals:列出对该提供方而言属于渠道/会话引用的裸词。解析会优先遵循已配置的目录条目,然后才拒绝保留字面量,最后在目录未命中时 fail closed(默认拒绝)。messaging.targetResolver.resolveTarget(...):当核心在规范化之后或目录未命中之后需要最终的提供方自有解析时,作为插件回退。messaging.resolveOutboundSessionRoute(...):在目标解析后负责提供方特定的会话路由构建。
推荐的分工:
- 使用
inferTargetChatType做出应在搜索对等方/群组之前进行的类别决策。 - 使用
looksLikeId进行“将其视为显式/原生目标 id”的检查。 - 使用
resolveTarget进行提供方特定的规范化回退,而不是用于广泛的目录搜索。 - 将提供方原生的 id(如 chat id、thread id、JID、handle 和 room id)保留在
target值或提供方特定参数中,而不要放入通用 SDK 字段。
基于配置的目录¶
从配置中派生目录条目的插件应将此逻辑保留在插件内部,并复用 openclaw/plugin-sdk/directory-runtime 中的共享辅助函数。
当渠道需要基于配置的对等方/群组时使用此功能,例如:
- 由允许列表驱动的 DM 对等方
- 已配置的渠道/群组映射
- 账户范围的静态目录回退
directory-runtime 中的共享辅助函数仅处理通用操作:
- 查询过滤
- 限制应用
- 去重/规范化辅助函数
- 构建
ChannelDirectoryEntry[]
渠道特定的账户检查和 id 规范化应保留在插件实现中。
只读渠道检查¶
如果你的插件注册了渠道,建议在 resolveAccount(...) 之外同时实现 plugin.config.inspectAccount(cfg, accountId)。
原因:
resolveAccount(...)是运行时路径。它可以假定凭据已完全物化,并且在缺少所需机密时能够快速失败。- 只读命令路径(如
openclaw status、openclaw status --all、openclaw channels status、openclaw channels resolve)以及 doctor/配置修复流程,不应仅仅为了描述配置而物化运行时凭据。
推荐的 inspectAccount(...) 行为:
- 仅返回描述性的账户状态。
- 保留
enabled和configured。 - 在相关时包含凭据来源/状态字段,例如:
tokenSource、tokenStatusbotTokenSource、botTokenStatusappTokenSource、appTokenStatussigningSecretSource、signingSecretStatus- 你不需要为了报告只读可用性而返回原始 token 值。对于状态类命令,返回
tokenStatus: "available"(以及匹配的 source 字段)就足够了。 - 当凭据通过 SecretRef 配置但在当前命令路径中不可用时,使用
configured_unavailable。
这让只读命令报告“已配置但在当前命令路径中不可用”,而不会崩溃或误报账户未配置。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw