news 2026/9/14 17:30:31

OpenClaw Discord Skill:用 message 工具完成 Discord 消息工作流的设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenClaw Discord Skill:用 message 工具完成 Discord 消息工作流的设计与实现

OpenClaw Discord Skill:用 message 工具完成 Discord 消息工作流的设计与实现

【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw

本文以 OpenClaw 仓库中 Discord 插件内置的 discord skill 为主体,完整还原该 skill 定义的工作流规则(ID 选取、线程与 forum 约束、破坏性操作确认)、交互式组件(Components V2)的 JSON 用法及其硬性限制,并结合 discord 插件源码 逐条印证channels.discord.actions.*配置门控如何动态生成message工具的动作清单与参数 schema,以及 send 类动作为何在本地执行、其余动作交由 gateway 处理。读完后你可以理解:为什么模型"不能假设不存在的 action",以及一个 Discord 消息请求从工具 schema 发现到实际执行的完整链路。

Skill 的定位与 frontmatter

该 skill 位于 Discord 插件内部:extensions/discord/skills/discord/SKILL.md,其 frontmatter 声明了 skill 的基本契约:

--- name: discord description: "Discord messaging workflows through OpenClaw's message tool." metadata: { "openclaw": { "emoji": "🎮", "requires": { "config": ["channels.discord"] } } } allowed-tools: ["message"] ---

三个关键点:

  • requires.config: ["channels.discord"]表示只有配置中启用了 Discord 通道(存在channels.discord配置)时,该 skill 才会对 Agent 生效。这与源码中describeDiscordMessageTool的发现逻辑一致:当没有任何"已启用且已配置"的 Discord 账号时,直接返回actions: []、capabilities: []、schema: null,即工具不暴露任何 Discord 动作(见 channel-actions.ts)。
  • allowed-tools: ["message"]表明该 skill 的全部能力收敛在单一的message工具上,调用时固定携带channel: "discord"
  • 原文档开宗明义:"工具 schema 会列出当前账号channels.discord.actions.*门控允许的动作;不要假设不存在的动作。"这不是空话,而是由源码保证的——下文展开。

动作清单由配置门控动态生成

Skill 的核心原则是"以工具 schema 为准,而非静态动作目录"。在 channel-actions.ts 的describeDiscordMessageTool中可以看到完整的门控→动作映射:

actions.*配置键默认值解锁的 message 动作
(无门控)send(始终可用,只要有可发现的账号)
pollspoll
reactionsreactreactionsemoji-list
messagesupload-filereadeditdelete
pinspinunpinlist-pins
permissionspermissions
threadsthread-createthread-listthread-reply
searchsearch
stickerssticker
memberInfomember-info
roleInforole-info
emojiUploadsemoji-upload
stickerUploadssticker-upload
rolesrole-addrole-remove
channelInfochannel-infochannel-list
channelschannel-createchannel-editchannel-deletechannel-movecategory-createcategory-editcategory-delete
voiceStatusvoice-status
eventsevent-listevent-create
moderationtimeoutkickban
presenceset-presence

这些配置键与 config-schema.ts 中actions的严格 schema 一一对应(reactionsstickersemojiUploadsstickerUploadspollspermissionsmessagesthreadspinssearchmemberInforoleInforoleschannelInfovoiceStatuseventsmoderationchannelspresence,均为可选布尔值)。注意三个默认关闭的门控:rolesmoderationpresence——涉及角色增删、禁言/踢出/封禁、状态设置这类高敏感操作,需要显式开启,这与 skill 文档"不要假设不可用动作"的告诫相互印证。

门控的取值来源有双层结构,见 accounts.ts 的createDiscordActionGate

  • 基础层:cfg.channels.discord.actions(通道级默认);
  • 账号层:cfg.channels.discord.accounts.<accountId>.actions(单账号覆盖)。

当未指定accountId时,channel-actions.ts 的resolveDiscordActionDiscovery会对所有已启用且已配置的账号做并集createUnionActionGate):任一账号开启某门控,该动作就会出现在工具 schema 中;指定了accountId后则只看该账号自己的门控。这就是 skill 中"当多个 Discord 账号可能适用时,请传accountId"的底层依据——传与不传,决定的是动作清单的并集还是单集。

Skill 工作流规则及其源码依据

Skill 文档给出的四条工作流规则,每一条都能落到具体实现约束上:

1. 优先使用稳定的guildIdchannelIdmessageIduserId;多账号时传accountIdDiscord 的 Snowflake ID 是全局稳定标识。配置层面,config-schema.ts 的DiscordIdSchema明确允许数字或字符串形式的 ID,并对数字做了安全整数校验(非安全整数会被要求"在配置文件中加引号"),说明整个体系以 Snowflake 字符串为一等公民。

2. 用户指代含糊时,先解析出精确消息再执行编辑、删除、置顶、 moderation 或 reaction。这一条对应动作侧的实现:编辑/删除/置顶等动作都归入messages/pins/moderation门控(见上表),执行入口统一走 handle-action.ts 与 runtime.moderation.ts,后者带有独立的鉴权测试 runtime.moderation.authz.test.ts。源码结构表明 moderation 类动作在执行前会做请求者身份核验,因此"先确认精确目标"既是行为要求也是安全边界。

3. 线程回复留在原线程内;forum 父频道不能接收 components,应发到已创建的 forum 线程中。这是 Discord 平台侧的真实限制:forum 类型的父频道是只读的消息容器,只有其下自动创建的帖子线程才可承载交互组件。工具层对线程语义有专门的适配——channel-actions.ts 中的resolveDiscordThreadReplyTarget/resolveDiscordThreadReplyDeliveryAlias会把threadId归一化为channel:<threadId>目标,thread-reply动作通过messageActionTargetAliases声明threadId别名(第 278-286 行),并在matchesCurrentConversation命中时直接投递到当前会话线程,保证"线程回复留在原线程"。

4. 破坏性或 moderation 动作必须确认,除非用户已明确指定目标与动作。配合默认关闭的moderationroles门控,以及requiresTrustedRequesterSender(guild-admin 类动作需要受信任请求者,见 channel-actions.ts),skill 文档把"确认"写成了 Agent 的硬性行为约束。

交互式组件:Components V2 的用法与硬性限制

Skill 文档给出的组件示例(原文完整保留):

{ "action": "send", "channel": "discord", "to": "channel:123", "message": "Choose an option", "components": { "blocks": [ { "type": "actions", "buttons": [ { "label": "Approve", "style": "success", "callbackData": "approve" }, { "label": "Decline", "style": "danger", "callbackData": "decline" } ] } ] } }

两条硬性约束来自原文,且都能在源码中找到执行点:

约束一:components必须是结构化对象或原生组件数组,绝不能是占位字符串。在 channel-actions.ts 的prepareSendPayload中,ctx.params.components先经coerceDiscordComponentParam强制转换(定义于 components.parse.ts);若转换结果是函数(非法输入形态),直接返回null拒绝发送。合法对象再经readDiscordComponentSpec解析为组件 spec,原生数组则作为nativeComponents直通,最终写入channelData.discord.components。schema 侧同样如此:describeDiscordMessageToolsend动作声明的components属性是blocks(V2 块数组:text、buttons、selects、media、containers、separators)加可选modal的对象结构(第 229-262 行),与 components.ts 导出的类型体系(DiscordComponentBlockDiscordComponentButtonSpecDiscordModalSpec等)及构建器(buildDiscordComponentMessagecreateDiscordFormModal)保持一致。

约束二:Components V2 不得与 legacyembeds混用。这一点在prepareSendPayload中被写成显式守卫:

if ((componentSpec || nativeComponents) && embeds?.length) { return null; // 组件与 embeds 同时出现 → 拒绝 }

即两者同时存在时整个 payload 被拒绝,而不是静默降级,这正是 skill 文档要求 Agent"不要组合"的原因。

组件点击后的回传链路同样有源码支撑:custom id 的编解码集中在 component-custom-id.ts(buildDiscordComponentCustomId/parseDiscordComponentCustomId),交互分发在 interactive-dispatch.ts,按钮/选择器事件最终被格式化为Clicked "Approve".这类文本回灌给模型(formatDiscordComponentEventText)。

执行位置:本地动作与 gateway 动作的分流

从源码结构看,Discord 动作并非全部在同一位置执行。channel-actions.ts 定义了localExecutionActions白名单:

const localExecutionActions = new Set<ChannelMessageActionName>([ "send", "poll", "upload-file", "thread-reply", "sticker", "emoji-upload", "sticker-upload", "event-create", ]);

白名单内的动作以local模式执行,源码注释解释了原因:"Credential-only Discord actions run in the gateway when one is available. Send/file-style actions stay local because core owns their thread, media, component, and client-local payload semantics."——发送、上传、线程回复这类动作涉及核心拥有的线程路由、媒体文件与本地组件语义,必须留在客户端本地处理;而编辑、删除、置顶、moderation 等"只需凭证"的动作在可用时交给 gateway 执行。此外supportsAction明确排除poll(Discord 投票走独立本地路径)。理解这个分流,有助于在排查"某个动作为什么没执行/在哪里执行"时定位正确的日志与进程边界。

提示注入与"不要维护重复目录"

Skill 文档最后一句值得单独强调:"Discord mention 语法、组件可用性和表单提示会自动注入。请遵循当前的提示与工具 schema,而不是复制的动作目录。"

结合源码可以推断其设计动机:动作清单、schema 描述(例如react动作的emoji参数说明会根据emoji-list是否可用动态变化,见 channel-actions.ts)在每次工具发现时实时计算。若 skill 文档里硬编码一份动作目录,配置变更后必然失真;因此文档只固化工作流规则与组件约束这类不变量,把能力清单完全交给运行时 schema。这也是编写其他 OpenClaw channel skill 时可参考的模式:frontmatter 声明依赖配置与允许工具,正文写行为规则,能力细节交给门控与 schema 动态生成。

相关源码索引

主题路径
Skill 定义(本文主体)extensions/discord/skills/discord/SKILL.md
工具发现与动作门控映射extensions/discord/src/channel-actions.ts
账号配置合并与 action gateextensions/discord/src/accounts.ts
channels.discord配置 schema(含actions.*extensions/discord/src/config-schema.ts
组件解析/构建/模态框extensions/discord/src/components.ts
动作执行入口extensions/discord/src/actions/handle-action.ts
moderation 执行与鉴权测试extensions/discord/src/actions/runtime.moderation.ts、runtime.moderation.authz.test.ts
门控行为的契约测试extensions/discord/src/channel-actions.contract.test.ts、channel-actions.test.ts

适用前提:以上所有结论均基于当前仓库中 Discord 插件的源码与 skill 文档,需配置channels.discord(含有效 bot token,账号可通过token配置项或DISCORD_BOT_TOKEN环境变量提供,见 accounts.ts)方可生效;动作的最终可见集合由通道级与账号级actions.*门控共同决定。

【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 17:29:05

Hadoop源码深度剖析:从核心模块到RPC与HDFS读写链路实战

我决定把这一年多啃Hadoop源码的笔记整理成一篇可以直接照着读的索引式分享。不是那种罗列类名的源码导读&#xff0c;也不是贴一堆注释的代码复述&#xff0c;而是从“我为什么会去读源码、读了哪些模块、怎么搭建调试环境、核心流程到底怎么跑通、踩了哪些坑”这几个角度&…

作者头像 李华
网站建设 2026/9/14 17:23:25

【C语言】 数组

目录 1&#xff0c;数组的概念 2&#xff0c;数组的创建和初始化 3&#xff0c;数组的使用 4&#xff0c;数组的内存存储情况 5&#xff0c;sizeof 计算数组的元素个数 6&#xff0c;二维数组 7&#xff0c;二维数组的初始化和创建 8&#xff0c;二维数组的使用 9&…

作者头像 李华
网站建设 2026/9/14 17:22:31

供配电实训仿真软件:倒闸操作与故障处理全流程解析

干电气培训这些年&#xff0c;我见过太多学员第一次面对高压柜时的表情——手放在断路器分闸按钮上&#xff0c;迟迟不敢按下去。不是不知道步骤&#xff0c;而是怕按错了出大事。这种怕是对的&#xff0c;10kV开关柜一旦带负荷拉隔离开关&#xff0c;电弧瞬间就能把人灼伤&…

作者头像 李华
网站建设 2026/9/14 17:19:13

C++序列输出题全攻略:从读题到OJ提交的完整避坑指南

1. 一道短得不像话的题&#xff0c;凭什么让我交了三版才过东华OJ的基础题里有一类题属于“看着简单、做着崩溃”&#xff0c;第50题“按要求输出序列”就是典型。题面可能短到只有一句话&#xff0c;给一个整数N&#xff0c;让你按某种规则输出一串数。很多人的第一反应是&…

作者头像 李华
网站建设 2026/9/14 17:17:56

商丘做建设网站的公司3个最佳实践解决网站被黑

商丘做建设网站的公司3个最佳实践解决网站被黑 网站被黑挂马,后台密码泄露,首页瞬间变成赌博链接,这种绝望感每个运维都懂。在商丘本地,很多中小企业找 商丘做建设网站的公司 时,只盯着价格,却忽略了安全架构,结果就是养虎为患。面对这种紧急状况,盲目重装系统往往治标不治本,真正的 最佳实践…

作者头像 李华