diff --git a/docs/zh-CN/channels/discord.md b/docs/zh-CN/channels/discord.md index 0468ebe81..86114371e 100644 --- a/docs/zh-CN/channels/discord.md +++ b/docs/zh-CN/channels/discord.md @@ -4,17 +4,17 @@ read_when: summary: Discord 机器人支持状态、功能和配置 title: Discord x-i18n: - generated_at: "2026-04-23T07:03:23Z" + generated_at: "2026-04-23T08:25:07Z" model: gpt-5.4 provider: openai - source_hash: 0bee2c419651701f7ab57e46a4c0c473c83596eb9bd2156bac3c6117513236ab + source_hash: 1160a0b221bc3251722a81c00c65ee7c2001efce345248727f1f3c8580a0e953 source_path: channels/discord.md workflow: 15 --- # Discord(Bot API) -状态:已就绪,可通过官方 Discord Gateway 网关用于私信和服务器频道。 +状态:已就绪,可通过官方 Discord gateway 用于私信和服务器频道。 @@ -30,7 +30,7 @@ x-i18n: ## 快速开始 -你需要创建一个带机器人的新应用,将机器人添加到你的服务器,并将其与 OpenClaw 配对。我们建议把你的机器人添加到你自己的私有服务器。如果你还没有服务器,请先[创建一个](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server)(选择 **Create My Own > For me and my friends**)。 +你需要创建一个带有机器人的新应用,将机器人添加到你的服务器中,并将其与 OpenClaw 配对。我们建议将你的机器人添加到你自己的私有服务器。如果你还没有服务器,请先[创建一个](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server)(选择 **Create My Own > For me and my friends**)。 @@ -41,34 +41,34 @@ x-i18n: - 仍在 **Bot** 页面时,向下滚动到 **Privileged Gateway Intents**,并启用: + 仍然停留在 **Bot** 页面,向下滚动到 **Privileged Gateway Intents** 并启用: - **Message Content Intent**(必需) - - **Server Members Intent**(推荐;角色 allowlist 和名称到 ID 匹配时必需) - - **Presence Intent**(可选;仅在需要在线状态更新时使用) + - **Server Members Intent**(推荐;角色允许列表和名称到 ID 匹配需要它) + - **Presence Intent**(可选;仅在需要在线状态更新时启用) - 向上滚动回 **Bot** 页面顶部,点击 **Reset Token**。 + 向上滚动回 **Bot** 页面并点击 **Reset Token**。 - 尽管名字叫这样,但这里会生成你的第一个令牌 —— 并没有任何内容被“重置”。 + 尽管名字叫这样,这会生成你的第一个令牌——并没有任何内容被“重置”。 - 复制该令牌并保存到某处。这就是你的 **Bot Token**,你很快就会用到它。 + 复制该令牌并将其保存到某处。这就是你的 **Bot Token**,你很快就会用到它。 - - 点击侧边栏中的 **OAuth2**。你将生成一个带有正确权限的邀请 URL,用于把机器人添加到你的服务器。 + + 点击侧边栏中的 **OAuth2**。你将生成一个带有正确权限的邀请 URL,用于将机器人添加到你的服务器。 - 向下滚动到 **OAuth2 URL Generator**,并启用: + 向下滚动到 **OAuth2 URL Generator** 并启用: - `bot` - `applications.commands` - 下方会出现 **Bot Permissions** 区域。至少启用: + 下方会出现一个 **Bot Permissions** 部分。至少启用: **General Permissions** - View Channels @@ -79,31 +79,31 @@ x-i18n: - Attach Files - Add Reactions(可选) - 这是普通文本频道的基础权限集。如果你计划在 Discord 帖子串中发帖,包括会创建或继续帖子串的 forum 或 media 渠道工作流,还需要启用 **Send Messages in Threads**。 - 复制底部生成的 URL,粘贴到浏览器中,选择你的服务器,然后点击 **Continue** 进行连接。现在你应该能在 Discord 服务器中看到你的机器人。 + 这是普通文本频道的基础权限集。如果你计划在 Discord 线程中发帖,包括会创建或继续线程的论坛或媒体频道工作流,还需要启用 **Send Messages in Threads**。 + 复制底部生成的 URL,将其粘贴到浏览器中,选择你的服务器,然后点击 **Continue** 进行连接。现在你应该能在 Discord 服务器中看到你的机器人。 - - 回到 Discord 应用中,你需要启用开发者模式,这样才能复制内部 ID。 + + 回到 Discord 应用中,你需要启用 Developer Mode,这样你才能复制内部 ID。 1. 点击 **User Settings**(头像旁边的齿轮图标)→ **Advanced** → 打开 **Developer Mode** - 2. 在侧边栏中右键点击你的 **server icon** → **Copy Server ID** - 3. 右键点击你自己的 **avatar** → **Copy User ID** + 2. 在侧边栏中右键点击你的**服务器图标** → **Copy Server ID** + 3. 右键点击你自己的**头像** → **Copy User ID** - 将你的 **Server ID** 和 **User ID** 与 Bot Token 一起保存 —— 下一步你会把这三项都提供给 OpenClaw。 + 将你的 **Server ID** 和 **User ID** 与 Bot Token 一起保存——下一步你需要把这三个值都提供给 OpenClaw。 - 要让配对正常工作,Discord 需要允许你的机器人向你发送私信。右键点击你的 **server icon** → **Privacy Settings** → 打开 **Direct Messages**。 + 为了让配对正常工作,Discord 需要允许你的机器人向你发送私信。右键点击你的**服务器图标** → **Privacy Settings** → 打开 **Direct Messages**。 - 这样服务器成员(包括机器人)就可以向你发送私信。如果你想在 OpenClaw 中使用 Discord 私信,请保持该选项启用。如果你只打算使用服务器频道,那么在完成配对后可以关闭私信。 + 这样服务器成员(包括机器人)就可以向你发送私信。如果你想通过 OpenClaw 使用 Discord 私信,请保持此设置开启。如果你只打算使用服务器频道,那么配对完成后可以关闭私信。 - - 你的 Discord 机器人令牌是机密信息(类似密码)。在给你的智能体发消息之前,请先在运行 OpenClaw 的机器上设置它。 + + 你的 Discord 机器人令牌是机密信息(就像密码一样)。在给你的智能体发送消息之前,先在运行 OpenClaw 的机器上设置它。 ```bash export DISCORD_BOT_TOKEN="YOUR_BOT_TOKEN" @@ -113,7 +113,7 @@ openclaw config set channels.discord.enabled true --strict-json openclaw gateway ``` - 如果 OpenClaw 已经作为后台服务运行,请通过 OpenClaw Mac 应用重启它,或者停止并重新启动 `openclaw gateway run` 进程。 + 如果 OpenClaw 已经作为后台服务在运行,请通过 OpenClaw Mac 应用重启它,或者停止并重新启动 `openclaw gateway run` 进程。 @@ -121,9 +121,9 @@ openclaw gateway - 在任何现有渠道(例如 Telegram)上与你的 OpenClaw 智能体聊天,并告诉它。如果 Discord 是你的第一个渠道,请改用 CLI / config 标签页。 + 在任何现有渠道(例如 Telegram)上与你的 OpenClaw 智能体聊天,并告诉它。如果 Discord 是你的第一个渠道,请改用 CLI / 配置标签页。 - > “我已经在配置中设置好了 Discord 机器人令牌。请使用 User ID `` 和 Server ID `` 完成 Discord 设置。” + > “我已经在配置中设置了 Discord 机器人令牌。请使用 User ID `` 和 Server ID `` 完成 Discord 设置。” 如果你更喜欢基于文件的配置,请设置: @@ -149,7 +149,7 @@ openclaw gateway DISCORD_BOT_TOKEN=... ``` - 支持纯文本 `token` 值。`channels.discord.token` 也支持跨 env/file/exec 提供商的 SecretRef 值。请参阅 [Secrets Management](/zh-CN/gateway/secrets)。 + 支持明文 `token` 值。`channels.discord.token` 也支持跨 env/file/exec 提供商的 SecretRef 值。参见 [Secrets Management](/zh-CN/gateway/secrets)。 @@ -157,11 +157,11 @@ DISCORD_BOT_TOKEN=... - 等待 Gateway 网关运行后,在 Discord 中向你的机器人发送私信。它会回复一个配对码。 + 等待 Gateway 网关运行起来,然后在 Discord 中向你的机器人发送私信。它会回复一个配对码。 - 在你现有的渠道中,把配对码发送给你的智能体: + 在你现有的渠道中,将该配对码发送给你的智能体: > “批准这个 Discord 配对码:``” @@ -177,27 +177,27 @@ openclaw pairing approve discord 配对码会在 1 小时后过期。 - 现在你应该已经可以通过私信在 Discord 中与你的智能体聊天了。 + 现在你应该已经可以通过 Discord 私信与你的智能体聊天了。 -令牌解析是账户感知的。配置中的令牌值优先于环境变量回退。`DISCORD_BOT_TOKEN` 仅用于默认账户。 -对于高级出站调用(消息工具/渠道操作),会为该次调用使用显式的逐调用 `token`。这适用于发送以及读取/探测类操作(例如 read/search/fetch/thread/pins/permissions)。账户策略和重试设置仍然来自活动运行时快照中所选的账户。 +令牌解析具有账户感知能力。配置中的令牌值优先于环境变量回退。`DISCORD_BOT_TOKEN` 仅用于默认账户。 +对于高级出站调用(消息工具/渠道操作),显式的每次调用 `token` 会用于该次调用。这适用于发送以及读取/探测类操作(例如 read/search/fetch/thread/pins/permissions)。账户策略/重试设置仍来自活动运行时快照中所选账户。 ## 推荐:设置服务器工作区 -私信可用后,你可以把 Discord 服务器设置为一个完整工作区,其中每个频道都会获得自己的智能体会话和独立上下文。对于只有你和机器人使用的私有服务器,我们推荐这样做。 +一旦私信工作正常,你就可以将 Discord 服务器设置为一个完整工作区,其中每个频道都会获得自己的智能体会话及其各自的上下文。对于只有你和机器人使用的私有服务器,我们推荐这样配置。 - - 这样你的智能体就可以在服务器中的任意频道内响应,而不仅仅是私信。 + + 这样你的智能体就可以在服务器中的任何频道响应,而不仅仅是在私信中。 - > “把我的 Discord Server ID `` 添加到服务器 allowlist” + > “将我的 Discord Server ID `` 添加到服务器允许列表” @@ -223,14 +223,14 @@ openclaw pairing approve discord - 默认情况下,你的智能体只有在服务器频道中被 @ 提及时才会回复。对于私有服务器,你可能更希望它对每条消息都进行回复。 + 默认情况下,你的智能体只会在被 @mention 时才在服务器频道中响应。对于私有服务器,你很可能希望它对每条消息都做出响应。 - > “允许我的智能体在这个服务器中回复,而不需要被 @ 提及” + > “允许我的智能体在这个服务器中无需被 @mention 也能回复” - 在你的服务器配置中将 `requireMention: false` 设置为: + 在你的服务器配置中设置 `requireMention: false`: ```json5 { @@ -251,7 +251,7 @@ openclaw pairing approve discord - + 默认情况下,长期记忆(MEMORY.md)只会在私信会话中加载。服务器频道不会自动加载 MEMORY.md。 @@ -259,68 +259,68 @@ openclaw pairing approve discord > “当我在 Discord 频道中提问时,如果你需要来自 MEMORY.md 的长期上下文,请使用 memory_search 或 memory_get。” - 如果你需要在每个频道中共享上下文,请把稳定的指令放在 `AGENTS.md` 或 `USER.md` 中(它们会注入到每个会话)。把长期笔记保存在 `MEMORY.md` 中,并在需要时通过 memory 工具访问它们。 + 如果你需要在每个频道中共享上下文,请将稳定的说明放入 `AGENTS.md` 或 `USER.md`(它们会注入到每个会话中)。将长期笔记保存在 `MEMORY.md` 中,并在需要时通过 memory 工具访问它们。 -现在,在你的 Discord 服务器中创建一些频道并开始聊天吧。你的智能体可以看到频道名称,并且每个频道都会获得自己隔离的会话 —— 因此你可以设置 `#coding`、`#home`、`#research`,或者任何适合你工作流的频道。 +现在,在你的 Discord 服务器上创建一些频道并开始聊天吧。你的智能体可以看到频道名称,并且每个频道都会获得自己隔离的会话——因此你可以设置 `#coding`、`#home`、`#research`,或者任何适合你工作流的频道。 ## 运行时模型 - Gateway 网关负责 Discord 连接。 -- 回复路由是确定性的:来自 Discord 的入站消息会回复到 Discord。 +- 回复路由是确定性的:来自 Discord 的入站回复会返回到 Discord。 - 默认情况下(`session.dmScope=main`),私聊共享智能体主会话(`agent:main:main`)。 - 服务器频道使用隔离的会话键(`agent::discord:channel:`)。 - 默认忽略群组私信(`channels.discord.dm.groupEnabled=false`)。 -- 原生斜杠命令在隔离的命令会话中运行(`agent::discord:slash:`),同时仍会将 `CommandTargetSessionKey` 传递到路由后的对话会话。 +- 原生斜杠命令在隔离的命令会话中运行(`agent::discord:slash:`),同时仍携带 `CommandTargetSessionKey` 指向路由后的对话会话。 -## forum 渠道 +## 论坛频道 -Discord forum 和 media 渠道只接受帖子串。OpenClaw 支持两种创建方式: +Discord 论坛和媒体频道只接受线程帖子。OpenClaw 支持两种创建方式: -- 向 forum 父频道(`channel:`)发送消息以自动创建帖子串。帖子串标题使用你消息中的第一行非空内容。 -- 使用 `openclaw message thread create` 直接创建帖子串。对于 forum 渠道,不要传递 `--message-id`。 +- 向论坛父频道(`channel:`)发送消息,以自动创建线程。线程标题使用你消息中的第一条非空行。 +- 使用 `openclaw message thread create` 直接创建线程。不要为论坛频道传递 `--message-id`。 -示例:发送到 forum 父频道以创建帖子串 +示例:发送到论坛父频道以创建线程 ```bash openclaw message send --channel discord --target channel: \ --message "Topic title\nBody of the post" ``` -示例:显式创建 forum 帖子串 +示例:显式创建论坛线程 ```bash openclaw message thread create --channel discord --target channel: \ --thread-name "Topic title" --message "Body of the post" ``` -forum 父频道不接受 Discord components。如果你需要 components,请发送到帖子串本身(`channel:`)。 +论坛父频道不接受 Discord 组件。如果你需要组件,请发送到线程本身(`channel:`)。 -## 交互式 components +## 交互式组件 -OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 `components` 负载的消息工具。交互结果会像普通入站消息一样路由回智能体,并遵循现有的 Discord `replyToMode` 设置。 +OpenClaw 为智能体消息支持 Discord components v2 容器。使用带有 `components` 负载的消息工具。交互结果会像普通入站消息一样路由回智能体,并遵循现有的 Discord `replyToMode` 设置。 -支持的块: +支持的区块: - `text`、`section`、`separator`、`actions`、`media-gallery`、`file` -- 操作行最多允许 5 个按钮或单个选择菜单 +- 操作行最多允许 5 个按钮,或单个选择菜单 - 选择类型:`string`、`user`、`role`、`mentionable`、`channel` -默认情况下,components 为一次性使用。设置 `components.reusable=true` 可允许按钮、选择器和表单在过期前被多次使用。 +默认情况下,组件只能使用一次。设置 `components.reusable=true` 可让按钮、选择器和表单在过期前被多次使用。 -如果要限制谁可以点击按钮,请在该按钮上设置 `allowedUsers`(Discord 用户 ID、标签,或 `*`)。配置后,不匹配的用户会收到一条仅自己可见的拒绝消息。 +要限制谁可以点击按钮,请在该按钮上设置 `allowedUsers`(Discord 用户 ID、标签,或 `*`)。配置后,不匹配的用户会收到一条仅自己可见的拒绝提示。 -`/model` 和 `/models` 斜杠命令会打开一个交互式模型选择器,其中包含提供商和模型下拉菜单,以及一个 Submit 步骤。除非设置了 `commands.modelsWrite=false`,否则 `/models add` 也支持通过聊天添加新的提供商/模型条目,新增模型无需重启 Gateway 网关即可显示。选择器回复为仅自己可见,并且只有调用它的用户可以使用。 +`/model` 和 `/models` 斜杠命令会打开一个交互式模型选择器,其中包含提供商和模型下拉菜单,以及一个提交步骤。除非设置了 `commands.modelsWrite=false`,否则 `/models add` 也支持在聊天中添加新的提供商/模型条目,而且新添加的模型无需重启 Gateway 网关就会显示出来。选择器的回复仅自己可见,且只有调用该命令的用户可以使用它。 文件附件: -- `file` 块必须指向一个附件引用(`attachment://`) -- 通过 `media`/`path`/`filePath` 提供附件(单文件);多个文件请使用 `media-gallery` -- 当上传名称需要与附件引用匹配时,请使用 `filename` 覆盖上传名称 +- `file` 区块必须指向一个附件引用(`attachment://`) +- 通过 `media`/`path`/`filePath` 提供附件(单个文件);多个文件请使用 `media-gallery` +- 当上传名称应与附件引用匹配时,使用 `filename` 覆盖上传名称 模态表单: @@ -393,20 +393,20 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - `open`(要求 `channels.discord.allowFrom` 包含 `"*"`;旧版:`channels.discord.dm.allowFrom`) - `disabled` - 如果私信策略不是 open,未知用户会被阻止(或在 `pairing` 模式下被提示进行配对)。 + 如果私信策略不是 open,未知用户会被阻止(或在 `pairing` 模式下提示进行配对)。 多账户优先级: - `channels.discord.accounts.default.allowFrom` 仅适用于 `default` 账户。 - - 当具名账户自己的 `allowFrom` 未设置时,会继承 `channels.discord.allowFrom`。 - - 具名账户不会继承 `channels.discord.accounts.default.allowFrom`。 + - 当命名账户自身的 `allowFrom` 未设置时,会继承 `channels.discord.allowFrom`。 + - 命名账户不会继承 `channels.discord.accounts.default.allowFrom`。 用于投递的私信目标格式: - `user:` - `<@id>` 提及 - 裸数字 ID 存在歧义,除非提供了明确的用户/频道目标类型,否则会被拒绝。 + 纯数字 ID 存在歧义,除非显式提供 user/channel 目标类型,否则会被拒绝。 @@ -417,16 +417,16 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - `allowlist` - `disabled` - 当存在 `channels.discord` 时,安全的基线是 `allowlist`。 + 当存在 `channels.discord` 时,安全基线是 `allowlist`。 `allowlist` 行为: - 服务器必须匹配 `channels.discord.guilds`(优先使用 `id`,也接受 slug) - - 可选的发送者 allowlist:`users`(推荐使用稳定 ID)和 `roles`(仅角色 ID);如果配置了任一项,则当发送者匹配 `users` 或 `roles` 时即被允许 - - 默认禁用直接名称/标签匹配;只有在紧急兼容模式下才启用 `channels.discord.dangerouslyAllowNameMatching: true` + - 可选的发送者允许列表:`users`(推荐使用稳定 ID)和 `roles`(仅角色 ID);如果配置了其中任意一项,当发送者匹配 `users` 或 `roles` 时即被允许 + - 默认禁用直接名称/标签匹配;仅在作为紧急兼容模式时启用 `channels.discord.dangerouslyAllowNameMatching: true` - `users` 支持名称/标签,但 ID 更安全;使用名称/标签条目时,`openclaw security audit` 会发出警告 - 如果某个服务器配置了 `channels`,则未列出的频道会被拒绝 - - 如果某个服务器没有 `channels` 块,则该 allowlist 服务器中的所有频道都被允许 + - 如果某个服务器没有 `channels` 块,则该允许列表服务器中的所有频道都被允许 示例: @@ -452,26 +452,26 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 } ``` - 如果你只设置了 `DISCORD_BOT_TOKEN`,但没有创建 `channels.discord` 块,则运行时回退为 `groupPolicy="allowlist"`(日志中会有警告),即使 `channels.defaults.groupPolicy` 是 `open` 也是如此。 + 如果你只设置了 `DISCORD_BOT_TOKEN`,而没有创建 `channels.discord` 块,则运行时回退为 `groupPolicy="allowlist"`(日志中会有警告),即使 `channels.defaults.groupPolicy` 是 `open` 也是如此。 - 默认情况下,服务器消息受提及门控。 + 默认情况下,服务器消息需要提及才会触发。 提及检测包括: - 显式提及机器人 - 已配置的提及模式(`agents.list[].groupChat.mentionPatterns`,回退为 `messages.groupChat.mentionPatterns`) - - 在受支持场景中的隐式回复机器人行为 + - 在支持的情况下,隐式回复机器人行为 `requireMention` 按服务器/频道配置(`channels.discord.guilds...`)。 - `ignoreOtherMentions` 可选择丢弃那些提及了其他用户/角色但没有提及机器人的消息(不包括 @everyone/@here)。 + `ignoreOtherMentions` 可选地丢弃提及了其他用户/角色但未提及机器人的消息(不包括 @everyone/@here)。 群组私信: - 默认:忽略(`dm.groupEnabled=false`) - - 可选:通过 `dm.groupChannels` allowlist 允许(频道 ID 或 slug) + - 可选允许列表通过 `dm.groupChannels` 配置(频道 ID 或 slug) @@ -519,7 +519,7 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - Message Content Intent - Server Members Intent(推荐) - Presence intent 是可选的,只有在你希望接收在线状态更新时才需要。设置机器人在线状态(`setPresence`)并不要求为成员启用在线状态更新。 + Presence intent 是可选的,只有当你希望接收在线状态更新时才需要。设置机器人在线状态(`setPresence`)并不要求为成员启用在线状态更新。 @@ -539,7 +539,7 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - Attach Files - Add Reactions(可选) - 这是普通文本频道的基础权限集。如果你计划在 Discord 帖子串中发帖,包括会创建或继续帖子串的 forum 或 media 渠道工作流,还需要启用 **Send Messages in Threads**。 + 这是普通文本频道的基础权限集。如果你计划在 Discord 线程中发帖,包括会创建或继续线程的论坛或媒体频道工作流,还需要启用 **Send Messages in Threads**。 除非明确需要,否则避免使用 `Administrator`。 @@ -551,20 +551,20 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - channel ID - user ID - 在 OpenClaw 配置中优先使用数字 ID,以获得更可靠的审计和探测结果。 + 在 OpenClaw 配置中,优先使用数字 ID,以获得可靠的审计和探测能力。 ## 原生命令和命令鉴权 -- `commands.native` 默认为 `"auto"`,并且已为 Discord 启用。 +- `commands.native` 默认为 `"auto"`,并且对 Discord 已启用。 - 按渠道覆盖:`channels.discord.commands.native`。 -- `commands.native=false` 会显式清除之前已注册的 Discord 原生命令。 -- 原生命令鉴权使用与普通消息处理相同的 Discord allowlist/策略。 -- 对于未获授权的用户,这些命令在 Discord UI 中可能仍然可见;但执行时仍会强制执行 OpenClaw 鉴权,并返回 “not authorized”。 +- `commands.native=false` 会显式清除先前已注册的 Discord 原生命令。 +- 原生命令鉴权使用与普通消息处理相同的 Discord 允许列表/策略。 +- 即使未授权用户仍可能在 Discord UI 中看到命令,执行时仍会强制应用 OpenClaw 鉴权,并返回 “not authorized”。 -命令目录和行为请参阅[斜杠命令](/zh-CN/tools/slash-commands)。 +参见 [Slash commands](/zh-CN/tools/slash-commands) 了解命令目录和行为。 默认斜杠命令设置: @@ -587,38 +587,17 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - `batched` 注意:`off` 会禁用隐式回复线程。显式的 `[[reply_to_*]]` 标签仍会被遵循。 - `first` 始终会把隐式原生回复引用附加到该轮的第一条 Discord 出站消息上。 - `batched` 仅当入站轮次是由多条消息组成的去抖动批次时,才会附加 Discord 的隐式原生回复引用。当你主要想在含糊不清的突发聊天中使用原生回复,而不是对每一个单消息轮次都使用时,这会很有用。 + `first` 总是会将隐式原生回复引用附加到该轮的第一条 Discord 出站消息上。 + `batched` 仅在入站轮次是由多条消息组成的去抖批次时,才附加 Discord 的隐式原生回复引用。这在你希望原生回复主要用于存在歧义的突发聊天,而不是每一个单条消息轮次时非常有用。 - 消息 ID 会在上下文/历史记录中呈现,因此智能体可以定位特定消息。 + 消息 ID 会在上下文/历史记录中显示,因此智能体可以定位到特定消息。 - OpenClaw 可以通过发送一条临时消息并在文本到达时编辑它,来流式显示草稿回复。 + OpenClaw 可以通过发送一条临时消息并在文本到达时编辑它来流式显示草稿回复。`channels.discord.streaming` 接受 `off`(默认)| `partial` | `block` | `progress`。在 Discord 上,`progress` 会映射为 `partial`;`streamMode` 是旧版别名,会被自动迁移。 - - `channels.discord.streaming` 控制预览流式传输(`off` | `partial` | `block` | `progress`,默认:`off`)。 - - 默认保持 `off`,因为 Discord 预览编辑很容易触发速率限制,尤其是在多个机器人或 Gateway 网关共享同一账户或服务器流量时。 - - 为了跨渠道一致性,接受 `progress`,并在 Discord 上映射为 `partial`。 - - `channels.discord.streamMode` 是旧版别名,会被自动迁移。 - - `partial` 会在 token 到达时编辑单条预览消息。 - - `block` 会输出草稿大小的分块(使用 `draftChunk` 调整大小和断点)。 - - 媒体、错误和显式回复的最终消息会取消待处理的预览编辑,而不会在正常投递前刷新临时草稿。 - - `streaming.preview.toolProgress` 控制工具/进度更新是否复用同一条草稿预览消息(默认:`true`)。设置为 `false` 可保留单独的工具/进度消息。 - - 示例: - -```json5 -{ - channels: { - discord: { - streaming: "partial", - }, - }, -} -``` - - `block` 模式的默认分块设置(会被限制在 `channels.discord.textChunkLimit` 范围内): + 默认保持为 `off`,因为当多个机器人或 Gateway 网关共享同一个账户时,Discord 预览编辑很快会触及速率限制。 ```json5 { @@ -635,13 +614,16 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 } ``` - 预览流式传输仅支持文本;媒体回复会回退为普通投递。 + - `partial` 会在 token 到达时编辑单条预览消息。 + - `block` 会发出草稿大小的分块(使用 `draftChunk` 调整大小和断点,并受 `textChunkLimit` 限制)。 + - 媒体、错误和显式回复的最终消息会取消待处理的预览编辑。 + - `streaming.preview.toolProgress`(默认 `true`)控制工具/进度更新是否复用预览消息。 - 注意:预览流式传输与分块流式传输是分开的。当为 Discord 显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免重复流式传输。 + 预览流式传输仅支持文本;媒体回复会回退为普通投递。当显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。 - + 服务器历史上下文: - `channels.discord.historyLimit` 默认值为 `20` @@ -653,32 +635,27 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - `channels.discord.dmHistoryLimit` - `channels.discord.dms[""].historyLimit` - 帖子串行为: + 线程行为: - - Discord 帖子串作为频道会话进行路由 - - 父帖子串元数据可用于父会话关联 - - 除非存在特定于帖子串的条目,否则帖子串配置会继承父频道配置 - - 新创建的自动帖子串是否继承父转录内容,由 `channels.discord.thread.inheritParent` 选择启用(默认 `false`)。当为 `false` 时,新创建的 Discord 帖子串会话会与父频道转录内容隔离;当为 `true` 时,父频道历史会为新帖子串会话提供初始上下文 - - 按账户覆盖位于 `channels.discord.accounts..thread.inheritParent` - - 消息工具的 reaction 除了频道目标外,也可以解析 `user:` 私信目标 - - `channels.discord.guilds..channels..requireMention: false` 会在回复阶段激活回退期间被保留,因此即使运行回复阶段回退,已配置为始终开启的频道仍会保持始终开启 + - Discord 线程按频道会话路由,并继承父频道配置,除非被覆盖。 + - `channels.discord.thread.inheritParent`(默认 `false`)可选择让新自动线程从父级对话记录中播种。按账户覆盖位于 `channels.discord.accounts..thread.inheritParent` 下。 + - 消息工具的 reactions 可以解析 `user:` 私信目标。 + - `guilds..channels..requireMention: false` 会在回复阶段激活回退期间保留。 - 频道主题会作为**不受信任**的上下文注入(而不是作为系统提示词)。 - 回复和引用消息上下文目前会按接收时的样子保留。 - Discord allowlist 主要用于限制谁可以触发智能体,而不是完整的补充上下文脱敏边界。 + 频道主题会作为**不受信任**的上下文注入。允许列表控制的是谁可以触发智能体,而不是完整的补充上下文脱敏边界。 - Discord 可以将一个帖子串绑定到某个会话目标,这样该帖子串中的后续消息会持续路由到同一个会话(包括子智能体会话)。 + Discord 可以将线程绑定到一个会话目标,以便该线程中的后续消息持续路由到同一个会话(包括子智能体会话)。 命令: - - `/focus ` 将当前/新帖子串绑定到一个子智能体/会话目标 - - `/unfocus` 移除当前帖子串绑定 + - `/focus ` 将当前/新线程绑定到子智能体/会话目标 + - `/unfocus` 移除当前线程绑定 - `/agents` 显示活动运行和绑定状态 - - `/session idle ` 查看/更新聚焦绑定的空闲自动取消聚焦时间 - - `/session max-age ` 查看/更新聚焦绑定的硬性最大存活时间 + - `/session idle ` 检查/更新聚焦绑定的空闲自动取消聚焦 + - `/session max-age ` 检查/更新聚焦绑定的硬性最长存活时间 配置: @@ -707,21 +684,21 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 说明: - `session.threadBindings.*` 设置全局默认值。 - - `channels.discord.threadBindings.*` 会覆盖 Discord 行为。 - - `spawnSubagentSessions` 必须为 true,才能为 `sessions_spawn({ thread: true })` 自动创建/绑定帖子串。 - - `spawnAcpSessions` 必须为 true,才能为 ACP 自动创建/绑定帖子串(`/acp spawn ... --thread ...` 或 `sessions_spawn({ runtime: "acp", thread: true })`)。 - - 如果某个账户禁用了帖子串绑定,则 `/focus` 及相关帖子串绑定操作不可用。 + - `channels.discord.threadBindings.*` 覆盖 Discord 行为。 + - 要为 `sessions_spawn({ thread: true })` 自动创建/绑定线程,必须将 `spawnSubagentSessions` 设为 true。 + - 要为 ACP(`/acp spawn ... --thread ...` 或 `sessions_spawn({ runtime: "acp", thread: true })`)自动创建/绑定线程,必须将 `spawnAcpSessions` 设为 true。 + - 如果某个账户禁用了线程绑定,则 `/focus` 和相关线程绑定操作不可用。 - 请参阅[子智能体](/zh-CN/tools/subagents)、[ACP Agents](/zh-CN/tools/acp-agents) 和[配置参考](/zh-CN/gateway/configuration-reference)。 + 参见 [Sub-agents](/zh-CN/tools/subagents)、[ACP Agents](/zh-CN/tools/acp-agents) 和 [Configuration Reference](/zh-CN/gateway/configuration-reference)。 - 对于稳定的“始终在线” ACP 工作区,可配置顶层的类型化 ACP 绑定,并将其目标指向 Discord 对话。 + 对于稳定的“始终在线” ACP 工作区,可配置顶层的类型化 ACP 绑定,将目标指向 Discord 对话。 配置路径: - - `bindings[]`,其中 `type: "acp"` 且 `match.channel: "discord"` + - 带有 `type: "acp"` 和 `match.channel: "discord"` 的 `bindings[]` 示例: @@ -773,31 +750,27 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 说明: - - `/acp spawn codex --bind here` 会就地绑定当前 Discord 频道或帖子串,并使未来的消息持续路由到同一个 ACP 会话。 - - 这仍然可能意味着“启动一个全新的 Codex ACP 会话”,但它本身不会创建新的 Discord 帖子串。现有频道会继续作为聊天界面。 - - Codex 仍然可能在它自己的 `cwd` 或磁盘上的后端工作区中运行。该工作区是运行时状态,而不是 Discord 帖子串。 - - 帖子串消息可以继承父频道的 ACP 绑定。 - - 在已绑定的频道或帖子串中,`/new` 和 `/reset` 会就地重置同一个 ACP 会话。 - - 临时帖子串绑定仍然可用,并且在生效期间可以覆盖目标解析。 - - 只有当 OpenClaw 需要通过 `--thread auto|here` 创建/绑定子帖子串时,才需要 `spawnAcpSessions`。对于当前频道中的 `/acp spawn ... --bind here`,则不需要。 + - `/acp spawn codex --bind here` 会就地绑定当前频道或线程,并让后续消息持续保留在同一个 ACP 会话中。线程消息会继承父频道绑定。 + - 在已绑定的频道或线程中,`/new` 和 `/reset` 会就地重置同一个 ACP 会话。临时线程绑定在激活期间可以覆盖目标解析。 + - 仅当 OpenClaw 需要通过 `--thread auto|here` 创建/绑定子线程时,才需要 `spawnAcpSessions`。 - 有关绑定行为的详细信息,请参阅 [ACP Agents](/zh-CN/tools/acp-agents)。 + 有关绑定行为的详细信息,参见 [ACP Agents](/zh-CN/tools/acp-agents)。 - - 按服务器配置的 reaction 通知模式: + + 按服务器配置的反应通知模式: - `off` - `own`(默认) - `all` - `allowlist`(使用 `guilds..users`) - Reaction 事件会被转换为系统事件,并附加到路由后的 Discord 会话。 + 反应事件会转换为系统事件,并附加到已路由的 Discord 会话中。 - + `ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认 emoji。 解析顺序: @@ -805,21 +778,21 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - `channels.discord.accounts..ackReaction` - `channels.discord.ackReaction` - `messages.ackReaction` - - 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 “👀”) + - 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 `"👀"`) 说明: - Discord 接受 unicode emoji 或自定义 emoji 名称。 - - 使用 `""` 可为某个渠道或账户禁用该 reaction。 + - 使用 `""` 可为某个渠道或账户禁用该反应。 默认启用由渠道发起的配置写入。 - 这会影响 `/config set|unset` 流程(当命令功能启用时)。 + 这会影响 `/config set|unset` 流程(启用命令功能时)。 - 禁用: + 禁用方式: ```json5 { @@ -834,7 +807,7 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - 使用 `channels.discord.proxy`,通过 HTTP(S) 代理路由 Discord gateway WebSocket 流量和启动时的 REST 查询(application ID + allowlist 解析)。 + 使用 `channels.discord.proxy` 通过 HTTP(S) 代理转发 Discord gateway WebSocket 流量和启动时的 REST 查询(应用 ID + allowlist 解析)。 ```json5 { @@ -865,7 +838,7 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - 启用 PluralKit 解析,将代理消息映射到 system member 身份: + 启用 PluralKit 解析,将代理消息映射到系统成员身份: ```json5 { @@ -883,14 +856,14 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 说明: - allowlist 可以使用 `pk:` - - 只有当 `channels.discord.dangerouslyAllowNameMatching: true` 时,才会按名称/slug 匹配成员显示名 + - 仅当 `channels.discord.dangerouslyAllowNameMatching: true` 时,才会按名称/slug 匹配成员显示名称 - 查询使用原始消息 ID,并受时间窗口限制 - 如果查询失败,代理消息会被视为机器人消息并丢弃,除非设置了 `allowBots=true` - 当你设置状态或活动字段,或启用自动在线状态时,会应用在线状态更新。 + 当你设置状态或活动字段,或启用自动在线状态时,将应用在线状态更新。 仅状态示例: @@ -917,7 +890,7 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 } ``` - Streaming 示例: + 直播示例: ```json5 { @@ -957,7 +930,7 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 } ``` - 自动在线状态会将运行时可用性映射为 Discord 状态:healthy => online,degraded 或 unknown => idle,exhausted 或 unavailable => dnd。可选的文本覆盖项: + 自动在线状态会将运行时可用性映射到 Discord 状态:healthy => online,degraded 或 unknown => idle,exhausted 或 unavailable => dnd。可选文本覆盖: - `autoPresence.healthyText` - `autoPresence.degradedText` @@ -966,69 +939,56 @@ OpenClaw 为智能体消息支持 Discord components v2 容器。请使用带有 - Discord 支持在私信中使用基于按钮的审批处理,并且还可以选择在发起审批的原始频道中发布审批提示。 + Discord 支持在私信中基于按钮处理审批,并且可选择在发起请求的频道中发布审批提示。 配置路径: - `channels.discord.execApprovals.enabled` - - `channels.discord.execApprovals.approvers`(可选;在可能时回退到 `commands.ownerAllowFrom`) + - `channels.discord.execApprovals.approvers`(可选;如果可能,会回退到 `commands.ownerAllowFrom`) - `channels.discord.execApprovals.target`(`dm` | `channel` | `both`,默认:`dm`) - `agentFilter`、`sessionFilter`、`cleanupAfterResolve` - 当 `enabled` 未设置或为 `"auto"`,并且至少可以解析出一个 approver(来自 `execApprovals.approvers` 或 `commands.ownerAllowFrom`)时,Discord 会自动启用原生 exec 审批。Discord 不会从渠道 `allowFrom`、旧版 `dm.allowFrom` 或私信 `defaultTo` 推断 exec approver。将 `enabled: false` 设为显式禁用 Discord 作为原生审批客户端。 + 当 `enabled` 未设置或为 `"auto"`,并且至少可以解析出一个审批人时,Discord 会自动启用原生 exec 审批;审批人可来自 `execApprovals.approvers` 或 `commands.ownerAllowFrom`。Discord 不会从渠道 `allowFrom`、旧版 `dm.allowFrom` 或直接消息的 `defaultTo` 推断 exec 审批人。若要显式禁用 Discord 作为原生审批客户端,请设置 `enabled: false`。 - 当 `target` 为 `channel` 或 `both` 时,审批提示会显示在频道中。只有已解析的 approver 可以使用这些按钮;其他用户会收到仅自己可见的拒绝提示。审批提示包含命令文本,因此仅应在受信任的频道中启用频道投递。如果无法从会话键推导出频道 ID,OpenClaw 会回退为私信投递。 + 当 `target` 为 `channel` 或 `both` 时,审批提示会显示在频道中。只有已解析的审批人可以使用按钮;其他用户会收到一条仅自己可见的拒绝提示。审批提示包含命令文本,因此仅应在受信任频道中启用频道投递。如果无法从会话键推导出频道 ID,OpenClaw 会回退到私信投递。 - Discord 也会渲染其他聊天渠道使用的共享审批按钮。原生 Discord 适配器主要增加了 approver 私信路由和频道扇出。 + Discord 还会渲染其他聊天渠道共用的审批按钮。原生 Discord 适配器主要增加了审批人私信路由和频道扇出。 当这些按钮存在时,它们就是主要的审批 UX;只有当工具结果表明聊天审批不可用,或手动审批是唯一途径时,OpenClaw 才应包含手动 `/approve` 命令。 - 此处理器的 Gateway 网关鉴权使用与其他 Gateway 网关客户端相同的共享凭证解析契约: + Gateway 网关鉴权和审批解析遵循共享的 Gateway 网关客户端契约(`plugin:` ID 通过 `plugin.approval.resolve` 解析;其他 ID 通过 `exec.approval.resolve` 解析)。审批默认会在 30 分钟后过期。 - - 环境变量优先的本地鉴权(`OPENCLAW_GATEWAY_TOKEN` / `OPENCLAW_GATEWAY_PASSWORD`,然后是 `gateway.auth.*`) - - 在本地模式下,仅当 `gateway.auth.*` 未设置时,才可将 `gateway.remote.*` 作为回退;已配置但无法解析的本地 SecretRef 会失败关闭 - - 在适用情况下,通过 `gateway.remote.*` 支持远程模式 - - URL 覆盖是安全的覆盖:CLI 覆盖不会复用隐式凭证,而环境变量覆盖仅使用环境变量凭证 - - 审批解析行为: - - - 以 `plugin:` 为前缀的 ID 通过 `plugin.approval.resolve` 解析。 - - 其他 ID 通过 `exec.approval.resolve` 解析。 - - Discord 不会在这里再执行额外的 exec 到 plugin 回退跳转;ID 前缀决定它调用哪个 Gateway 网关方法。 - - 默认情况下,Exec 审批会在 30 分钟后过期。如果审批因未知审批 ID 而失败,请检查 approver 解析、功能是否已启用,以及已投递的审批 ID 类型是否与待处理请求匹配。 - - 相关文档:[Exec approvals](/zh-CN/tools/exec-approvals) + 参见 [Exec approvals](/zh-CN/tools/exec-approvals)。 ## 工具和操作门控 -Discord 消息操作包括消息传递、频道管理、审核、在线状态和元数据操作。 +Discord 消息操作包括消息发送、频道管理、审核、在线状态和元数据操作。 核心示例: -- 消息传递:`sendMessage`、`readMessages`、`editMessage`、`deleteMessage`、`threadReply` -- reactions:`react`、`reactions`、`emojiList` +- 消息:`sendMessage`、`readMessages`、`editMessage`、`deleteMessage`、`threadReply` +- 反应:`react`、`reactions`、`emojiList` - 审核:`timeout`、`kick`、`ban` - 在线状态:`setPresence` -`event-create` 操作接受一个可选的 `image` 参数(URL 或本地文件路径),用于设置计划事件封面图片。 +`event-create` 操作接受一个可选的 `image` 参数(URL 或本地文件路径),用于设置计划事件封面图像。 操作门控位于 `channels.discord.actions.*` 下。 默认门控行为: -| 操作组 | 默认值 | -| --- | --- | -| reactions、messages、threads、pins、polls、search、memberInfo、roleInfo、channelInfo、channels、voiceStatus、events、stickers、emojiUploads、stickerUploads、permissions | enabled | -| roles | disabled | -| moderation | disabled | -| presence | disabled | +| 操作组 | 默认值 | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | +| reactions、messages、threads、pins、polls、search、memberInfo、roleInfo、channelInfo、channels、voiceStatus、events、stickers、emojiUploads、stickerUploads、permissions | 已启用 | +| roles | 已禁用 | +| moderation | 已禁用 | +| presence | 已禁用 | ## Components v2 UI -OpenClaw 使用 Discord components v2 作为 exec 审批和跨上下文标记的 UI。Discord 消息操作也可以接受 `components` 用于自定义 UI(高级用法;需要通过 discord 工具构造组件负载),而旧版 `embeds` 仍然可用,但不推荐。 +OpenClaw 对 exec 审批和跨上下文标记使用 Discord components v2。Discord 消息操作也可以接受 `components` 用于自定义 UI(高级用法;需要通过 discord 工具构造组件负载);旧版 `embeds` 仍可用,但不推荐。 - `channels.discord.ui.components.accentColor` 设置 Discord 组件容器使用的强调色(hex)。 - 可通过 `channels.discord.accounts..ui.components.accentColor` 按账户设置。 @@ -1050,17 +1010,19 @@ OpenClaw 使用 Discord components v2 作为 exec 审批和跨上下文标记的 } ``` -## 语音频道 +## 语音 -OpenClaw 可以加入 Discord 语音频道,以实现实时、连续的对话。这与语音消息附件是分开的。 +Discord 有两种不同的语音表面:实时**语音频道**(连续对话)和**语音消息附件**(波形预览格式)。Gateway 网关同时支持这两者。 + +### 语音频道 要求: - 启用原生命令(`commands.native` 或 `channels.discord.commands.native`)。 - 配置 `channels.discord.voice`。 -- 机器人需要在目标语音频道中拥有 Connect 和 Speak 权限。 +- 机器人在目标语音频道中需要 Connect 和 Speak 权限。 -使用仅限 Discord 的原生命令 `/vc join|leave|status` 来控制会话。该命令使用账户默认智能体,并遵循与其他 Discord 命令相同的 allowlist 和 group policy 规则。 +使用 `/vc join|leave|status` 控制会话。该命令使用账户默认智能体,并遵循与其他 Discord 命令相同的 allowlist 和服务器策略规则。 自动加入示例: @@ -1091,25 +1053,21 @@ OpenClaw 可以加入 Discord 语音频道,以实现实时、连续的对话 说明: - `voice.tts` 仅对语音播放覆盖 `messages.tts`。 -- 语音转录轮次会根据 Discord `allowFrom`(或 `dm.allowFrom`)派生 owner 状态;非 owner 的说话者无法访问仅限 owner 的工具(例如 `gateway` 和 `cron`)。 -- 语音默认启用;设置 `channels.discord.voice.enabled=false` 可禁用它。 +- 语音转写轮次会从 Discord `allowFrom`(或 `dm.allowFrom`)派生所有者状态;非所有者说话者无法访问仅所有者可用的工具(例如 `gateway` 和 `cron`)。 +- 默认启用语音;设置 `channels.discord.voice.enabled=false` 可禁用。 - `voice.daveEncryption` 和 `voice.decryptionFailureTolerance` 会透传给 `@discordjs/voice` 的加入选项。 -- 如果未设置,`@discordjs/voice` 的默认值为 `daveEncryption=true` 和 `decryptionFailureTolerance=24`。 -- OpenClaw 还会监控接收解密失败,并在短时间内重复失败后,通过离开/重新加入语音频道自动恢复。 -- 如果接收日志反复显示 `DecryptionFailed(UnencryptedWhenPassthroughDisabled)`,这可能是上游 `@discordjs/voice` 的接收 bug,记录在 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419) 中。 +- 如果未设置,`@discordjs/voice` 的默认值是 `daveEncryption=true` 和 `decryptionFailureTolerance=24`。 +- OpenClaw 还会监视接收解密失败,并在短时间内重复失败后通过离开/重新加入语音频道自动恢复。 +- 如果接收日志反复显示 `DecryptionFailed(UnencryptedWhenPassthroughDisabled)`,这可能是上游 `@discordjs/voice` 接收 bug,见 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419)。 -## 语音消息 +### 语音消息 -Discord 语音消息会显示波形预览,并且需要 OGG/Opus 音频和元数据。OpenClaw 会自动生成波形,但它需要在 Gateway 网关主机上可用的 `ffmpeg` 和 `ffprobe` 来检查和转换音频文件。 +Discord 语音消息会显示波形预览,并要求使用 OGG/Opus 音频。OpenClaw 会自动生成波形,但需要在 Gateway 网关主机上安装 `ffmpeg` 和 `ffprobe` 来进行检测和转换。 -要求和限制: - -- 提供**本地文件路径**(URL 会被拒绝)。 -- 省略文本内容(Discord 不允许在同一负载中同时发送文本和语音消息)。 +- 提供**本地文件路径**(不接受 URL)。 +- 不要附带文本内容(Discord 会拒绝在同一负载中同时包含文本和语音消息)。 - 接受任意音频格式;OpenClaw 会在需要时将其转换为 OGG/Opus。 -示例: - ```bash message(action="send", channel="discord", target="channel:123", path="/path/to/audio.mp3", asVoice=true) ``` @@ -1129,7 +1087,7 @@ message(action="send", channel="discord", target="channel:123", path="/path/to/a - 验证 `groupPolicy` - 验证 `channels.discord.guilds` 下的服务器 allowlist - - 如果存在服务器 `channels` 映射,则只允许列出的频道 + - 如果存在服务器 `channels` 映射,则只允许其中列出的频道 - 验证 `requireMention` 行为和提及模式 有用的检查: @@ -1142,16 +1100,16 @@ openclaw logs --follow - + 常见原因: - `groupPolicy="allowlist"`,但没有匹配的服务器/频道 allowlist - - `requireMention` 配置在错误的位置(必须位于 `channels.discord.guilds` 或频道条目下) + - `requireMention` 配置在错误位置(必须位于 `channels.discord.guilds` 或频道条目下) - 发送者被服务器/频道 `users` allowlist 阻止 - + 典型日志: @@ -1159,16 +1117,16 @@ openclaw logs --follow - `Slow listener detected ...` - `discord inbound worker timed out after ...` - 监听器预算旋钮: + 监听器预算控制项: - 单账户:`channels.discord.eventQueue.listenerTimeout` - 多账户:`channels.discord.accounts..eventQueue.listenerTimeout` - Worker 运行超时旋钮: + Worker 运行超时控制项: - 单账户:`channels.discord.inboundWorker.runTimeoutMs` - 多账户:`channels.discord.accounts..inboundWorker.runTimeoutMs` - - 默认值:`1800000`(30 分钟);设置为 `0` 可禁用 + - 默认值:`1800000`(30 分钟);设为 `0` 可禁用 推荐基线: @@ -1191,14 +1149,14 @@ openclaw logs --follow } ``` - 对于缓慢的监听器初始化,请使用 `eventQueue.listenerTimeout`;只有在你希望为排队的智能体轮次设置单独的安全阀时,才使用 `inboundWorker.runTimeoutMs`。 + 对于缓慢的监听器初始化,请使用 `eventQueue.listenerTimeout`;只有在你希望为排队的智能体轮次设置单独安全阀时,才使用 `inboundWorker.runTimeoutMs`。 `channels status --probe` 权限检查仅适用于数字频道 ID。 - 如果你使用 slug 键,运行时匹配仍然可以工作,但探测无法完整验证权限。 + 如果你使用 slug 键,运行时匹配仍然可能正常工作,但探测无法完整验证权限。 @@ -1211,22 +1169,22 @@ openclaw logs --follow - 默认情况下,由机器人发送的消息会被忽略。 + 默认情况下,会忽略由机器人发送的消息。 - 如果你设置了 `channels.discord.allowBots=true`,请使用严格的提及和 allowlist 规则,以避免循环行为。 - 建议使用 `channels.discord.allowBots="mentions"`,仅接受提及该机器人的机器人消息。 + 如果你设置了 `channels.discord.allowBots=true`,请使用严格的提及和 allowlist 规则以避免循环行为。 + 优先使用 `channels.discord.allowBots="mentions"`,这样只接受提及该机器人的机器人消息。 - - 保持 OpenClaw 为最新版本(`openclaw update`),以确保存在 Discord 语音接收恢复逻辑 - - 确认 `channels.discord.voice.daveEncryption=true`(默认) - - 从 `channels.discord.voice.decryptionFailureTolerance=24`(上游默认值)开始,仅在必要时调整 - - 关注日志中的以下内容: + - 保持 OpenClaw 为最新版本(`openclaw update`),以确保包含 Discord 语音接收恢复逻辑 + - 确认 `channels.discord.voice.daveEncryption=true`(默认值) + - 从 `channels.discord.voice.decryptionFailureTolerance=24`(上游默认值)开始,仅在需要时调整 + - 观察日志中的以下内容: - `discord voice: DAVE decrypt failures detected` - `discord voice: repeated decrypt failures; attempting rejoin` - - 如果自动重新加入后故障仍然持续,请收集日志并与 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419) 进行对比 + - 如果自动重新加入后问题仍持续,请收集日志并与 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419) 对照 @@ -1235,7 +1193,7 @@ openclaw logs --follow 主要参考: -- [配置参考 - Discord](/zh-CN/gateway/configuration-reference#discord) +- [Configuration reference - Discord](/zh-CN/gateway/configuration-reference#discord) 高信号 Discord 字段: diff --git a/docs/zh-CN/gateway/configuration.md b/docs/zh-CN/gateway/configuration.md index 10984cb2f..10d7c093a 100644 --- a/docs/zh-CN/gateway/configuration.md +++ b/docs/zh-CN/gateway/configuration.md @@ -2,14 +2,14 @@ read_when: - 首次设置 OpenClaw - 查找常见配置模式 - - 跳转到特定配置章节 -summary: 配置概览:常见任务、快速设置,以及完整参考的链接 + - 导航到特定配置部分 +summary: 配置概览:常见任务、快速设置,以及指向完整参考的链接 title: 配置 x-i18n: - generated_at: "2026-04-23T08:14:07Z" + generated_at: "2026-04-23T08:25:19Z" model: gpt-5.4 provider: openai - source_hash: a674bbc73f3a501ffd47ef9396d55d6087806921cfb24ef576398022dd0248c3 + source_hash: d76b40c25f98de791e0d8012b2bc5b80e3e38dde99bb9105539e800ddac3f362 source_path: gateway/configuration.md workflow: 15 --- @@ -17,20 +17,21 @@ x-i18n: # 配置 OpenClaw 会从 `~/.openclaw/openclaw.json` 读取一个可选的 **JSON5** 配置。 -当前使用的配置路径必须是一个常规文件。对于由 OpenClaw 管理的写入操作,不支持将 `openclaw.json` -布局为符号链接;原子写入可能会替换该路径, -而不是保留符号链接。如果你将配置保存在默认状态目录之外,请将 `OPENCLAW_CONFIG_PATH` 直接指向真实文件。 +当前使用的配置路径必须是一个常规文件。对于 OpenClaw 自身发起的写入操作, +不支持使用符号链接形式的 `openclaw.json` 布局;原子写入可能会替换该路径, +而不是保留符号链接。如果你将配置保存在默认状态目录之外,请将 +`OPENCLAW_CONFIG_PATH` 直接指向真实文件。 -如果该文件不存在,OpenClaw 会使用安全默认值。添加配置的常见原因包括: +如果文件缺失,OpenClaw 会使用安全的默认值。添加配置的常见原因包括: -- 连接渠道并控制谁可以向机器人发消息 -- 设置模型、工具、沙箱隔离或自动化(cron、hooks) +- 连接渠道并控制谁可以向机器人发送消息 +- 设置模型、工具、沙箱隔离或自动化功能(cron、hooks) - 调整会话、媒体、网络或 UI -请参阅[完整参考](/zh-CN/gateway/configuration-reference)了解所有可用字段。 +有关所有可用字段,请参阅[完整参考](/zh-CN/gateway/configuration-reference)。 -**刚接触配置?** 可先运行 `openclaw onboard` 进行交互式设置,或查看[配置示例](/zh-CN/gateway/configuration-examples)指南,获取可直接复制粘贴的完整配置。 +**刚接触配置?** 可以从 `openclaw onboard` 开始进行交互式设置,或者查看 [Configuration Examples](/zh-CN/gateway/configuration-examples) 指南,获取可直接复制粘贴的完整配置。 ## 最小配置 @@ -48,7 +49,7 @@ OpenClaw 会从 `~/.openclaw/openclaw.json` 读取一个可选的 ```bash - openclaw onboard # 完整新手引导流程 + openclaw onboard # 完整的新手引导流程 openclaw configure # 配置向导 ``` @@ -60,51 +61,50 @@ OpenClaw 会从 `~/.openclaw/openclaw.json` 读取一个可选的 - 打开 [http://127.0.0.1:18789](http://127.0.0.1:18789) 并使用 **配置** 标签页。 - 控制 UI 会根据实时配置 schema 渲染表单,其中包括字段 - `title` / `description` 文档元数据,以及可用时的插件和渠道 schema, - 同时提供 **原始 JSON** 编辑器作为兜底方式。对于逐层下钻 - UI 和其他工具,Gateway 网关 还暴露了 `config.schema.lookup`, - 用于获取单个按路径限定的 schema 节点及其直接子项摘要。 + 打开 [http://127.0.0.1:18789](http://127.0.0.1:18789),然后使用 **配置** 选项卡。 + 控制 UI 会根据当前配置 schema 渲染表单,其中包括字段 + `title` / `description` 文档元数据,以及在可用情况下的插件和渠道 schema, + 同时还提供一个 **Raw JSON** 编辑器作为兜底入口。对于下钻式 + UI 和其他工具,Gateway 网关 还提供了 `config.schema.lookup`,用于 + 获取单个路径范围内的 schema 节点及其直接子节点摘要。 - 直接编辑 `~/.openclaw/openclaw.json`。Gateway 网关 会监视该文件并自动应用更改(请参阅[热重载](#config-hot-reload))。 + 直接编辑 `~/.openclaw/openclaw.json`。Gateway 网关 会监视该文件并自动应用更改(参见[热重载](#config-hot-reload))。 ## 严格校验 -OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错误或无效值都会导致 Gateway 网关 **拒绝启动**。唯一的根级例外是 `$schema`(字符串),这样编辑器就可以附加 JSON Schema 元数据。 +OpenClaw 只接受与 schema 完全匹配的配置。未知键名、格式错误的类型或无效值都会导致 Gateway 网关 **拒绝启动**。唯一的根级例外是 `$schema`(字符串),这样编辑器就可以附加 JSON Schema 元数据。 -`openclaw config schema` 会输出控制 UI -和校验所使用的规范 JSON Schema。`config.schema.lookup` 会获取单个按路径限定的节点以及 -子项摘要,用于逐层下钻工具。字段 `title`/`description` 文档元数据 +`openclaw config schema` 会打印供控制 UI +和校验使用的规范 JSON Schema。`config.schema.lookup` 会获取单个路径范围内的节点及其 +子节点摘要,用于下钻式工具。字段 `title`/`description` 文档元数据 会传递到嵌套对象、通配符(`*`)、数组项(`[]`)以及 `anyOf`/ -`oneOf`/`allOf` 分支。加载 manifest 注册表后, -运行时插件和渠道 schema 也会合并进来。 +`oneOf`/`allOf` 分支中。当清单注册表加载后,运行时插件和渠道 schema 也会合并进来。 当校验失败时: - Gateway 网关 不会启动 - 只有诊断命令可用(`openclaw doctor`、`openclaw logs`、`openclaw health`、`openclaw status`) - 运行 `openclaw doctor` 查看具体问题 -- 运行 `openclaw doctor --fix`(或 `--yes`)应用修复 +- 运行 `openclaw doctor --fix`(或 `--yes`)以应用修复 -每次成功启动后,Gateway 网关 都会保留一份可信的“最后已知正常”副本。 -如果之后 `openclaw.json` 未通过校验(或丢失 `gateway.mode`、体积 -明显缩小,或前面误加了一行日志),OpenClaw 会将损坏的文件 -保存为 `.clobbered.*`,恢复最后已知正常的副本,并记录恢复 -原因。下一次智能体回合也会收到系统事件警告,这样主 -智能体就不会盲目重写已恢复的配置。当候选配置包含已脱敏的密钥占位符(例如 `***`)时, -将其提升为最后已知正常副本的操作会被跳过。 +Gateway 网关 在每次成功启动后都会保留一份受信任的“上次已知正常”副本。 +如果之后 `openclaw.json` 未通过校验(或缺少 `gateway.mode`、体积明显缩小, +或前面意外插入了一行日志),OpenClaw 会将损坏的文件保留为 +`.clobbered.*`,恢复“上次已知正常”副本,并记录恢复原因。 +下一次智能体回合也会收到一条系统事件警告,这样主智能体就不会盲目重写已恢复的配置。 +当候选配置中包含诸如 `***` 之类已脱敏的密钥占位符时, +将其提升为“上次已知正常”副本的操作会被跳过。 ## 常见任务 - 每个渠道在 `channels.` 下都有自己的配置段。请查看对应渠道页面了解设置步骤: + 每个渠道在 `channels.` 下都有自己的配置部分。设置步骤请参见对应的专用渠道页面: - [WhatsApp](/zh-CN/channels/whatsapp) — `channels.whatsapp` - [Telegram](/zh-CN/channels/telegram) — `channels.telegram` @@ -117,7 +117,7 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 - [iMessage](/zh-CN/channels/imessage) — `channels.imessage` - [Mattermost](/zh-CN/channels/mattermost) — `channels.mattermost` - 所有渠道都遵循相同的私信策略模式: + 所有渠道都共享相同的私信策略模式: ```json5 { @@ -126,7 +126,7 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 enabled: true, botToken: "123:abc", dmPolicy: "pairing", // pairing | allowlist | open | disabled - allowFrom: ["tg:123"], // 仅用于 allowlist/open + allowFrom: ["tg:123"], // only for allowlist/open }, }, } @@ -135,7 +135,7 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 - 设置主模型以及可选的回退模型: + 设置主模型和可选的后备模型: ```json5 { @@ -154,26 +154,26 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - - `agents.defaults.models` 用于定义模型目录,同时也是 `/model` 的允许列表。 - - 使用 `openclaw config set agents.defaults.models '' --strict-json --merge` 可在不移除现有模型的情况下添加允许列表条目。如果普通替换会移除条目,则会被拒绝,除非你传入 `--replace`。 + - `agents.defaults.models` 定义模型目录,并充当 `/model` 的允许列表。 + - 使用 `openclaw config set agents.defaults.models '' --strict-json --merge` 添加允许列表条目,而不会移除现有模型。会删除条目的普通替换操作将被拒绝,除非你传入 `--replace`。 - 模型引用使用 `provider/model` 格式(例如 `anthropic/claude-opus-4-6`)。 - - `agents.defaults.imageMaxDimensionPx` 控制转录/工具图像的缩放上限(默认 `1200`);在大量使用截图的运行中,较低的值通常会减少视觉 token 的使用量。 - - 请参阅[模型 CLI](/zh-CN/concepts/models)了解如何在聊天中切换模型,并参阅[模型故障切换](/zh-CN/concepts/model-failover)了解凭证轮换和回退行为。 - - 对于自定义/自托管提供商,请参阅参考中的[自定义提供商](/zh-CN/gateway/configuration-reference#custom-providers-and-base-urls)。 + - `agents.defaults.imageMaxDimensionPx` 控制对话记录/工具图像的缩放上限(默认 `1200`);在截图较多的运行中,较低的值通常能减少视觉 token 的使用量。 + - 在聊天中切换模型,请参见 [Models CLI](/zh-CN/concepts/models);关于凭证轮换和后备行为,请参见 [Model Failover](/zh-CN/concepts/model-failover)。 + - 对于自定义/自托管提供商,请参见参考文档中的 [Custom providers](/zh-CN/gateway/configuration-reference#custom-providers-and-base-urls)。 - - 私信访问按渠道通过 `dmPolicy` 控制: + + 私信访问通过每个渠道的 `dmPolicy` 进行控制: - `"pairing"`(默认):未知发送者会收到一次性配对码以供批准 - - `"allowlist"`:仅允许 `allowFrom` 中的发送者(或已配对允许存储中的发送者) + - `"allowlist"`:仅允许 `allowFrom` 中的发送者(或已配对的允许存储) - `"open"`:允许所有入站私信(需要 `allowFrom: ["*"]`) - `"disabled"`:忽略所有私信 - 对于群组,请使用 `groupPolicy` + `groupAllowFrom` 或渠道专用允许列表。 + 对于群组,请使用 `groupPolicy` + `groupAllowFrom` 或渠道专用的允许列表。 - 请参阅[完整参考](/zh-CN/gateway/configuration-reference#dm-and-group-access)了解各渠道的详细信息。 + 有关每个渠道的详细信息,请参见[完整参考](/zh-CN/gateway/configuration-reference#dm-and-group-access)。 @@ -201,14 +201,14 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 ``` - **元数据提及**:原生 @ 提及(WhatsApp 点按提及、Telegram @bot 等) - - **文本模式**:`mentionPatterns` 中的安全正则模式 - - 请参阅[完整参考](/zh-CN/gateway/configuration-reference#group-chat-mention-gating)了解各渠道覆盖项和 self-chat 模式。 + - **文本模式**:`mentionPatterns` 中的安全正则表达式模式 + - 有关每个渠道的覆盖规则和自聊模式,请参见[完整参考](/zh-CN/gateway/configuration-reference#group-chat-mention-gating)。 - 使用 `agents.defaults.skills` 作为共享基线,然后通过 `agents.list[].skills` 覆盖特定 - 智能体: + 使用 `agents.defaults.skills` 作为共享基线,然后通过 + `agents.list[].skills` 覆盖特定智能体: ```json5 { @@ -219,22 +219,22 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 list: [ { id: "writer" }, // 继承 github、weather { id: "docs", skills: ["docs-search"] }, // 替换默认值 - { id: "locked-down", skills: [] }, // 不启用任何 Skills + { id: "locked-down", skills: [] }, // 无 Skills ], }, } ``` - - 省略 `agents.defaults.skills` 表示默认不限制 Skills。 - - 省略 `agents.list[].skills` 表示继承默认值。 - - 设置 `agents.list[].skills: []` 表示不启用任何 Skills。 - - 请参阅 [Skills](/zh-CN/tools/skills)、[Skills 配置](/zh-CN/tools/skills-config) 以及 + - 省略 `agents.defaults.skills` 可使默认 Skills 不受限制。 + - 省略 `agents.list[].skills` 将继承默认值。 + - 设置 `agents.list[].skills: []` 表示不启用 Skills。 + - 请参见 [Skills](/zh-CN/tools/skills)、[Skills 配置](/zh-CN/tools/skills-config) 和 [配置参考](/zh-CN/gateway/configuration-reference#agents-defaults-skills)。 - 控制 Gateway 网关 对看起来已卡住的渠道进行重启的激进程度: + 控制 Gateway 网关 对看起来已停滞的渠道执行重启的激进程度: ```json5 { @@ -256,20 +256,20 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - - 将 `gateway.channelHealthCheckMinutes: 0` 设为 0 可在全局禁用健康监控重启。 + - 设置 `gateway.channelHealthCheckMinutes: 0` 可全局禁用健康监控重启。 - `channelStaleEventThresholdMinutes` 应大于或等于检查间隔。 - - 使用 `channels..healthMonitor.enabled` 或 `channels..accounts..healthMonitor.enabled`,可只为某个渠道或账号禁用自动重启,而无需禁用全局监控。 - - 请参阅[健康检查](/zh-CN/gateway/health)了解运维调试方法,并参阅[完整参考](/zh-CN/gateway/configuration-reference#gateway)了解所有字段。 + - 使用 `channels..healthMonitor.enabled` 或 `channels..accounts..healthMonitor.enabled`,可对单个渠道或账户禁用自动重启,而无需禁用全局监控。 + - 关于运维调试,请参见[健康检查](/zh-CN/gateway/health);有关所有字段,请参见[完整参考](/zh-CN/gateway/configuration-reference#gateway)。 - 会话控制对话连续性和隔离性: + 会话控制对话的连续性和隔离性: ```json5 { session: { - dmScope: "per-channel-peer", // 推荐用于多用户 + dmScope: "per-channel-peer", // recommended for multi-user threadBindings: { enabled: true, idleHours: 24, @@ -285,9 +285,9 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 ``` - `dmScope`:`main`(共享)| `per-peer` | `per-channel-peer` | `per-account-channel-peer` - - `threadBindings`:用于线程绑定会话路由的全局默认值(Discord 支持 `/focus`、`/unfocus`、`/agents`、`/session idle` 和 `/session max-age`)。 - - 请参阅[会话管理](/zh-CN/concepts/session)了解作用域、身份关联和发送策略。 - - 请参阅[完整参考](/zh-CN/gateway/configuration-reference#session)了解所有字段。 + - `threadBindings`:线程绑定会话路由的全局默认值(Discord 支持 `/focus`、`/unfocus`、`/agents`、`/session idle` 和 `/session max-age`)。 + - 关于作用域、身份关联和发送策略,请参见[会话管理](/zh-CN/concepts/session)。 + - 有关所有字段,请参见[完整参考](/zh-CN/gateway/configuration-reference#session)。 @@ -307,16 +307,16 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - 请先构建镜像:`scripts/sandbox-setup.sh` + 先构建镜像:`scripts/sandbox-setup.sh` - 请参阅[沙箱隔离](/zh-CN/gateway/sandboxing)了解完整指南,并参阅[完整参考](/zh-CN/gateway/configuration-reference#agentsdefaultssandbox)了解所有选项。 + 完整指南请参见[沙箱隔离](/zh-CN/gateway/sandboxing),所有选项请参见[完整参考](/zh-CN/gateway/configuration-reference#agentsdefaultssandbox)。 - 基于 relay 的推送在 `openclaw.json` 中进行配置。 + 基于 relay 的推送在 `openclaw.json` 中配置。 - 在 Gateway 网关 配置中设置以下内容: + 在 Gateway 网关 配置中设置: ```json5 { @@ -334,43 +334,43 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - CLI 等效命令: + 对应的 CLI 命令: ```bash openclaw config set gateway.push.apns.relay.baseUrl https://relay.example.com ``` - 作用如下: + 这会执行以下操作: - - 让 Gateway 网关 可以通过外部 relay 发送 `push.test`、唤醒提示和重连唤醒。 - - 使用由已配对 iOS 应用转发的、以注册为作用域的发送授权。Gateway 网关 不需要部署范围的 relay token。 - - 将每个基于 relay 的注册绑定到 iOS 应用所配对的 Gateway 网关 身份,因此其他 Gateway 网关 无法复用已存储的注册信息。 - - 本地/手动 iOS 构建仍使用直接 APNs。基于 relay 的发送仅适用于通过 relay 完成注册的官方分发构建。 - - 必须与官方/TestFlight iOS 构建中内置的 relay 基础 URL 保持一致,这样注册流量和发送流量才能到达同一个 relay 部署。 + - 允许 Gateway 网关 通过外部 relay 发送 `push.test`、唤醒提示和重连唤醒。 + - 使用由已配对 iOS 应用转发的、限定注册范围的发送授权。Gateway 网关 不需要部署范围的 relay token。 + - 将每个基于 relay 的注册绑定到 iOS 应用配对时所连接的 Gateway 网关 身份,因此其他 Gateway 网关 无法复用已存储的注册信息。 + - 本地/手动构建的 iOS 版本仍使用直接 APNs。基于 relay 的发送仅适用于通过 relay 注册的官方分发构建版本。 + - 必须与官方/TestFlight iOS 构建中内置的 relay base URL 匹配,这样注册和发送流量才会到达同一个 relay 部署。 端到端流程: - 1. 安装一个使用相同 relay 基础 URL 编译的官方/TestFlight iOS 构建。 + 1. 安装一个使用相同 relay base URL 编译的官方/TestFlight iOS 构建版本。 2. 在 Gateway 网关 上配置 `gateway.push.apns.relay.baseUrl`。 - 3. 将 iOS 应用与 Gateway 网关 配对,并让节点会话和操作员会话都连接上。 + 3. 将 iOS 应用与 Gateway 网关 配对,并让节点会话和操作员会话都建立连接。 4. iOS 应用获取 Gateway 网关 身份,使用 App Attest 和应用收据向 relay 注册,然后将基于 relay 的 `push.apns.register` 负载发布到已配对的 Gateway 网关。 - 5. Gateway 网关 存储 relay 句柄和发送授权,然后将其用于 `push.test`、唤醒提示和重连唤醒。 + 5. Gateway 网关 存储 relay 句柄和发送授权,然后将它们用于 `push.test`、唤醒提示和重连唤醒。 运行说明: - - 如果你将 iOS 应用切换到另一个 Gateway 网关,请重新连接该应用,以便它发布一个绑定到该 Gateway 网关 的新 relay 注册。 - - 如果你发布了一个指向不同 relay 部署的新 iOS 构建,应用会刷新其缓存的 relay 注册,而不是复用旧的 relay 来源。 + - 如果你将 iOS 应用切换到另一个 Gateway 网关,请重新连接应用,以便它发布绑定到该 Gateway 网关 的新 relay 注册信息。 + - 如果你发布了一个指向不同 relay 部署的新 iOS 构建版本,应用会刷新其缓存的 relay 注册信息,而不是复用旧的 relay 来源。 兼容性说明: - `OPENCLAW_APNS_RELAY_BASE_URL` 和 `OPENCLAW_APNS_RELAY_TIMEOUT_MS` 仍可作为临时环境变量覆盖项使用。 - - `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true` 仍然是仅限 local loopback 的开发逃生阀;不要在配置中持久化 HTTP relay URL。 + - `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true` 仍然只是一个仅限 local loopback 的开发逃生口;不要在配置中持久保存 HTTP relay URL。 - 请参阅 [iOS App](/zh-CN/platforms/ios#relay-backed-push-for-official-builds) 了解端到端流程,并参阅 [Authentication and trust flow](/zh-CN/platforms/ios#authentication-and-trust-flow) 了解 relay 安全模型。 + 有关端到端流程,请参见 [iOS App](/zh-CN/platforms/ios#relay-backed-push-for-official-builds);有关 relay 安全模型,请参见 [Authentication and trust flow](/zh-CN/platforms/ios#authentication-and-trust-flow)。 - + ```json5 { agents: { @@ -384,10 +384,10 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - - `every`:时长字符串(`30m`、`2h`)。设为 `0m` 可禁用。 + - `every`:时长字符串(`30m`、`2h`)。设置为 `0m` 可禁用。 - `target`:`last` | `none` | ``(例如 `discord`、`matrix`、`telegram` 或 `whatsapp`) - - `directPolicy`:用于私信式 heartbeat 目标的 `allow`(默认)或 `block` - - 请参阅 [Heartbeat](/zh-CN/gateway/heartbeat) 了解完整指南。 + - `directPolicy`:对于私信式心跳目标,可设为 `allow`(默认)或 `block` + - 完整指南请参见 [Heartbeat](/zh-CN/gateway/heartbeat)。 @@ -406,13 +406,13 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - - `sessionRetention`:从 `sessions.json` 中清理已完成的隔离运行会话(默认 `24h`;设为 `false` 可禁用)。 + - `sessionRetention`:从 `sessions.json` 中清理已完成的隔离运行会话(默认 `24h`;设置为 `false` 可禁用)。 - `runLog`:按大小和保留行数清理 `cron/runs/.jsonl`。 - - 请参阅 [Cron jobs](/zh-CN/automation/cron-jobs) 了解功能概览和 CLI 示例。 + - 功能概览和 CLI 示例请参见 [Cron jobs](/zh-CN/automation/cron-jobs)。 - + 在 Gateway 网关 上启用 HTTP webhook 端点: ```json5 @@ -442,15 +442,15 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 - Hook 身份验证仅支持请求头(`Authorization: Bearer ...` 或 `x-openclaw-token`);查询字符串 token 会被拒绝。 - `hooks.path` 不能为 `/`;请将 webhook 入口保留在专用子路径下,例如 `/hooks`。 - 保持不安全内容绕过标志为禁用状态(`hooks.gmail.allowUnsafeExternalContent`、`hooks.mappings[].allowUnsafeExternalContent`),除非你是在进行严格限定范围的调试。 - - 如果你启用了 `hooks.allowRequestSessionKey`,也要设置 `hooks.allowedSessionKeyPrefixes` 以限制调用方可选择的会话键。 - - 对于由 hook 驱动的智能体,优先使用更强的现代模型层级和严格的工具策略(例如仅限消息传递,并尽可能配合沙箱隔离)。 + - 如果你启用了 `hooks.allowRequestSessionKey`,也要同时设置 `hooks.allowedSessionKeyPrefixes`,以限制调用方可选的会话键。 + - 对于由 hook 驱动的智能体,优先使用强大的现代模型层级和严格的工具策略(例如仅消息传递,并在可能时启用沙箱隔离)。 - 请参阅[完整参考](/zh-CN/gateway/configuration-reference#hooks)了解所有映射选项和 Gmail 集成。 + 有关所有映射选项和 Gmail 集成,请参见[完整参考](/zh-CN/gateway/configuration-reference#hooks)。 - 运行多个彼此隔离的智能体,并分别使用独立工作区和会话: + 运行多个相互隔离的智能体,并为其分配独立的工作区和会话: ```json5 { @@ -467,7 +467,7 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - 请参阅 [Multi-Agent](/zh-CN/concepts/multi-agent) 和[完整参考](/zh-CN/gateway/configuration-reference#multi-agent-routing)了解绑定规则和每个智能体的访问配置文件。 + 绑定规则和每个智能体的访问配置文件,请参见 [Multi-Agent](/zh-CN/concepts/multi-agent) 和[完整参考](/zh-CN/gateway/configuration-reference#multi-agent-routing)。 @@ -485,47 +485,46 @@ OpenClaw 只接受完全符合 schema 的配置。未知键名、类型格式错 } ``` - - **单个文件**:替换其所在对象 - - **文件数组**:按顺序深度合并(后者覆盖前者) - - **同级键**:在 include 之后合并(覆盖被包含值) + - **单个文件**:替换所在对象 + - **文件数组**:按顺序深度合并(后者优先) + - **同级键**:在 include 之后再合并(覆盖引入的值) - **嵌套 include**:支持,最多 10 层 - - **相对路径**:相对于包含它的文件进行解析 - - **由 OpenClaw 管理的写入**:当一次写入只更改一个顶级分区, - 且该分区由单文件 include 支撑时,例如 `plugins: { $include: "./plugins.json5" }`, - OpenClaw 会更新该被包含文件,并保持 `openclaw.json` 不变 - - **不支持的透传写入**:根级 include、include 数组以及带有 - 同级覆盖项的 include,在 OpenClaw 管理的写入场景下会以安全关闭方式失败, - 而不会将配置拍平 - - **错误处理**:对于缺失文件、解析错误和循环 include 提供清晰错误信息 + - **相对路径**:相对于包含它的文件解析 + - **由 OpenClaw 发起的写入**:当一次写入只更改一个由单文件 include + 支撑的顶层部分时,例如 `plugins: { $include: "./plugins.json5" }`, + OpenClaw 会更新该被引入文件,并保持 `openclaw.json` 不变 + - **不支持透传写入**:对于根级 include、include 数组以及带有 + 同级覆盖的 include,OpenClaw 发起的写入会以封闭失败方式终止,而不是 + 将配置拍平 + - **错误处理**:对缺失文件、解析错误和循环 include 提供清晰错误信息 ## 配置热重载 -Gateway 网关 会监视 `~/.openclaw/openclaw.json` 并自动应用更改——大多数设置都不需要手动重启。 +Gateway 网关 会监视 `~/.openclaw/openclaw.json` 并自动应用更改 —— 对于大多数设置,无需手动重启。 -直接编辑文件在通过校验前会被视为不可信。监视器会等待 -编辑器的临时写入/重命名抖动稳定下来,读取最终文件,并通过恢复最后已知正常配置来拒绝 -无效的外部编辑。由 OpenClaw 管理的 -配置写入在写入前也会通过同样的 schema 门控;像删除 `gateway.mode` -或将文件缩小到不足原来一半这类破坏性覆盖,会被拒绝, +直接编辑文件会在通过校验前被视为不可信。监视器会等待 +编辑器的临时写入/重命名抖动稳定下来,读取最终文件,并通过恢复 +“上次已知正常”配置来拒绝无效的外部编辑。由 OpenClaw 发起的 +配置写入在落盘前也会经过相同的 schema 校验;具有破坏性的覆盖行为,例如 +删除 `gateway.mode` 或将文件缩小到原来的一半以下,会被拒绝, 并保存为 `.rejected.*` 以供检查。 如果你在日志中看到 `Config auto-restored from last-known-good` 或 -`config reload restored last-known-good config`,请检查 -`openclaw.json` 旁边对应的 `.clobbered.*` 文件,修复被拒绝的负载,然后运行 -`openclaw config validate`。请参阅[Gateway 网关 故障排除](/zh-CN/gateway/troubleshooting#gateway-restored-last-known-good-config) -了解恢复检查清单。 +`config reload restored last-known-good config`,请检查 `openclaw.json` 旁边对应的 +`.clobbered.*` 文件,修复被拒绝的负载,然后运行 +`openclaw config validate`。恢复检查清单请参见[Gateway 网关 故障排除](/zh-CN/gateway/troubleshooting#gateway-restored-last-known-good-config)。 ### 重载模式 | 模式 | 行为 | | ---------------------- | --------------------------------------------------------------------------------------- | -| **`hybrid`**(默认) | 立即热应用安全更改。对于关键更改会自动重启。 | -| **`hot`** | 仅热应用安全更改。当需要重启时会记录警告——由你来处理。 | -| **`restart`** | 任何配置更改都会重启 Gateway 网关,不论是否安全。 | -| **`off`** | 禁用文件监视。更改将在下次手动重启时生效。 | +| **`hybrid`**(默认) | 立即热应用安全更改。对关键更改自动重启。 | +| **`hot`** | 仅热应用安全更改。当需要重启时记录警告 —— 由你手动处理。 | +| **`restart`** | 对任何配置更改都重启 Gateway 网关,无论是否安全。 | +| **`off`** | 禁用文件监视。更改会在下一次手动重启时生效。 | ```json5 { @@ -535,56 +534,55 @@ Gateway 网关 会监视 `~/.openclaw/openclaw.json` 并自动应用更改—— } ``` -### 哪些会热应用,哪些需要重启 +### 哪些可以热应用,哪些需要重启 -大多数字段都可以在不停机的情况下热应用。在 `hybrid` 模式下,需要重启的更改会自动处理。 +大多数字段都可以无停机热应用。在 `hybrid` 模式下,需要重启的更改会自动处理。 | 类别 | 字段 | 需要重启? | | ------------------- | ----------------------------------------------------------------- | --------------- | -| 渠道 | `channels.*`、`web`(WhatsApp)——所有内置和插件渠道 | 否 | -| 智能体与模型 | `agent`、`agents`、`models`、`routing` | 否 | +| 渠道 | `channels.*`、`web`(WhatsApp)—— 所有内置和插件渠道 | 否 | +| 智能体和模型 | `agent`、`agents`、`models`、`routing` | 否 | | 自动化 | `hooks`、`cron`、`agent.heartbeat` | 否 | -| 会话与消息 | `session`、`messages` | 否 | -| 工具与媒体 | `tools`、`browser`、`skills`、`audio`、`talk` | 否 | -| UI 与其他 | `ui`、`logging`、`identity`、`bindings` | 否 | +| 会话和消息 | `session`、`messages` | 否 | +| 工具和媒体 | `tools`、`browser`、`skills`、`audio`、`talk` | 否 | +| UI 和其他 | `ui`、`logging`、`identity`、`bindings` | 否 | | Gateway 网关 服务器 | `gateway.*`(port、bind、auth、tailscale、TLS、HTTP) | **是** | | 基础设施 | `discovery`、`canvasHost`、`plugins` | **是** | -`gateway.reload` 和 `gateway.remote` 是例外——更改它们**不会**触发重启。 +`gateway.reload` 和 `gateway.remote` 是例外 —— 更改它们**不会**触发重启。 ### 重载规划 -当你编辑通过 `$include` 引用的源文件时,OpenClaw 会根据源文件作者定义的布局来规划 -重载,而不是基于拍平后的内存视图。 -这样即使 -某个顶级分区位于单独的被包含文件中,例如 -`plugins: { $include: "./plugins.json5" }`,热重载决策(热应用还是重启)也会保持可预测。 -如果源布局存在歧义,重载规划会以安全关闭方式失败。 +当你编辑一个通过 `$include` 引用的源文件时,OpenClaw 会基于 +源文件编写时的布局来规划重载,而不是基于拍平后的内存视图。 +这样即使某个单独的顶层部分位于其自己的被引入文件中,例如 +`plugins: { $include: "./plugins.json5" }`,热重载决策(热应用还是重启)也能保持可预测。 +如果源布局存在歧义,重载规划会以封闭失败方式终止。 ## 配置 RPC(程序化更新) 对于通过 Gateway 网关 API 写入配置的工具,推荐使用以下流程: -- `config.schema.lookup`:检查一个子树(浅层 schema 节点 + 子项 +- 使用 `config.schema.lookup` 检查一个子树(浅层 schema 节点 + 子节点 摘要) -- `config.get`:获取当前快照以及 `hash` -- `config.patch`:进行部分更新(JSON merge patch:对象合并,`null` - 删除,数组替换) -- `config.apply`:仅在你打算替换整个配置时使用 -- `update.run`:执行显式自更新并重启 +- 使用 `config.get` 获取当前快照及其 `hash` +- 使用 `config.patch` 进行部分更新(JSON merge patch:对象合并,`null` + 表示删除,数组整体替换) +- 仅当你确实打算替换整个配置时,才使用 `config.apply` +- 使用 `update.run` 显式执行自更新并重启 -控制平面写入(`config.apply`、`config.patch`、`update.run`)会按 -每个 `deviceId+clientIp` 在每 60 秒内限制为 3 次请求。 +控制平面写入(`config.apply`、`config.patch`、`update.run`) +按每个 `deviceId+clientIp` 限流为每 60 秒 3 次请求。 重启请求会被合并,然后在两次重启周期之间强制执行 30 秒冷却时间。 部分 patch 示例: ```bash -openclaw gateway call config.get --params '{}' # 获取 payload.hash +openclaw gateway call config.get --params '{}' # capture payload.hash openclaw gateway call config.patch --params '{ "raw": "{ channels: { telegram: { groups: { \"*\": { requireMention: false } } } } }", "baseHash": "" @@ -592,15 +590,15 @@ openclaw gateway call config.patch --params '{ ``` `config.apply` 和 `config.patch` 都接受 `raw`、`baseHash`、`sessionKey`、 -`note` 和 `restartDelayMs`。`baseHash` 对 `config.patch` 是必需的, -而当配置已存在时,也建议为 `config.apply` 提供它。 +`note` 和 `restartDelayMs`。当配置已存在时,这两种方法都要求提供 +`baseHash`。 ## 环境变量 -OpenClaw 会从父进程读取环境变量,另外还会读取: +OpenClaw 会从父进程读取环境变量,此外还包括: - 当前工作目录中的 `.env`(如果存在) -- `~/.openclaw/.env`(全局后备) +- `~/.openclaw/.env`(全局回退) 这两个文件都不会覆盖现有环境变量。你也可以在配置中设置内联环境变量: @@ -613,8 +611,8 @@ OpenClaw 会从父进程读取环境变量,另外还会读取: } ``` - - 如果已启用且预期键名尚未设置,OpenClaw 会运行你的登录 shell,并且只导入缺失的键: + + 如果启用,并且预期键名尚未设置,OpenClaw 会运行你的登录 shell,并且只导入缺失的键名: ```json5 { @@ -624,10 +622,10 @@ OpenClaw 会从父进程读取环境变量,另外还会读取: } ``` -等效环境变量:`OPENCLAW_LOAD_SHELL_ENV=1` +对应的环境变量:`OPENCLAW_LOAD_SHELL_ENV=1` - + 可在任意配置字符串值中使用 `${VAR_NAME}` 引用环境变量: ```json5 @@ -640,14 +638,14 @@ OpenClaw 会从父进程读取环境变量,另外还会读取: 规则: - 仅匹配大写名称:`[A-Z_][A-Z0-9_]*` -- 缺失/为空的环境变量会在加载时抛出错误 +- 缺失或为空的变量会在加载时报错 - 使用 `$${VAR}` 转义以输出字面量 -- 在 `$include` 文件中也可用 +- 在 `$include` 文件中同样有效 - 内联替换:`"${BASE}/v1"` → `"https://api.example.com/v1"` - + 对于支持 SecretRef 对象的字段,你可以使用: ```json5 @@ -680,16 +678,16 @@ OpenClaw 会从父进程读取环境变量,另外还会读取: } ``` -有关 SecretRef 的详细信息(包括用于 `env`/`file`/`exec` 的 `secrets.providers`),请参阅[密钥管理](/zh-CN/gateway/secrets)。 -支持的凭证路径列在[SecretRef 凭证范围](/zh-CN/reference/secretref-credential-surface)中。 +有关 SecretRef 的详细信息(包括用于 `env`/`file`/`exec` 的 `secrets.providers`),请参见[Secrets Management](/zh-CN/gateway/secrets)。 +支持的凭证路径列在 [SecretRef Credential Surface](/zh-CN/reference/secretref-credential-surface) 中。 -请参阅[环境](/zh-CN/help/environment)了解完整的优先级和来源。 +有关完整的优先级和来源,请参见[环境](/zh-CN/help/environment)。 ## 完整参考 -如需完整的逐字段参考,请参阅 **[配置参考](/zh-CN/gateway/configuration-reference)**。 +有关完整的逐字段参考,请参见 **[配置参考](/zh-CN/gateway/configuration-reference)**。 --- -_相关内容:[配置示例](/zh-CN/gateway/configuration-examples) · [配置参考](/zh-CN/gateway/configuration-reference) · [Doctor](/zh-CN/gateway/doctor)_ +_相关内容:[Configuration Examples](/zh-CN/gateway/configuration-examples) · [配置参考](/zh-CN/gateway/configuration-reference) · [Doctor](/zh-CN/gateway/doctor)_ diff --git a/docs/zh-CN/plugins/architecture.md b/docs/zh-CN/plugins/architecture.md index da7807795..361eac04d 100644 --- a/docs/zh-CN/plugins/architecture.md +++ b/docs/zh-CN/plugins/architecture.md @@ -1,17 +1,17 @@ --- read_when: - 构建或调试原生 OpenClaw 插件 - - 理解插件能力模型或归属边界 + - 理解插件能力模型或所有权边界 - 处理插件加载流水线或注册表 - 实现提供商运行时钩子或渠道插件 sidebarTitle: Internals -summary: 插件内部机制:能力模型、归属、契约、加载流水线和运行时辅助工具 +summary: 插件内部机制:能力模型、所有权、契约、加载流水线和运行时辅助工具 title: 插件内部机制 x-i18n: - generated_at: "2026-04-23T08:14:04Z" + generated_at: "2026-04-23T08:25:13Z" model: gpt-5.4 provider: openai - source_hash: d3d5e4b9c48c2a0fc8116733e38a745bac5dfdbe65fdea8e9be6563b4051d805 + source_hash: b5a766c267b2618140c744cbebd28f2b206568f26ce50095b898520f4663e21d source_path: plugins/architecture.md workflow: 15 --- @@ -20,11 +20,11 @@ x-i18n: 这是**深度架构参考**。如需实用指南,请参阅: - - [安装和使用插件](/zh-CN/tools/plugin) —— 用户指南 - - [入门指南](/zh-CN/plugins/building-plugins) —— 第一个插件教程 - - [渠道插件](/zh-CN/plugins/sdk-channel-plugins) —— 构建消息渠道 - - [提供商插件](/zh-CN/plugins/sdk-provider-plugins) —— 构建模型提供商 - - [SDK 概览](/zh-CN/plugins/sdk-overview) —— import map 和注册 API + - [安装和使用插件](/zh-CN/tools/plugin) — 用户指南 + - [入门指南](/zh-CN/plugins/building-plugins) — 第一个插件教程 + - [渠道插件](/zh-CN/plugins/sdk-channel-plugins) — 构建消息渠道 + - [提供商插件](/zh-CN/plugins/sdk-provider-plugins) — 构建模型提供商 + - [SDK 概览](/zh-CN/plugins/sdk-overview) — 导入映射和注册 API 本页介绍 OpenClaw 插件系统的内部架构。 @@ -38,7 +38,7 @@ x-i18n: | 文本推理 | `api.registerProvider(...)` | `openai`, `anthropic` | | CLI 推理后端 | `api.registerCliBackend(...)` | `openai`, `anthropic` | | 语音 | `api.registerSpeechProvider(...)` | `elevenlabs`, `microsoft` | -| 实时转录 | `api.registerRealtimeTranscriptionProvider(...)` | `openai` | +| 实时转写 | `api.registerRealtimeTranscriptionProvider(...)` | `openai` | | 实时语音 | `api.registerRealtimeVoiceProvider(...)` | `openai` | | 媒体理解 | `api.registerMediaUnderstandingProvider(...)` | `openai`, `google` | | 图像生成 | `api.registerImageGenerationProvider(...)` | `openai`, `google`, `fal`, `minimax` | @@ -48,46 +48,46 @@ x-i18n: | Web 搜索 | `api.registerWebSearchProvider(...)` | `google` | | 渠道 / 消息传递 | `api.registerChannel(...)` | `msteams`, `matrix` | -一个注册了零个能力、但提供钩子、工具或服务的插件,属于**仅 legacy hook** 插件。这种模式目前仍然受到完全支持。 +如果一个插件注册了零个能力,但提供了钩子、工具或服务,那么它就是**仅旧版钩子**插件。这种模式仍然受到完全支持。 ### 外部兼容性立场 -能力模型已经在核心中落地,并已被当前的内置 / 原生插件使用,但外部插件的兼容性仍需要比“它已导出,因此它已冻结”更严格的标准。 +能力模型已经在核心中落地,并且如今已被内置 / 原生插件使用,但外部插件兼容性仍然需要比“它已导出,因此它已冻结”更严格的标准。 -当前指导如下: +当前指导原则: -- **现有外部插件:** 保持基于 hook 的集成可正常工作;将其视为兼容性的基线 -- **新的内置 / 原生插件:** 优先使用显式能力注册,而不是特定供应商的内部访问或新的仅 hook 设计 -- **采用能力注册的外部插件:** 允许,但除非文档明确将某个契约标记为稳定,否则应将能力专用的辅助接口视为仍在演进中 +- **现有外部插件:** 保持基于钩子的集成继续正常工作;将其视为兼容性的基线 +- **新的内置 / 原生插件:** 优先使用显式能力注册,而不是依赖供应商特定的内部调用或新的仅钩子设计 +- **采用能力注册的外部插件:** 允许,但除非文档明确将某项契约标记为稳定,否则应将特定于能力的辅助接口视为仍在演进中 -实际规则: +实践规则: - 能力注册 API 是预期的发展方向 -- 在过渡期间,legacy hook 仍然是对外部插件来说最安全、最不易破坏的路径 -- 并非所有导出的辅助子路径都同等重要;优先使用文档化的狭义契约,而不是偶然导出的辅助接口 +- 在过渡期间,旧版钩子仍然是外部插件最安全、最不容易中断的路径 +- 并非所有导出的辅助子路径都同等稳定;应优先使用文档化的狭义契约,而不是偶然暴露的辅助导出 ### 插件形态 -OpenClaw 会根据每个已加载插件的实际注册行为来判定其形态(而不仅仅是静态元数据): +OpenClaw 会根据每个已加载插件的实际注册行为来将其归类为某种形态(而不只是依据静态元数据): -- **plain-capability** —— 仅注册一种能力类型(例如仅提供商插件 `mistral`) -- **hybrid-capability** —— 注册多种能力类型(例如 `openai` 同时拥有文本推理、语音、媒体理解和图像生成) -- **hook-only** —— 仅注册 hooks(类型化或自定义),不注册能力、工具、命令或服务 +- **plain-capability** —— 只注册一种能力类型(例如仅提供商插件 `mistral`) +- **hybrid-capability** —— 注册多种能力类型(例如 `openai` 拥有文本推理、语音、媒体理解和图像生成) +- **hook-only** —— 仅注册钩子(类型化或自定义),不注册能力、工具、命令或服务 - **non-capability** —— 注册工具、命令、服务或路由,但不注册能力 -使用 `openclaw plugins inspect ` 可查看插件的形态和能力细分。详见 [CLI 参考](/zh-CN/cli/plugins#inspect)。 +使用 `openclaw plugins inspect ` 可以查看插件的形态和能力明细。详见 [CLI 参考](/zh-CN/cli/plugins#inspect)。 -### Legacy hooks +### 旧版钩子 -`before_agent_start` hook 仍然作为仅 hook 插件的兼容路径受到支持。现实中的 legacy 插件仍然依赖它。 +`before_agent_start` 钩子仍然作为仅钩子插件的兼容路径受到支持。现实中的旧版插件仍然依赖它。 方向如下: -- 保持其正常工作 -- 在文档中将其标记为 legacy +- 保持其可用 +- 将其文档化为旧版机制 - 对于模型 / 提供商覆盖工作,优先使用 `before_model_resolve` - 对于提示词变更工作,优先使用 `before_prompt_build` -- 只有在真实使用量下降且 fixture 覆盖证明迁移安全后,才考虑移除 +- 只有在真实使用量下降且夹具覆盖证明迁移安全之后,才考虑移除 ### 兼容性信号 @@ -95,57 +95,57 @@ OpenClaw 会根据每个已加载插件的实际注册行为来判定其形态 | 信号 | 含义 | | -------------------------- | ------------------------------------------------------------ | -| **config valid** | 配置解析正常,且插件可解析 | -| **compatibility advisory** | 插件使用了受支持但较旧的模式(例如 `hook-only`) | -| **legacy warning** | 插件使用了 `before_agent_start`,该接口已弃用 | -| **hard error** | 配置无效,或插件加载失败 | +| **配置有效** | 配置解析正常,且插件解析成功 | +| **兼容性提示** | 插件使用受支持但较旧的模式(例如 `hook-only`) | +| **旧版警告** | 插件使用 `before_agent_start`,该机制已弃用 | +| **硬错误** | 配置无效或插件加载失败 | -`hook-only` 和 `before_agent_start` 当前都不会导致你的插件失效——`hook-only` 只是提示,而 `before_agent_start` 只会触发警告。这些信号也会出现在 `openclaw status --all` 和 `openclaw plugins doctor` 中。 +`hook-only` 和 `before_agent_start` 目前都不会导致你的插件中断 —— `hook-only` 只是提示,而 `before_agent_start` 只会触发警告。这些信号也会出现在 `openclaw status --all` 和 `openclaw plugins doctor` 中。 ## 架构概览 -OpenClaw 的插件系统有四层: +OpenClaw 的插件系统分为四层: -1. **Manifest + 设备发现** - OpenClaw 会从已配置路径、workspace 根目录、全局插件根目录以及内置插件中查找候选插件。设备发现会优先读取原生 `openclaw.plugin.json` manifests,以及受支持的 bundle manifests。 +1. **清单 + 发现** + OpenClaw 会从已配置路径、工作区根目录、全局插件根目录以及内置插件中查找候选插件。发现阶段会首先读取原生 `openclaw.plugin.json` 清单以及受支持的 bundle 清单。 2. **启用 + 验证** - 核心决定已发现的插件是已启用、已禁用、已阻止,还是被选中用于某个独占槽位(例如 memory)。 + 核心决定已发现的插件是启用、禁用、阻止,还是被选中用于某个排他性槽位(例如 memory)。 3. **运行时加载** - 原生 OpenClaw 插件会通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容的 bundles 会在不导入运行时代码的情况下规范化为注册表记录。 -4. **表面消费** - OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、hooks、HTTP 路由、CLI 命令和服务。 + 原生 OpenClaw 插件通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容的 bundle 会被规范化为注册表记录,而无需导入运行时代码。 +4. **表面消费** + OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、钩子、HTTP 路由、CLI 命令和服务。 -对于插件 CLI 本身,根命令发现分为两个阶段: +对于插件 CLI 而言,根命令发现会拆分为两个阶段: -- 解析阶段的元数据来自 `registerCli(..., { descriptors: [...] })` -- 真正的插件 CLI 模块可以保持懒加载,并在首次调用时注册 +- 解析时元数据来自 `registerCli(..., { descriptors: [...] })` +- 真实的插件 CLI 模块可以保持惰性,仅在首次调用时注册 这样既能让插件拥有的 CLI 代码保留在插件内部,又能让 OpenClaw 在解析前预留根命令名称。 重要的设计边界是: -- 设备发现 + 配置验证应该仅依赖 **manifest / schema 元数据** 即可工作,而无需执行插件代码 +- 发现 + 配置验证应能基于**清单 / schema 元数据**工作,而无需执行插件代码 - 原生运行时行为来自插件模块的 `register(api)` 路径 -这种拆分让 OpenClaw 能在完整运行时尚未激活之前,先验证配置、解释缺失 / 已禁用的插件,并构建 UI / schema 提示。 +这种拆分让 OpenClaw 能在完整运行时激活之前,验证配置、解释缺失 / 禁用的插件,并构建 UI / schema 提示。 -### 渠道插件与共享消息工具 +### 渠道插件和共享 message 工具 -对于常规聊天操作,渠道插件无需单独注册发送 / 编辑 / 反应工具。OpenClaw 在核心中保留一个共享的 `message` 工具,而渠道插件则拥有其背后的渠道专用发现和执行逻辑。 +对于常规聊天操作,渠道插件不需要单独注册发送 / 编辑 / 响应工具。OpenClaw 在核心中保留了一个共享的 `message` 工具,而渠道插件负责其背后的渠道特定发现和执行。 -当前的边界如下: +当前边界如下: -- 核心拥有共享 `message` 工具宿主、提示词接线、会话 / 线程记录和执行分发 -- 渠道插件拥有作用域化动作发现、能力发现,以及任何渠道专用的 schema 片段 -- 渠道插件拥有提供商专用的会话对话语法,例如对话 id 如何编码线程 id,或如何从父对话继承 +- 核心拥有共享 `message` 工具宿主、提示词接线、会话 / 线程簿记和执行分发 +- 渠道插件拥有作用域化动作发现、能力发现以及任何渠道特定的 schema 片段 +- 渠道插件拥有提供商特定的会话对话语法,例如对话 id 如何编码线程 id 或从父对话继承 - 渠道插件通过其动作适配器执行最终动作 -对于渠道插件,SDK 表面是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用允许插件同时返回其可见动作、能力和 schema 贡献,从而避免这些部分彼此漂移。 +对于渠道插件,SDK 接口是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用允许插件将其可见动作、能力和 schema 贡献一起返回,从而避免这些部分彼此漂移。 -当某个渠道专用 message-tool 参数携带媒体来源(例如本地路径或远程媒体 URL)时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心会使用这个显式列表来应用沙箱路径规范化和出站媒体访问提示,而不会硬编码插件拥有的参数名称。 -这里应优先使用按动作划分的映射,而不是某个渠道范围内的扁平列表,这样仅限 profile 的媒体参数就不会在 `send` 等无关动作上被规范化。 +当某个渠道特定的 message-tool 参数携带媒体来源(例如本地路径或远程媒体 URL)时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心会使用这个显式列表来应用沙箱路径规范化和出站媒体访问提示,而不是将插件拥有的参数名硬编码。 +这里应优先使用按动作划分的映射,而不是整个渠道范围内的扁平列表,这样仅用于 profile 的媒体参数就不会在像 `send` 这样的无关动作上被规范化。 -核心会将运行时作用域传入该发现步骤。重要字段包括: +核心会将运行时作用域传入这个发现步骤。重要字段包括: - `accountId` - `currentChannelId` @@ -156,31 +156,31 @@ OpenClaw 的插件系统有四层: - `agentId` - 受信任的入站 `requesterSenderId` -这对于上下文敏感的插件很重要。渠道可以根据活动账户、当前房间 / 线程 / 消息,或受信任的请求者身份来隐藏或暴露消息动作,而无需在核心 `message` 工具中硬编码渠道专用分支。 +这对于上下文敏感型插件非常重要。渠道可以根据活动账户、当前房间 / 线程 / 消息,或受信任的请求者身份,隐藏或暴露消息动作,而无需在核心 `message` 工具中硬编码渠道特定分支。 -这也是为什么嵌入式 runner 路由改动仍然属于插件工作:runner 负责将当前聊天 / 会话身份转发到插件发现边界,以便共享的 `message` 工具能够为当前轮次暴露正确的、由渠道拥有的表面。 +这也是为什么嵌入式 runner 路由变更仍然属于插件工作:runner 负责将当前聊天 / 会话身份转发到插件发现边界,以便共享的 `message` 工具为当前轮次暴露正确的渠道拥有表面。 -对于渠道拥有的执行辅助工具,内置插件应将执行运行时保留在它们自己的扩展模块中。核心不再拥有位于 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp 消息动作运行时。 -我们不会发布单独的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从其扩展拥有的模块导入本地运行时代码。 +对于渠道拥有的执行辅助工具,内置插件应将执行运行时保留在它们自己的扩展模块中。核心不再拥有 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp 消息动作运行时。 +我们不会发布单独的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从其扩展拥有的模块导入自己的本地运行时代码。 -相同的边界也适用于一般意义上按提供商命名的 SDK 接缝:核心不应导入 Slack、Discord、Signal、WhatsApp 或类似扩展的渠道专用便捷 barrel。如果核心需要某种行为,要么消费内置插件自己的 `api.ts` / `runtime-api.ts` barrel,要么将该需求提升为共享 SDK 中狭义的通用能力。 +同样的边界也适用于一般意义上按提供商命名的 SDK 接缝:核心不应导入 Slack、Discord、Signal、WhatsApp 或类似扩展的渠道特定便捷 barrel。如果核心需要某种行为,要么消费内置插件自身的 `api.ts` / `runtime-api.ts` barrel,要么将该需求提升为共享 SDK 中一个狭义的通用能力。 对于投票,当前有两条执行路径: -- `outbound.sendPoll` 是适用于符合通用投票模型渠道的共享基线 -- `actions.handleAction("poll")` 是适用于渠道专用投票语义或额外投票参数的首选路径 +- `outbound.sendPoll` 是适用于符合通用投票模型的渠道的共享基线 +- `actions.handleAction("poll")` 是适用于渠道特定投票语义或额外投票参数的首选路径 -现在,核心会在插件投票分发拒绝该动作之后,才延迟执行共享投票解析,因此插件拥有的投票处理器可以接受渠道专用投票字段,而不会先被通用投票解析器拦住。 +现在,核心会在插件投票分发拒绝该动作之后,才延迟执行共享投票解析,因此插件拥有的投票处理器可以接受渠道特定的投票字段,而不会先被通用投票解析器阻挡。 -完整启动顺序请参阅[加载流水线](#load-pipeline)。 +完整的启动顺序请参见[加载流水线](#load-pipeline)。 -## 能力归属模型 +## 能力所有权模型 -OpenClaw 将原生插件视为**公司**或**功能**的归属边界,而不是无关集成的大杂烩。 +OpenClaw 将原生插件视为**公司**或**功能特性**的所有权边界,而不是一堆互不相关集成的杂物袋。 这意味着: -- 公司插件通常应拥有该公司的所有 OpenClaw 对外表面 +- 公司插件通常应拥有该公司所有面向 OpenClaw 的表面 - 功能插件通常应拥有其引入的完整功能表面 - 渠道应消费共享的核心能力,而不是临时重新实现提供商行为 @@ -193,41 +193,42 @@ OpenClaw 将原生插件视为**公司**或**功能**的归属边界,而不是 - 内置的 `firecrawl` 插件拥有 Firecrawl Web 抓取行为 - 内置的 `minimax`、`mistral`、`moonshot` 和 `zai` 插件拥有它们各自的媒体理解后端 - 内置的 `qwen` 插件拥有 Qwen 文本提供商行为,以及媒体理解和视频生成行为 -- `voice-call` 插件是一个功能插件:它拥有通话传输、工具、CLI、路由以及 Twilio 媒体流桥接,但它会消费共享的语音、实时转录和实时语音能力,而不是直接导入供应商插件 +- `voice-call` 插件是一个功能插件:它拥有通话传输、工具、CLI、路由和 Twilio 媒体流桥接,但它会消费共享的语音以及实时转写和实时语音能力,而不是直接导入供应商插件 预期的最终状态是: -- 即使 OpenAI 横跨文本模型、语音、图像和未来的视频,它仍然位于一个插件中 -- 另一个供应商也可以对其自身的表面区域采用相同方式 -- 渠道并不关心哪个供应商插件拥有该提供商;它们消费的是由核心暴露的共享能力契约 +- 即使 OpenAI 横跨文本模型、语音、图像以及未来的视频,它也只存在于一个插件中 +- 另一个供应商也可以对其自身表面做同样的事情 +- 渠道并不关心是哪个供应商插件拥有该提供商;它们消费的是由核心暴露的共享能力契约 -这就是关键区别: +这是关键区别: -- **plugin** = 归属边界 +- **plugin** = 所有权边界 - **capability** = 可由多个插件实现或消费的核心契约 -因此,如果 OpenClaw 新增了诸如视频之类的新领域,第一个问题不应是“哪个提供商应该硬编码视频处理?”而应该是“核心视频能力契约是什么?”一旦该契约存在,供应商插件就可以针对它进行注册,渠道 / 功能插件也可以消费它。 +因此,如果 OpenClaw 添加一个新领域,例如视频,第一个问题不应是“哪个提供商应该把视频处理硬编码进去?” 第一个问题应当是“核心视频能力契约是什么?” +一旦该契约存在,供应商插件就可以针对它进行注册,而渠道 / 功能插件则可以消费它。 如果该能力尚不存在,通常正确的做法是: 1. 在核心中定义缺失的能力 2. 通过插件 API / 运行时以类型化方式暴露它 -3. 让渠道 / 功能对接该能力 +3. 让渠道 / 功能针对该能力完成接线 4. 让供应商插件注册实现 -这样可以保持归属明确,同时避免核心行为依赖单一供应商或某个一次性的插件专用代码路径。 +这样可以在保持所有权明确的同时,避免核心行为依赖单一供应商或一次性的插件特定代码路径。 ### 能力分层 -决定代码应放在哪里时,请使用这个心智模型: +在决定代码应放在哪里时,可以使用以下思维模型: - **核心能力层**:共享编排、策略、回退、配置合并规则、交付语义和类型化契约 -- **供应商插件层**:供应商专用 API、身份验证、模型目录、语音合成、图像生成、未来的视频后端、使用量端点 +- **供应商插件层**:供应商特定 API、认证、模型目录、语音合成、图像生成、未来的视频后端、用量端点 - **渠道 / 功能插件层**:Slack / Discord / voice-call / 等集成,它们消费核心能力并将其呈现在某个表面上 -例如,TTS 遵循如下结构: +例如,TTS 遵循这样的形态: -- 核心拥有回复时 TTS 策略、回退顺序、偏好和渠道交付 +- 核心拥有回复时 TTS 策略、回退顺序、偏好设置和渠道交付 - `openai`、`elevenlabs` 和 `microsoft` 拥有合成实现 - `voice-call` 消费电话 TTS 运行时辅助工具 @@ -235,7 +236,7 @@ OpenClaw 将原生插件视为**公司**或**功能**的归属边界,而不是 ### 多能力公司插件示例 -一个公司插件从外部看起来应当是内聚的。如果 OpenClaw 具有用于模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、Web 抓取和 Web 搜索的共享契约,那么一个供应商就可以在同一个地方拥有其所有表面: +从外部看,一个公司插件应当具有内聚性。如果 OpenClaw 为模型、语音、实时转写、实时语音、媒体理解、图像生成、视频生成、Web 抓取和 Web 搜索提供了共享契约,那么一个供应商就可以在一个地方拥有它的全部表面: ```ts import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry"; @@ -289,168 +290,180 @@ const plugin: OpenClawPluginDefinition = { export default plugin; ``` -重要的不是确切的辅助函数名称,而是这种结构: +重要的不是精确的辅助函数名称,重要的是这种形态: - 一个插件拥有该供应商表面 - 核心仍然拥有能力契约 -- 渠道和功能插件消费 `api.runtime.*` 辅助工具,而不是供应商代码 -- 契约测试可以断言该插件已注册它声称拥有的能力 +- 渠道和功能插件消费的是 `api.runtime.*` 辅助工具,而不是供应商代码 +- 契约测试可以断言插件确实注册了它声称拥有的能力 ### 能力示例:视频理解 -OpenClaw 已经将图像 / 音频 / 视频理解视为一种共享能力。相同的归属模型也适用于这里: +OpenClaw 已经将图像 / 音频 / 视频理解视为一个共享能力。这里也适用同样的所有权模型: 1. 核心定义媒体理解契约 -2. 供应商插件按适用情况注册 `describeImage`、`transcribeAudio` 和 `describeVideo` -3. 渠道和功能插件消费共享的核心行为,而不是直接连接到供应商代码 +2. 供应商插件按需注册 `describeImage`、`transcribeAudio` 和 `describeVideo` +3. 渠道和功能插件消费共享核心行为,而不是直接接线到供应商代码 -这样可以避免将某个提供商对视频的假设固化进核心中。插件拥有供应商表面;核心拥有能力契约和回退行为。 +这样可以避免将某个提供商的视频假设固化进核心。插件拥有供应商表面;核心拥有能力契约和回退行为。 -视频生成也已经采用了同样的顺序:核心拥有类型化能力契约和运行时辅助工具,供应商插件则针对其注册 `api.registerVideoGenerationProvider(...)` 实现。 +视频生成已经采用了同样的顺序:核心拥有类型化能力契约和运行时辅助工具,而供应商插件则注册 `api.registerVideoGenerationProvider(...)` 实现。 -需要一个具体的发布清单吗?请参阅[能力扩展手册](/zh-CN/plugins/architecture)。 +需要一个具体的发布检查清单吗?请参阅 +[能力扩展手册](/zh-CN/plugins/architecture)。 -## 契约与约束 +## 契约与强制机制 -插件 API 表面是有意进行类型化并集中在 `OpenClawPluginApi` 中的。这个契约定义了受支持的注册点,以及插件可依赖的运行时辅助工具。 +插件 API 表面被有意设计为类型化,并集中在 +`OpenClawPluginApi` 中。该契约定义了受支持的注册点,以及插件可依赖的运行时辅助工具。 -这很重要,原因如下: +这很重要,因为: -- 插件作者获得一种稳定的内部标准 -- 核心可以拒绝重复归属,例如两个插件注册相同的 provider id -- 启动阶段可以为格式错误的注册提供可执行的诊断信息 -- 契约测试可以强制执行内置插件的归属,并防止静默漂移 +- 插件作者会获得一个稳定的内部标准 +- 核心可以拒绝重复所有权,例如两个插件注册同一个 provider id +- 启动过程可以为格式错误的注册暴露可执行的诊断信息 +- 契约测试可以强制内置插件所有权,并防止无声漂移 -这里有两层约束: +这里有两层强制机制: -1. **运行时注册约束** - 插件注册表会在插件加载时验证注册内容。例如:重复的 provider id、重复的 speech provider id 以及格式错误的注册,都会产生插件诊断,而不是导致未定义行为。 -2. **契约测试** - 在测试运行期间,内置插件会被捕获到契约注册表中,这样 OpenClaw 就可以明确断言归属。如今这已用于模型提供商、语音提供商、Web 搜索提供商以及内置注册归属。 +1. **运行时注册强制** + 插件注册表会在插件加载时验证注册内容。例如:重复的 provider id、重复的语音提供商 id,以及格式错误的注册,都会产生插件诊断,而不是导致未定义行为。 +2. **契约测试** + 在测试运行期间,内置插件会被捕获到契约注册表中,因此 OpenClaw 可以显式断言所有权。目前这用于模型提供商、语音提供商、Web 搜索提供商,以及内置注册所有权。 -实际效果是,OpenClaw 能够预先知道哪个插件拥有哪个表面。这使得核心和渠道可以无缝组合,因为归属是声明式的、类型化的、可测试的,而不是隐式的。 +其实际效果是,OpenClaw 可以预先知道哪个插件拥有哪个表面。这样,核心和渠道就可以无缝组合,因为所有权是被声明的、类型化的、可测试的,而不是隐式的。 -### 什么应该属于契约 +### 什么内容应属于契约 好的插件契约应当是: - 类型化的 - 小而精的 -- 能力专用的 +- 特定于能力的 - 由核心拥有 - 可被多个插件复用 - 可被渠道 / 功能消费,而无需了解供应商细节 不好的插件契约则是: -- 隐藏在核心中的供应商专用策略 +- 隐藏在核心中的供应商特定策略 - 绕过注册表的一次性插件逃生口 -- 直接深入供应商实现的渠道代码 +- 渠道代码直接伸手到供应商实现内部 - 不属于 `OpenClawPluginApi` 或 `api.runtime` 的临时运行时对象 -如果拿不准,请提升抽象层级:先定义能力,再让插件接入它。 +如有疑问,就提升抽象层级:先定义能力,再让插件接入它。 ## 执行模型 -原生 OpenClaw 插件与 Gateway 网关 **在同一进程中** 运行。它们不是沙箱隔离的。一个已加载的原生插件与核心代码具有相同的进程级信任边界。 +原生 OpenClaw 插件会与 Gateway 网关**在同一进程内**运行。它们**没有**沙箱隔离。一个已加载的原生插件与核心代码处于相同的进程级信任边界内。 -这意味着: +其影响包括: -- 原生插件可以注册工具、网络处理器、hooks 和服务 -- 原生插件中的 bug 可能导致 gateway 崩溃或变得不稳定 -- 恶意原生插件等同于在 OpenClaw 进程内部执行任意代码 +- 原生插件可以注册工具、网络处理器、钩子和服务 +- 原生插件中的 bug 可能导致 gateway 崩溃或不稳定 +- 恶意原生插件等同于在 OpenClaw 进程内执行任意代码 -兼容 bundle 默认更安全,因为 OpenClaw 当前将它们视为元数据 / 内容包。在当前版本中,这主要意味着内置 skills。 +兼容 bundle 默认更安全,因为 OpenClaw 当前将其视为元数据 / 内容包。在当前版本中,这主要指内置 Skills。 -对于非内置插件,请使用 allowlist 和显式的安装 / 加载路径。应将 workspace 插件视为开发时代码,而不是生产默认项。 +对于非内置插件,应使用 allowlist 和显式安装 / 加载路径。应将工作区插件视为开发期代码,而不是生产默认值。 -对于内置 workspace 包名,请让插件 id 锚定在 npm 名称中:默认使用 `@openclaw/`,或者使用批准的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`,前提是该包有意暴露更狭义的插件角色。 +对于内置工作区包名,插件 id 应默认锚定在 npm 名称中:`@openclaw/`,或者使用经批准的类型化后缀,例如 +`-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`,当该包有意暴露更窄的插件角色时可使用这些后缀。 重要的信任说明: -- `plugins.allow` 信任的是**插件 id**,而不是来源出处。 -- 当同 id 的 workspace 插件被启用 / 加入 allowlist 时,它会有意遮蔽内置插件副本。 -- 这属于正常且有用的行为,适用于本地开发、补丁测试和热修复。 -- 内置插件信任是根据源码快照来解析的——即加载时磁盘上的 manifest 和代码——而不是根据安装元数据。损坏或被替换的安装记录,无法在实际源码声称之外悄悄扩大内置插件的信任表面。 +- `plugins.allow` 信任的是**插件 id**,而不是源出处。 +- 当启用了 / 加入 allowlist 的工作区插件与内置插件具有相同 id 时,它会有意遮蔽内置副本。 +- 这很正常,而且对本地开发、补丁测试和热修复都很有用。 +- 内置插件信任是根据源码快照解析的——即加载时磁盘上的清单和代码——而不是根据安装元数据解析。损坏或被替换的安装记录不能悄悄扩大某个内置插件的信任表面,超出实际源码所声明的范围。 ## 导出边界 -OpenClaw 导出的是能力,而不是实现便利接口。 +OpenClaw 导出的是能力,而不是实现层面的便捷工具。 -保持能力注册对外公开。裁剪非契约辅助导出: +保持能力注册为公开接口。裁剪非契约辅助导出: -- 内置插件专用辅助子路径 +- 内置插件特定的辅助子路径 - 不打算作为公共 API 的运行时管线子路径 -- 供应商专用的便捷辅助工具 -- 属于实现细节的 setup / onboarding 辅助工具 +- 供应商特定的便捷辅助工具 +- 属于实现细节的设置 / 新手引导辅助工具 -出于兼容性和内置插件维护目的,某些内置插件辅助子路径仍然保留在生成的 SDK 导出映射中。当前示例包括 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup` 以及若干 `plugin-sdk/matrix*` 接缝。应将这些视为保留的实现细节导出,而不是新第三方插件推荐采用的 SDK 模式。 +一些内置插件辅助子路径仍然保留在生成的 SDK 导出映射中,以兼容旧行为并便于维护内置插件。当前示例包括 +`plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、 +`plugin-sdk/zalo-setup`,以及若干 `plugin-sdk/matrix*` 接缝。应将它们视为保留的实现细节导出,而不是为新的第三方插件推荐的 SDK 模式。 ## 加载流水线 -在启动时,OpenClaw 大致会执行以下流程: +在启动时,OpenClaw 大致会执行以下步骤: 1. 发现候选插件根目录 -2. 读取原生或兼容 bundle 的 manifest 和包元数据 +2. 读取原生或兼容 bundle 的清单与包元数据 3. 拒绝不安全的候选项 -4. 规范化插件配置(`plugins.enabled`、`allow`、`deny`、`entries`、`slots`、`load.paths`) -5. 决定每个候选项是否启用 +4. 规范化插件配置(`plugins.enabled`、`allow`、`deny`、`entries`、 + `slots`、`load.paths`) +5. 决定每个候选项的启用状态 6. 加载已启用的原生模块:已构建的内置模块使用原生加载器;未构建的原生插件使用 jiti -7. 调用原生 `register(api)` hooks,并将注册内容收集到插件注册表中 +7. 调用原生 `register(api)` 钩子,并将注册内容收集到插件注册表中 8. 将注册表暴露给命令 / 运行时表面 -`activate` 是 `register` 的 legacy 别名——加载器会解析两者中存在的那个(`def.register ?? def.activate`),并在同一时机调用。所有内置插件都使用 `register`;新插件请优先使用 `register`。 +`activate` 是 `register` 的旧版别名 —— 加载器会解析其中存在的那个(`def.register ?? def.activate`),并在同一时机调用它。所有内置插件都使用 `register`;新插件也应优先使用 `register`。 -安全门会发生在运行时代码执行**之前**。如果候选项的入口逃逸出插件根目录、路径对所有人可写,或者对于非内置插件来说路径归属看起来可疑,那么该候选项会被阻止。 +安全门控发生在运行时执行**之前**。在以下情况下,候选项会被阻止: -### Manifest 优先行为 +- 入口逃逸出插件根目录 +- 路径可被所有用户写入 +- 对于非内置插件,路径所有权看起来可疑 -manifest 是控制平面的事实来源。OpenClaw 使用它来: +### Manifest-first 行为 + +清单是控制平面的事实来源。OpenClaw 会用它来: - 标识插件 -- 发现声明的渠道 / skills / 配置 schema 或 bundle 能力 +- 发现已声明的渠道 / Skills / 配置 schema 或 bundle 能力 - 验证 `plugins.entries..config` - 增强 Control UI 标签 / 占位符 - 显示安装 / 目录元数据 -- 在不加载插件运行时的情况下保留轻量激活和设置描述符 +- 在不加载插件运行时的情况下保留轻量级激活和设置描述符 -对于原生插件,运行时模块是数据平面部分。它会注册实际行为,例如 hooks、工具、命令或提供商流程。 +对于原生插件,运行时模块是数据平面部分。它会注册实际行为,例如钩子、工具、命令或提供商流程。 -可选的 manifest `activation` 和 `setup` 块仍然留在控制平面。它们是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`。 -首批实时激活消费者现在会使用 manifest 中的命令、渠道和提供商提示,在更广泛的注册表实体化之前缩小插件加载范围: +可选的清单 `activation` 和 `setup` 块仍然属于控制平面。它们只是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`。 +首批真实激活消费者现在会使用清单中的命令、渠道和提供商提示,在更广泛的注册表实体化之前缩小插件加载范围: - CLI 加载会收窄到拥有所请求主命令的插件 - 渠道设置 / 插件解析会收窄到拥有所请求渠道 id 的插件 -- 显式提供商设置 / 运行时解析会收窄到拥有所请求 provider id 的插件 +- 显式提供商设置 / 运行时解析会收窄到拥有所请求提供商 id 的插件 -设置发现现在会优先使用由描述符拥有的 id,例如 `setup.providers` 和 `setup.cliBackends`,以便在回退到 `setup-api` 之前先收窄候选插件范围;`setup-api` 仅用于那些仍需要设置时运行时 hooks 的插件。如果多个已发现插件声称拥有相同的规范化 setup provider 或 CLI backend id,则设置查找会拒绝这个有歧义的归属,而不是依赖发现顺序。 +设置发现现在会优先使用由描述符拥有的 id,例如 `setup.providers` 和 `setup.cliBackends`,以便在回退到 `setup-api` 之前先收窄候选插件;`setup-api` 仅用于那些在设置阶段仍然需要运行时钩子的插件。如果多个已发现插件声明了相同的规范化设置提供商或 CLI 后端 id,设置查找会拒绝这个有歧义的所有者,而不是依赖发现顺序。 -### 加载器缓存的内容 +### 加载器会缓存什么 -OpenClaw 会保留以下短期进程内缓存: +OpenClaw 会在进程内保留短期缓存,用于: - 发现结果 -- manifest 注册表数据 +- 清单注册表数据 - 已加载的插件注册表 -这些缓存可减少突发启动和重复命令的开销。可以将它们安全地视为短生命周期的性能缓存,而不是持久化机制。 +这些缓存可以减少突发启动和重复命令的开销。可以安全地将它们理解为短生命周期的性能缓存,而不是持久化。 性能说明: -- 设置 `OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1` 或 `OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1` 可禁用这些缓存。 -- 使用 `OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS` 和 `OPENCLAW_PLUGIN_MANIFEST_CACHE_MS` 调整缓存窗口。 +- 设置 `OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1` 或 + `OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1` 可以禁用这些缓存。 +- 可通过 `OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS` 和 + `OPENCLAW_PLUGIN_MANIFEST_CACHE_MS` 调整缓存窗口。 ## 注册表模型 -已加载插件不会直接修改任意核心全局状态。它们会注册到一个中央插件注册表中。 +已加载的插件不会直接修改任意核心全局状态。它们会注册到一个中央插件注册表中。 -该注册表会跟踪: +注册表会跟踪: - 插件记录(身份、来源、源头、状态、诊断) - 工具 -- legacy hooks 和类型化 hooks +- 旧版钩子和类型化钩子 - 渠道 - 提供商 - Gateway 网关 RPC 处理器 @@ -459,18 +472,18 @@ OpenClaw 会保留以下短期进程内缓存: - 后台服务 - 插件拥有的命令 -然后核心功能从该注册表读取,而不是直接与插件模块通信。这使加载保持单向: +然后,核心功能会从这个注册表中读取,而不是直接与插件模块交互。这样可以保持单向加载: - 插件模块 -> 注册表注册 - 核心运行时 -> 注册表消费 -这种分离对可维护性很重要。它意味着大多数核心表面只需要一个集成点:“读取注册表”,而不是“为每个插件模块做特殊处理”。 +这种分离对可维护性非常重要。它意味着大多数核心表面只需要一个集成点:“读取注册表”,而不是“为每个插件模块做特例处理”。 -## 会话绑定回调 +## 对话绑定回调 -绑定会话的插件可以在批准结果确定时作出响应。 +绑定对话的插件可以在审批完成时作出响应。 -使用 `api.onConversationBindingResolved(...)` 可在绑定请求被批准或拒绝后收到回调: +使用 `api.onConversationBindingResolved(...)` 可在绑定请求被批准或拒绝后接收回调: ```ts export default { @@ -494,82 +507,100 @@ export default { - `status`:`"approved"` 或 `"denied"` - `decision`:`"allow-once"`、`"allow-always"` 或 `"deny"` -- `binding`:已获批准请求的已解析绑定 -- `request`:原始请求摘要、分离提示、发送者 id 和会话元数据 +- `binding`:已批准请求对应的解析后绑定 +- `request`:原始请求摘要、detach 提示、发送者 id 和对话元数据 -此回调仅用于通知。它不会改变谁被允许绑定某个会话,并且会在核心批准处理完成后运行。 +这个回调仅用于通知。它不会改变谁被允许绑定对话,并且它会在核心审批处理完成后才运行。 -## 提供商运行时 hooks +## 提供商运行时钩子 -提供商插件现在有两层: +提供商插件现在分为两层: -- manifest 元数据:`providerAuthEnvVars` 用于在运行时加载前以低成本查找基于环境变量的提供商认证,`providerAuthAliases` 用于共享认证的提供商变体,`channelEnvVars` 用于在运行时加载前以低成本查找基于环境变量的渠道配置 / 设置,此外还有 `providerAuthChoices`,用于在运行时加载前以低成本提供 onboarding / 认证选择标签和 CLI flag 元数据 -- 配置时 hooks:`catalog` / legacy `discovery`,以及 `applyConfigDefaults` -- 运行时 hooks:`normalizeModelId`、`normalizeTransport`、`normalizeConfig`、`applyNativeStreamingUsageCompat`、`resolveConfigApiKey`、`resolveSyntheticAuth`、`resolveExternalAuthProfiles`、`shouldDeferSyntheticProfileAuth`、`resolveDynamicModel`、`prepareDynamicModel`、`normalizeResolvedModel`、`contributeResolvedModelCompat`、`capabilities`、`normalizeToolSchemas`、`inspectToolSchemas`、`resolveReasoningOutputMode`、`prepareExtraParams`、`createStreamFn`、`wrapStreamFn`、`resolveTransportTurnState`、`resolveWebSocketSessionPolicy`、`formatApiKey`、`refreshOAuth`、`buildAuthDoctorHint`、`matchesContextOverflowError`、`classifyFailoverReason`、`isCacheTtlEligible`、`buildMissingAuthMessage`、`suppressBuiltInModel`、`augmentModelCatalog`、`resolveThinkingProfile`、`isBinaryThinking`、`supportsXHighThinking`、`resolveDefaultThinkingLevel`、`isModernModelRef`、`prepareRuntimeAuth`、`resolveUsageAuth`、`fetchUsageSnapshot`、`createEmbeddingProvider`、`buildReplayPolicy`、`sanitizeReplayHistory`、`validateReplayTurns`、`onModelSelected` +- 清单元数据:`providerAuthEnvVars` 用于在运行时加载前,以低成本查找提供商的环境变量认证;`providerAuthAliases` 用于共享认证的提供商变体;`channelEnvVars` 用于在运行时加载前,以低成本执行渠道环境变量 / 设置查找;此外,`providerAuthChoices` 用于在运行时加载前,以低成本提供新手引导 / 认证选项标签和 CLI 标志元数据 +- 配置期钩子:`catalog` / 旧版 `discovery` 以及 `applyConfigDefaults` +- 运行时钩子:`normalizeModelId`、`normalizeTransport`、 + `normalizeConfig`、 + `applyNativeStreamingUsageCompat`、`resolveConfigApiKey`、 + `resolveSyntheticAuth`、`resolveExternalAuthProfiles`、 + `shouldDeferSyntheticProfileAuth`、 + `resolveDynamicModel`、`prepareDynamicModel`、`normalizeResolvedModel`、 + `contributeResolvedModelCompat`、`capabilities`、 + `normalizeToolSchemas`、`inspectToolSchemas`、 + `resolveReasoningOutputMode`、`prepareExtraParams`、`createStreamFn`、 + `wrapStreamFn`、`resolveTransportTurnState`、 + `resolveWebSocketSessionPolicy`、`formatApiKey`、`refreshOAuth`、 + `buildAuthDoctorHint`、`matchesContextOverflowError`、 + `classifyFailoverReason`、`isCacheTtlEligible`、 + `buildMissingAuthMessage`、`suppressBuiltInModel`、`augmentModelCatalog`、 + `resolveThinkingProfile`、`isBinaryThinking`、`supportsXHighThinking`、 + `resolveDefaultThinkingLevel`、`isModernModelRef`、`prepareRuntimeAuth`、 + `resolveUsageAuth`、`fetchUsageSnapshot`、`createEmbeddingProvider`、 + `buildReplayPolicy`、 + `sanitizeReplayHistory`、`validateReplayTurns`、`onModelSelected` -OpenClaw 仍然拥有通用智能体循环、故障切换、转录处理和工具策略。这些 hooks 是提供商专用行为的扩展表面,而无需引入一整套自定义推理传输。 +OpenClaw 仍然拥有通用智能体循环、故障切换、转录处理和工具策略。这些钩子是在无需整套自定义推理传输的情况下,为提供商特定行为提供的扩展表面。 -当提供商具有基于环境变量的凭证,并且通用认证 / 状态 / 模型选择器路径需要在不加载插件运行时的情况下感知它们时,请使用 manifest `providerAuthEnvVars`。当某个 provider id 应复用另一个 provider id 的环境变量、认证配置文件、基于配置的认证以及 API 密钥 onboarding 选项时,请使用 manifest `providerAuthAliases`。当 onboarding / 认证选择 CLI 表面需要在不加载提供商运行时的情况下了解该提供商的 choice id、分组标签和简单的单 flag 认证接线时,请使用 manifest `providerAuthChoices`。将提供商运行时 `envVars` 保留给面向操作员的提示,例如 onboarding 标签或 OAuth client-id / client-secret 设置变量。 +当提供商具有基于环境变量的凭证,并且希望通用认证 / 状态 / 模型选择器路径在不加载插件运行时的情况下也能看到这些凭证时,应使用清单中的 `providerAuthEnvVars`。当一个提供商 id 应复用另一个提供商 id 的环境变量、认证 profile、配置支持的认证以及 API key 新手引导选项时,应使用清单中的 `providerAuthAliases`。当新手引导 / 认证选项 CLI 表面需要在不加载提供商运行时的情况下,了解该提供商的选项 id、分组标签和简单的单标志认证接线时,应使用清单中的 `providerAuthChoices`。提供商运行时中的 `envVars` 应保留用于面向操作员的提示,例如新手引导标签或 OAuth client-id / client-secret 设置变量。 -当某个渠道具有基于环境变量的认证或设置,并且通用 shell 环境变量回退、配置 / 状态检查或设置提示需要在不加载渠道运行时的情况下感知它时,请使用 manifest `channelEnvVars`。 +当某个渠道具有由环境变量驱动的认证或设置,并且希望通用 shell 环境变量回退、配置 / 状态检查或设置提示在不加载渠道运行时的情况下也能看到这些信息时,应使用清单中的 `channelEnvVars`。 -### Hook 顺序和用法 +### 钩子顺序和使用场景 -对于模型 / 提供商插件,OpenClaw 大致会按以下顺序调用 hooks。 -“何时使用”一列是快速决策指南。 +对于模型 / 提供商插件,OpenClaw 会大致按如下顺序调用这些钩子。 +“何时使用”这一列是快速决策指南。 -| # | Hook | 作用 | 何时使用 | +| # | 钩子 | 作用 | 何时使用 | | --- | --------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | `catalog` | 在生成 `models.json` 期间将提供商配置发布到 `models.providers` 中 | 提供商拥有目录,或拥有 base URL 默认值 | -| 2 | `applyConfigDefaults` | 在配置实体化期间应用由提供商拥有的全局配置默认值 | 默认值依赖于认证模式、环境或提供商模型家族语义 | -| -- | _(内置模型查找)_ | OpenClaw 会先尝试常规注册表 / 目录路径 | _(不是插件 hook)_ | -| 3 | `normalizeModelId` | 在查找前规范化 legacy 或预览版 model-id 别名 | 提供商拥有在规范模型解析前进行别名清理的逻辑 | -| 4 | `normalizeTransport` | 在通用模型组装前规范化提供商家族的 `api` / `baseUrl` | 提供商拥有同一传输家族中自定义 provider id 的传输清理逻辑 | -| 5 | `normalizeConfig` | 在运行时 / 提供商解析前规范化 `models.providers.` | 提供商需要与插件放在一起的配置清理逻辑;内置的 Google 家族辅助工具也会为受支持的 Google 配置项提供兜底 | -| 6 | `applyNativeStreamingUsageCompat` | 对配置提供商应用原生流式用量兼容性重写 | 提供商需要基于端点的原生流式用量元数据修复 | -| 7 | `resolveConfigApiKey` | 在加载运行时认证前,为配置提供商解析环境变量标记认证 | 提供商具有由其拥有的环境变量标记 API 密钥解析逻辑;`amazon-bedrock` 在这里也有内置的 AWS 环境变量标记解析器 | -| 8 | `resolveSyntheticAuth` | 在不持久化明文的情况下暴露本地 / 自托管或基于配置的认证 | 提供商可使用合成 / 本地凭证标记运行 | -| 9 | `resolveExternalAuthProfiles` | 叠加由提供商拥有的外部认证配置文件;CLI / 应用拥有的凭证默认 `persistence` 为 `runtime-only` | 提供商会复用外部认证凭证,而不持久化复制的刷新令牌;请在 manifest 中声明 `contracts.externalAuthProviders` | -| 10 | `shouldDeferSyntheticProfileAuth` | 将已存储的合成配置文件占位符优先级降到基于环境变量 / 配置的认证之后 | 提供商会存储合成占位配置文件,而这些占位符不应获得更高优先级 | -| 11 | `resolveDynamicModel` | 为本地注册表中尚不存在的、由提供商拥有的 model id 执行同步回退解析 | 提供商接受任意上游 model id | -| 12 | `prepareDynamicModel` | 执行异步预热,然后再次运行 `resolveDynamicModel` | 提供商在解析未知 id 前需要网络元数据 | -| 13 | `normalizeResolvedModel` | 在嵌入式 runner 使用已解析模型前执行最终重写 | 提供商需要传输重写,但仍使用核心传输 | -| 14 | `contributeResolvedModelCompat` | 为另一种兼容传输后面的供应商模型提供兼容性标志 | 提供商能在代理传输上识别自己的模型,而无需接管该提供商 | -| 15 | `capabilities` | 由提供商拥有、供共享核心逻辑使用的转录 / 工具元数据 | 提供商需要转录 / 提供商家族特定差异处理 | -| 16 | `normalizeToolSchemas` | 在嵌入式 runner 看见工具 schema 之前对其进行规范化 | 提供商需要传输家族级别的 schema 清理 | -| 17 | `inspectToolSchemas` | 在规范化后暴露由提供商拥有的 schema 诊断信息 | 提供商希望给出关键字警告,而无需让核心理解提供商专用规则 | -| 18 | `resolveReasoningOutputMode` | 选择原生或带标记的推理输出契约 | 提供商需要带标记的推理 / 最终输出,而不是原生字段 | -| 19 | `prepareExtraParams` | 在通用流选项包装器之前进行请求参数规范化 | 提供商需要默认请求参数或按提供商清理参数 | -| 20 | `createStreamFn` | 用自定义传输完全替换正常流路径 | 提供商需要自定义线协议,而不仅仅是包装器 | -| 21 | `wrapStreamFn` | 在应用通用包装器后对流进行包装 | 提供商需要请求头 / 请求体 / 模型兼容性包装器,而不是自定义传输 | +| 1 | `catalog` | 在生成 `models.json` 期间,将提供商配置发布到 `models.providers` 中 | 提供商拥有目录或 base URL 默认值 | +| 2 | `applyConfigDefaults` | 在配置实体化期间,应用由提供商拥有的全局配置默认值 | 默认值依赖于认证模式、环境变量或提供商模型家族语义 | +| -- | _(内置模型查找)_ | OpenClaw 会先尝试正常的注册表 / 目录路径 | _(不是插件钩子)_ | +| 3 | `normalizeModelId` | 在查找前规范化旧版或预览版模型 id 别名 | 提供商拥有在规范模型解析前进行别名清理的逻辑 | +| 4 | `normalizeTransport` | 在通用模型组装前,规范化提供商家族的 `api` / `baseUrl` | 提供商拥有同一传输家族内自定义提供商 id 的传输清理逻辑 | +| 5 | `normalizeConfig` | 在运行时 / 提供商解析前规范化 `models.providers.` | 提供商需要由插件自身持有的配置清理;内置 Google 家族辅助工具也会为受支持的 Google 配置项提供兜底 | +| 6 | `applyNativeStreamingUsageCompat` | 对配置提供商应用原生流式用量兼容重写 | 提供商需要基于端点驱动的原生流式用量元数据修复 | +| 7 | `resolveConfigApiKey` | 在加载运行时认证之前,为配置提供商解析环境变量标记认证 | 提供商拥有由其自身控制的环境变量标记 API key 解析;`amazon-bedrock` 在这里也有一个内置的 AWS 环境变量标记解析器 | +| 8 | `resolveSyntheticAuth` | 在不持久化明文的情况下暴露本地 / 自托管或配置支持的认证 | 提供商可使用合成 / 本地凭证标记运行 | +| 9 | `resolveExternalAuthProfiles` | 叠加由提供商拥有的外部认证 profile;CLI / 应用拥有凭证的默认 `persistence` 为 `runtime-only` | 提供商可复用外部认证凭证,而无需持久化复制的刷新令牌;请在清单中声明 `contracts.externalAuthProviders` | +| 10 | `shouldDeferSyntheticProfileAuth` | 将已存储的合成 profile 占位符优先级降到环境变量 / 配置支持认证之后 | 提供商会存储不应具有更高优先级的合成占位符 profile | +| 11 | `resolveDynamicModel` | 为本地注册表中尚不存在的、由提供商拥有的模型 id 提供同步回退解析 | 提供商接受任意上游模型 id | +| 12 | `prepareDynamicModel` | 异步预热,然后再次运行 `resolveDynamicModel` | 提供商在解析未知 id 前需要网络元数据 | +| 13 | `normalizeResolvedModel` | 在嵌入式 runner 使用解析后的模型前做最终重写 | 提供商需要传输重写,但仍使用核心传输 | +| 14 | `contributeResolvedModelCompat` | 为位于另一兼容传输之后的供应商模型提供兼容标志 | 提供商可在不接管该提供商的情况下,在代理传输上识别自己的模型 | +| 15 | `capabilities` | 由提供商拥有、供共享核心逻辑使用的 transcript / 工具元数据 | 提供商需要 transcript / 提供商家族特有行为 | +| 16 | `normalizeToolSchemas` | 在嵌入式 runner 看到工具 schema 前进行规范化 | 提供商需要传输家族级别的 schema 清理 | +| 17 | `inspectToolSchemas` | 在规范化之后暴露由提供商拥有的 schema 诊断 | 提供商希望给出关键字警告,而不必让核心学习提供商特定规则 | +| 18 | `resolveReasoningOutputMode` | 选择原生或带标签的推理输出契约 | 提供商需要使用带标签的推理 / 最终输出,而不是原生字段 | +| 19 | `prepareExtraParams` | 在通用流式选项包装器之前进行请求参数规范化 | 提供商需要默认请求参数或按提供商进行参数清理 | +| 20 | `createStreamFn` | 用自定义传输完全替换正常的流式路径 | 提供商需要自定义线协议,而不仅仅是包装器 | +| 21 | `wrapStreamFn` | 在应用通用包装器之后对流函数进行包装 | 提供商需要请求头 / 请求体 / 模型兼容包装器,而无需自定义传输 | | 22 | `resolveTransportTurnState` | 附加原生的逐轮传输头或元数据 | 提供商希望通用传输发送提供商原生的轮次身份信息 | -| 23 | `resolveWebSocketSessionPolicy` | 附加原生 WebSocket 头或会话冷却策略 | 提供商希望通用 WS 传输调整会话头或回退策略 | -| 24 | `formatApiKey` | 认证配置文件格式化器:已存储配置文件会变成运行时 `apiKey` 字符串 | 提供商会存储额外认证元数据,并需要自定义运行时令牌形态 | -| 25 | `refreshOAuth` | 为自定义刷新端点或刷新失败策略覆盖 OAuth 刷新逻辑 | 提供商不适配共享的 `pi-ai` 刷新器 | -| 26 | `buildAuthDoctorHint` | 当 OAuth 刷新失败时附加修复提示 | 提供商需要在刷新失败后提供其自有的认证修复指导 | +| 23 | `resolveWebSocketSessionPolicy` | 附加原生 WebSocket 头或会话冷却策略 | 提供商希望通用 WS 传输调优会话头或回退策略 | +| 24 | `formatApiKey` | 认证 profile 格式化器:将已存储 profile 转换为运行时 `apiKey` 字符串 | 提供商存储了额外认证元数据,并需要自定义运行时令牌形态 | +| 25 | `refreshOAuth` | 用于自定义刷新端点或刷新失败策略的 OAuth 刷新覆盖 | 提供商不适配共享的 `pi-ai` 刷新器 | +| 26 | `buildAuthDoctorHint` | 当 OAuth 刷新失败时追加修复提示 | 提供商需要在刷新失败后提供由其自身拥有的认证修复指导 | | 27 | `matchesContextOverflowError` | 由提供商拥有的上下文窗口溢出匹配器 | 提供商存在通用启发式无法识别的原始溢出错误 | -| 28 | `classifyFailoverReason` | 由提供商拥有的故障切换原因分类 | 提供商可以将原始 API / 传输错误映射为速率限制 / 过载等原因 | -| 29 | `isCacheTtlEligible` | 面向代理 / 回程提供商的提示词缓存策略 | 提供商需要代理专用的缓存 TTL 门控 | -| 30 | `buildMissingAuthMessage` | 替换通用的缺失认证恢复消息 | 提供商需要提供商专用的缺失认证恢复提示 | -| 31 | `suppressBuiltInModel` | 过时上游模型抑制,以及可选的面向用户错误提示 | 提供商需要隐藏过时的上游条目,或用供应商提示替换它们 | -| 32 | `augmentModelCatalog` | 在发现后附加合成 / 最终目录条目 | 提供商需要在 `models list` 和选择器中添加合成的前向兼容条目 | -| 33 | `resolveThinkingProfile` | 特定模型的 `/think` 级别集、显示标签和默认值 | 提供商为选定模型暴露自定义思考层级或二元标签 | -| 34 | `isBinaryThinking` | 开 / 关推理切换兼容性 hook | 提供商只暴露二元思考开 / 关 | -| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性 hook | 提供商希望仅在部分模型上启用 `xhigh` | -| 36 | `resolveDefaultThinkingLevel` | 默认 `/think` 级别兼容性 hook | 提供商拥有某个模型家族的默认 `/think` 策略 | -| 37 | `isModernModelRef` | 用于实时配置文件过滤和 smoke 选择的现代模型匹配器 | 提供商拥有实时 / smoke 首选模型匹配逻辑 | -| 38 | `prepareRuntimeAuth` | 在推理前最后一刻,将已配置凭证交换为实际运行时令牌 / 密钥 | 提供商需要令牌交换或短期请求凭证 | -| 39 | `resolveUsageAuth` | 为 `/usage` 及相关状态表面解析用量 / 计费凭证 | 提供商需要自定义用量 / 配额令牌解析,或需要不同的用量凭证 | -| 40 | `fetchUsageSnapshot` | 在认证解析完成后获取并规范化提供商专用的用量 / 配额快照 | 提供商需要提供商专用的用量端点或负载解析器 | -| 41 | `createEmbeddingProvider` | 为 memory / 搜索构建由提供商拥有的 embedding 适配器 | Memory embedding 行为应属于提供商插件 | -| 42 | `buildReplayPolicy` | 返回一个控制该提供商转录处理方式的重放策略 | 提供商需要自定义转录策略(例如去除 thinking 块) | -| 43 | `sanitizeReplayHistory` | 在通用转录清理后重写重放历史 | 提供商需要超出共享压缩辅助工具之外的提供商专用重放重写 | -| 44 | `validateReplayTurns` | 在嵌入式 runner 之前对重放轮次进行最终验证或重塑 | 提供商传输在通用净化后需要更严格的轮次验证 | -| 45 | `onModelSelected` | 在模型被选中后运行由提供商拥有的副作用 | 当模型变为激活状态时,提供商需要遥测或提供商自有状态 | +| 28 | `classifyFailoverReason` | 由提供商拥有的故障切换原因分类 | 提供商可以将原始 API / 传输错误映射为速率限制 / 过载 / 等 | +| 29 | `isCacheTtlEligible` | 适用于代理 / 回程提供商的提示词缓存策略 | 提供商需要代理特定的缓存 TTL 门控 | +| 30 | `buildMissingAuthMessage` | 替换通用缺失认证恢复消息 | 提供商需要提供商特定的缺失认证恢复提示 | +| 31 | `suppressBuiltInModel` | 过时上游模型抑制,并可选提供面向用户的错误提示 | 提供商需要隐藏过时的上游条目,或使用供应商提示替换它们 | +| 32 | `augmentModelCatalog` | 在发现后追加合成 / 最终目录条目 | 提供商需要在 `models list` 和选择器中添加合成的前向兼容条目 | +| 33 | `resolveThinkingProfile` | 特定于模型的 `/think` 级别集合、显示标签和默认值 | 提供商为选定模型暴露自定义思考梯度或二元标签 | +| 34 | `isBinaryThinking` | 开 / 关推理切换兼容性钩子 | 提供商只暴露二元的思考开 / 关 | +| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性钩子 | 提供商希望仅在部分模型上启用 `xhigh` | +| 36 | `resolveDefaultThinkingLevel` | 默认 `/think` 级别兼容性钩子 | 提供商拥有某个模型家族的默认 `/think` 策略 | +| 37 | `isModernModelRef` | 用于实时 profile 过滤和 smoke 选择的现代模型匹配器 | 提供商拥有实时 / smoke 首选模型匹配逻辑 | +| 38 | `prepareRuntimeAuth` | 在推理前将已配置凭证交换为实际运行时令牌 / key | 提供商需要令牌交换或短期请求凭证 | +| 39 | `resolveUsageAuth` | 为 `/usage` 及相关状态表面解析用量 / 计费凭证 | 提供商需要自定义用量 / 配额令牌解析,或使用不同的用量凭证 | +| 40 | `fetchUsageSnapshot` | 在认证解析完成后获取并规范化提供商特定的用量 / 配额快照 | 提供商需要提供商特定的用量端点或负载解析器 | +| 41 | `createEmbeddingProvider` | 为 memory / 搜索构建由提供商拥有的嵌入适配器 | memory 嵌入行为应归属于提供商插件 | +| 42 | `buildReplayPolicy` | 返回一个重放策略,用于控制该提供商的 transcript 处理 | 提供商需要自定义 transcript 策略(例如移除 thinking 块) | +| 43 | `sanitizeReplayHistory` | 在通用 transcript 清理之后重写重放历史 | 提供商需要在共享压缩辅助工具之外,进行提供商特定的重放重写 | +| 44 | `validateReplayTurns` | 在嵌入式 runner 之前,对重放轮次进行最终验证或重塑 | 提供商传输在通用清理之后需要更严格的轮次验证 | +| 45 | `onModelSelected` | 运行由提供商拥有的选中后副作用 | 当某个模型变为活动状态时,提供商需要遥测或提供商拥有的状态 | -`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配到的提供商插件,然后继续回退到其他具备对应 hook 能力的提供商插件,直到某个插件实际修改了 model id 或 transport / config。这样可以让别名 / 兼容性提供商 shim 继续工作,而无需调用方知道哪个内置插件拥有该重写逻辑。如果没有任何提供商 hook 重写受支持的 Google 家族配置项,那么内置的 Google 配置规范化器仍会应用该兼容性清理。 +`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配到的提供商插件,然后再继续检查其他具备钩子能力的提供商插件,直到其中某个插件实际修改了模型 id 或传输 / 配置为止。这样可以让别名 / 兼容性提供商 shim 保持可用,而无需调用方知道究竟是哪个内置插件拥有该重写逻辑。如果没有任何提供商钩子重写某个受支持的 Google 家族配置项,内置的 Google 配置规范化器仍会应用该兼容性清理。 -如果提供商需要完全自定义的线协议或自定义请求执行器,那就是另一类扩展方式了。这里的这些 hooks 适用于仍运行在 OpenClaw 常规推理循环上的提供商行为。 +如果提供商需要完全自定义的线协议或自定义请求执行器,那就是另一类扩展。这些钩子适用于仍然运行在 OpenClaw 正常推理循环上的提供商行为。 ### 提供商示例 @@ -627,19 +658,30 @@ api.registerProvider({ ### 内置示例 -内置的提供商插件会根据各供应商在目录、认证、思考、重放和用量跟踪方面的需求,以不同组合使用上述 hooks。每个提供商的精确 hook 集合都与插件源码一起位于 `extensions/` 下;应以那里为权威列表,而不是在此处镜像维护。 +内置提供商插件会按各供应商在目录、认证、思考、重放和用量跟踪方面的需求,组合使用上述钩子。每个提供商的精确钩子集合都与其插件源码一起存放在 `extensions/` 下;应将那里视为权威列表,而不是在这里做镜像。 -示例模式: +说明性模式: -- **直通目录提供商**(OpenRouter、Kilocode、Z.AI、xAI)会注册 `catalog` 加 `resolveDynamicModel` / `prepareDynamicModel`,这样它们就可以在 OpenClaw 的静态目录之前暴露上游 model id。 -- **OAuth + 用量端点提供商**(GitHub Copilot、Gemini CLI、ChatGPT Codex、MiniMax、Xiaomi、z.ai)会将 `prepareRuntimeAuth` 或 `formatApiKey` 与 `resolveUsageAuth` + `fetchUsageSnapshot` 配对使用,以拥有令牌交换和 `/usage` 集成。 -- **重放 / 转录清理** 通过命名家族共享:`google-gemini`、`passthrough-gemini`、`anthropic-by-model`、`hybrid-anthropic-openai`。提供商通过 `buildReplayPolicy` 选择启用,而不是各自实现转录清理。 -- **仅目录** 的内置提供商(`byteplus`、`cloudflare-ai-gateway`、`huggingface`、`kimi-coding`、`nvidia`、`qianfan`、`synthetic`、`together`、`venice`、`vercel-ai-gateway`、`volcengine`)只注册 `catalog`,并复用共享推理循环。 -- **Anthropic 专用流辅助工具**(beta headers、`/fast` / `serviceTier`、`context1m`)位于 Anthropic 内置插件的公共 `api.ts` / `contract-api.ts` 接缝中(`wrapAnthropicProviderStream`、`resolveAnthropicBetas`、`resolveAnthropicFastMode`、`resolveAnthropicServiceTier`),而不在通用 SDK 中。 +- **透传目录提供商**(OpenRouter、Kilocode、Z.AI、xAI)会注册 + `catalog` 以及 `resolveDynamicModel` / `prepareDynamicModel`,从而能够在 OpenClaw 的静态目录之前暴露上游模型 id。 +- **OAuth + 用量端点提供商**(GitHub Copilot、Gemini CLI、ChatGPT + Codex、MiniMax、Xiaomi、z.ai)会将 `prepareRuntimeAuth` 或 `formatApiKey` + 与 `resolveUsageAuth` + `fetchUsageSnapshot` 配对使用,以拥有令牌交换和 + `/usage` 集成。 +- **重放 / transcript 清理** 通过具名家族共享: + `google-gemini`、`passthrough-gemini`、`anthropic-by-model`、 + `hybrid-anthropic-openai`。提供商通过 `buildReplayPolicy` 选择加入,而不是各自实现 transcript 清理。 +- **仅目录**的内置提供商(`byteplus`、`cloudflare-ai-gateway`、 + `huggingface`、`kimi-coding`、`nvidia`、`qianfan`、`synthetic`、`together`、 + `venice`、`vercel-ai-gateway`、`volcengine`)只注册 `catalog`,并复用共享推理循环。 +- **Anthropic 特定的流式辅助工具**(beta headers、`/fast` / `serviceTier`、 + `context1m`)位于 Anthropic 内置插件的公共 `api.ts` / + `contract-api.ts` 接缝中(`wrapAnthropicProviderStream`、`resolveAnthropicBetas`、 + `resolveAnthropicFastMode`、`resolveAnthropicServiceTier`),而不是放在通用 SDK 中。 ## 运行时辅助工具 -插件可以通过 `api.runtime` 访问部分核心辅助工具。以 TTS 为例: +插件可以通过 `api.runtime` 访问选定的核心辅助工具。以 TTS 为例: ```ts const clip = await api.runtime.tts.textToSpeech({ @@ -660,12 +702,12 @@ const voices = await api.runtime.tts.listVoices({ 说明: -- `textToSpeech` 返回用于文件 / 语音笔记表面的标准核心 TTS 输出负载。 -- 它使用核心 `messages.tts` 配置和提供商选择。 -- 返回 PCM 音频缓冲区 + 采样率。插件必须为各提供商自行重采样 / 编码。 -- `listVoices` 对每个提供商来说是可选的。可将其用于供应商自有语音选择器或设置流程。 -- 语音列表可以包含更丰富的元数据,例如区域设置、性别和 personality 标签,以供提供商感知型选择器使用。 -- 目前 OpenAI 和 ElevenLabs 支持电话场景。Microsoft 不支持。 +- `textToSpeech` 返回普通核心 TTS 输出负载,适用于文件 / 语音便签表面。 +- 使用核心 `messages.tts` 配置和提供商选择。 +- 返回 PCM 音频缓冲区 + 采样率。插件必须为提供商执行重采样 / 编码。 +- `listVoices` 对每个提供商来说都是可选的。可将它用于供应商拥有的语音选择器或设置流程。 +- 语音列表可以包含更丰富的元数据,例如语言区域、性别和人格标签,以供具备提供商感知能力的选择器使用。 +- 当前 OpenAI 和 ElevenLabs 支持电话场景。Microsoft 不支持。 插件也可以通过 `api.registerSpeechProvider(...)` 注册语音提供商。 @@ -688,11 +730,12 @@ api.registerSpeechProvider({ 说明: - 将 TTS 策略、回退和回复交付保留在核心中。 -- 将语音提供商用于供应商自有的合成行为。 -- legacy Microsoft `edge` 输入会被规范化为 `microsoft` provider id。 -- 首选的归属模型是面向公司的:随着 OpenClaw 增加这些能力契约,一个供应商插件可以同时拥有文本、语音、图像和未来的媒体提供商。 +- 使用语音提供商来承载由供应商拥有的合成行为。 +- 旧版 Microsoft `edge` 输入会被规范化为 `microsoft` 提供商 id。 +- 首选的所有权模型是面向公司的:随着 OpenClaw 添加这些能力契约,一个供应商插件可以同时拥有文本、语音、图像和未来的媒体提供商。 -对于图像 / 音频 / 视频理解,插件会注册一个类型化的媒体理解提供商,而不是通用的键 / 值袋: +对于图像 / 音频 / 视频理解,插件会注册一个类型化的 +media-understanding 提供商,而不是一个通用的键 / 值包: ```ts api.registerMediaUnderstandingProvider({ @@ -708,13 +751,13 @@ api.registerMediaUnderstandingProvider({ - 将编排、回退、配置和渠道接线保留在核心中。 - 将供应商行为保留在提供商插件中。 -- 增量扩展应保持类型化:新的可选方法、新的可选结果字段、新的可选能力。 -- 视频生成也已经遵循同样的模式: +- 增量扩展应保持类型化:新增可选方法、新增可选结果字段、新增可选能力。 +- 视频生成已经遵循相同模式: - 核心拥有能力契约和运行时辅助工具 - 供应商插件注册 `api.registerVideoGenerationProvider(...)` - 功能 / 渠道插件消费 `api.runtime.videoGeneration.*` -对于媒体理解运行时辅助工具,插件可以调用: +对于 media-understanding 运行时辅助工具,插件可以调用: ```ts const image = await api.runtime.mediaUnderstanding.describeImageFile({ @@ -729,7 +772,7 @@ const video = await api.runtime.mediaUnderstanding.describeVideoFile({ }); ``` -对于音频转录,插件可以使用媒体理解运行时,或较旧的 STT 别名: +对于音频转写,插件既可以使用 media-understanding 运行时,也可以使用较旧的 STT 别名: ```ts const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ @@ -743,8 +786,8 @@ const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ 说明: - `api.runtime.mediaUnderstanding.*` 是图像 / 音频 / 视频理解的首选共享表面。 -- 它使用核心媒体理解音频配置(`tools.media.audio`)和提供商回退顺序。 -- 当没有产生转录输出时,会返回 `{ text: undefined }`(例如输入被跳过 / 不受支持)。 +- 使用核心媒体理解音频配置(`tools.media.audio`)和提供商回退顺序。 +- 当未生成转写输出时(例如输入被跳过 / 不受支持),返回 `{ text: undefined }`。 - `api.runtime.stt.transcribeAudioFile(...)` 仍保留为兼容性别名。 插件还可以通过 `api.runtime.subagent` 启动后台子智能体运行: @@ -761,13 +804,13 @@ const result = await api.runtime.subagent.run({ 说明: -- `provider` 和 `model` 是按次运行覆盖项,而不是持久会话变更。 -- OpenClaw 仅对受信任调用方认可这些覆盖字段。 +- `provider` 和 `model` 是每次运行可选覆盖项,不是持久化的会话更改。 +- OpenClaw 只会为受信任调用方启用这些覆盖字段。 - 对于插件拥有的回退运行,操作员必须通过 `plugins.entries..subagent.allowModelOverride: true` 明确启用。 -- 使用 `plugins.entries..subagent.allowedModels` 可将受信任插件限制为特定规范 `provider/model` 目标,或显式设为 `"*"` 以允许任意目标。 -- 不受信任的插件子智能体运行仍可工作,但覆盖请求会被拒绝,而不是静默回退。 +- 使用 `plugins.entries..subagent.allowedModels` 可将受信任插件限制为特定规范化 `provider/model` 目标,或使用 `"*"` 以显式允许任意目标。 +- 不受信任的插件子智能体运行仍然可用,但覆盖请求会被拒绝,而不是悄悄回退。 -对于 Web 搜索,插件可以消费共享运行时辅助工具,而不必深入智能体工具接线: +对于 Web 搜索,插件可以消费共享运行时辅助工具,而不是直接深入到智能体工具接线中: ```ts const providers = api.runtime.webSearch.listProviders({ @@ -783,13 +826,14 @@ const result = await api.runtime.webSearch.search({ }); ``` -插件也可以通过 `api.registerWebSearchProvider(...)` 注册 Web 搜索提供商。 +插件也可以通过 +`api.registerWebSearchProvider(...)` 注册 Web 搜索提供商。 说明: - 将提供商选择、凭证解析和共享请求语义保留在核心中。 -- 将 Web 搜索提供商用于供应商专用搜索传输。 -- `api.runtime.webSearch.*` 是需要搜索行为但不依赖智能体工具包装器的功能 / 渠道插件的首选共享表面。 +- 使用 Web 搜索提供商承载供应商特定的搜索传输。 +- 对于需要搜索行为但又不想依赖智能体工具包装器的功能 / 渠道插件,`api.runtime.webSearch.*` 是首选共享表面。 ### `api.runtime.imageGeneration` @@ -827,152 +871,173 @@ api.registerHttpRoute({ 路由字段: - `path`:Gateway 网关 HTTP 服务器下的路由路径。 -- `auth`:必填。使用 `"gateway"` 以要求常规 gateway 认证,或使用 `"plugin"` 进行插件管理的认证 / webhook 验证。 +- `auth`:必填。使用 `"gateway"` 表示需要普通 Gateway 网关认证,或使用 `"plugin"` 表示由插件管理认证 / webhook 验证。 - `match`:可选。`"exact"`(默认)或 `"prefix"`。 -- `replaceExisting`:可选。允许同一插件替换它自己现有的路由注册。 +- `replaceExisting`:可选。允许同一个插件替换它自己现有的路由注册。 - `handler`:当路由处理了请求时返回 `true`。 说明: - `api.registerHttpHandler(...)` 已被移除,并会导致插件加载错误。请改用 `api.registerHttpRoute(...)`。 - 插件路由必须显式声明 `auth`。 -- 除非设置 `replaceExisting: true`,否则精确 `path + match` 冲突会被拒绝,而且一个插件不能替换另一个插件的路由。 -- 不同 `auth` 级别的重叠路由会被拒绝。仅在相同 auth 级别上保留 `exact` / `prefix` 回退链。 +- 除非设置了 `replaceExisting: true`,否则精确的 `path + match` 冲突会被拒绝,而且一个插件不能替换另一个插件的路由。 +- 不同 `auth` 级别的重叠路由会被拒绝。只在相同认证级别内保留 `exact` / `prefix` 贯穿链。 - `auth: "plugin"` 路由**不会**自动接收操作员运行时作用域。它们用于插件管理的 webhook / 签名验证,而不是特权 Gateway 网关辅助调用。 -- `auth: "gateway"` 路由会在 Gateway 网关请求运行时作用域内运行,但该作用域是有意保守的: - - 共享密钥 bearer 认证(`gateway.auth.mode = "token"` / `"password"`)会将插件路由运行时作用域固定为 `operator.write`,即使调用方发送了 `x-openclaw-scopes` 也是如此 - - 受信任、带身份的 HTTP 模式(例如 `trusted-proxy`,或私有入口上的 `gateway.auth.mode = "none"`)只有在显式存在该头时才会认可 `x-openclaw-scopes` - - 如果这些带身份的插件路由请求中缺少 `x-openclaw-scopes`,运行时作用域将回退为 `operator.write` -- 实际规则:不要假定 gateway-auth 插件路由天然就是隐式管理员表面。如果你的路由需要仅管理员可用的行为,请要求带身份的认证模式,并在文档中说明显式 `x-openclaw-scopes` 头契约。 +- `auth: "gateway"` 路由运行在 Gateway 网关请求运行时作用域内,但该作用域是有意保守的: + - 共享密钥 bearer 认证(`gateway.auth.mode = "token"` / `"password"`)会将插件路由运行时作用域固定为 `operator.write`,即使调用方发送了 `x-openclaw-scopes` + - 受信任的带身份 HTTP 模式(例如 `trusted-proxy` 或私有入口上的 `gateway.auth.mode = "none"`)只有在显式存在该头时,才会尊重 `x-openclaw-scopes` + - 如果这些带身份的插件路由请求中不存在 `x-openclaw-scopes`,运行时作用域会回退为 `operator.write` +- 实用规则:不要假设经过 gateway 认证的插件路由天然就是隐式管理员表面。如果你的路由需要仅管理员可用的行为,请要求使用带身份的认证模式,并文档化显式的 `x-openclaw-scopes` 请求头契约。 ## 插件 SDK 导入路径 -在编写新插件时,请使用狭义 SDK 子路径,而不是整体式的 `openclaw/plugin-sdk` 根 barrel。核心子路径: +在编写新插件时,请使用狭义 SDK 子路径,而不是使用单体式的 `openclaw/plugin-sdk` 根 barrel。 +核心子路径: | 子路径 | 用途 | | ----------------------------------- | -------------------------------------------------- | | `openclaw/plugin-sdk/plugin-entry` | 插件注册原语 | -| `openclaw/plugin-sdk/core` | 通用共享的面向插件契约 | -| `openclaw/plugin-sdk/config-schema` | 根 `openclaw.json` Zod schema(`OpenClawSchema`) | +| `openclaw/plugin-sdk/channel-core` | 渠道入口 / 构建辅助工具 | +| `openclaw/plugin-sdk/core` | 通用共享辅助工具和总括契约 | +| `openclaw/plugin-sdk/config-schema` | 根级 `openclaw.json` Zod schema(`OpenClawSchema`) | -渠道插件可从一组狭义接缝中进行选择——`channel-setup`、`setup-runtime`、`setup-adapter-runtime`、`setup-tools`、`channel-pairing`、`channel-contract`、`channel-feedback`、`channel-inbound`、`channel-lifecycle`、`channel-reply-pipeline`、`command-auth`、`secret-input`、`webhook-ingress`、`channel-targets` 和 `channel-actions`。审批行为应统一收敛到一个 `approvalCapability` 契约,而不是混杂在无关的插件字段之间。参见[渠道插件](/zh-CN/plugins/sdk-channel-plugins)。 +渠道插件可从一组狭义接缝中进行选择 —— `channel-setup`、 +`setup-runtime`、`setup-adapter-runtime`、`setup-tools`、`channel-pairing`、 +`channel-contract`、`channel-feedback`、`channel-inbound`、`channel-lifecycle`、 +`channel-reply-pipeline`、`command-auth`、`secret-input`、`webhook-ingress`、 +`channel-targets` 和 `channel-actions`。审批行为应统一收敛到一个 +`approvalCapability` 契约上,而不是混用到彼此无关的插件字段中。 +请参阅[渠道插件](/zh-CN/plugins/sdk-channel-plugins)。 -运行时和配置辅助工具位于对应的 `*-runtime` 子路径下(`approval-runtime`、`config-runtime`、`infra-runtime`、`agent-runtime`、`lazy-runtime`、`directory-runtime`、`text-runtime`、`runtime-store` 等)。 +运行时和配置辅助工具位于与之对应的 `*-runtime` 子路径下 +(`approval-runtime`、`config-runtime`、`infra-runtime`、`agent-runtime`、 +`lazy-runtime`、`directory-runtime`、`text-runtime`、`runtime-store` 等)。 -`openclaw/plugin-sdk/channel-runtime` 已弃用——它是为旧插件保留的兼容性 shim。新代码应改为导入更狭义的通用原语。 +`openclaw/plugin-sdk/channel-runtime` 已弃用 —— 它只是旧版插件的兼容 shim。 +新代码应改为导入更狭义的通用原语。 -仓库内部入口点(每个内置插件包根目录): +仓库内部入口点(按每个内置插件包根目录划分): - `index.js` —— 内置插件入口 - `api.js` —— 辅助工具 / 类型 barrel - `runtime-api.js` —— 仅运行时 barrel -- `setup-entry.js` —— setup 插件入口 +- `setup-entry.js` —— 设置插件入口 -外部插件应仅导入 `openclaw/plugin-sdk/*` 子路径。绝不要从核心或其他插件中导入另一个插件包的 `src/*`。由 facade 加载的入口点会优先使用当前激活的运行时配置快照;如果不存在,则回退到磁盘上已解析的配置文件。 +外部插件应只导入 `openclaw/plugin-sdk/*` 子路径。绝不要从核心或其他插件中导入另一个插件包的 `src/*`。 +Facade 加载的入口点会在存在时优先使用当前活动的运行时配置快照,否则回退到磁盘上解析出的配置文件。 -诸如 `image-generation`、`media-understanding` 和 `speech` 这样的能力专用子路径之所以存在,是因为当前的内置插件正在使用它们。它们并不自动等同于长期冻结的外部契约——依赖它们时,请查阅对应的 SDK 参考页面。 +像 `image-generation`、`media-understanding` 和 `speech` 这样的能力特定子路径之所以存在,是因为如今内置插件仍在使用它们。它们并不自动等同于长期冻结的外部契约 —— 当你依赖它们时,请查看相关 SDK 参考页面。 -## 消息工具 schema +## message 工具 schema -对于反应、已读和投票等非消息原语,插件应拥有渠道专用的 `describeMessageTool(...)` schema 贡献。共享发送呈现应使用通用 `MessagePresentation` 契约,而不是提供商原生的按钮、组件、区块或卡片字段。 -关于该契约、回退规则、提供商映射和插件作者清单,请参阅[消息呈现](/zh-CN/plugins/message-presentation)。 +对于 reaction、read 和 poll 这类非消息原语,插件应拥有渠道特定的 `describeMessageTool(...)` schema 贡献。 +共享发送展示应使用通用 `MessagePresentation` 契约,而不是提供商原生的按钮、组件、块或卡片字段。 +关于该契约、回退规则、提供商映射和插件作者检查清单,请参阅[消息展示](/zh-CN/plugins/message-presentation)。 -具备发送能力的插件通过消息能力声明自己能渲染的内容: +具备发送能力的插件通过消息能力声明它们可以渲染的内容: -- `presentation`,用于语义化呈现区块(`text`、`context`、`divider`、`buttons`、`select`) -- `delivery-pin`,用于固定投递请求 +- `presentation` 用于语义展示块(`text`、`context`、`divider`、`buttons`、`select`) +- `delivery-pin` 用于置顶投递请求 -核心决定是原生渲染该呈现,还是将其降级为文本。不要从通用 message 工具暴露提供商原生 UI 逃生口。 -面向 legacy 原生 schema 的已弃用 SDK 辅助工具仍然会为现有第三方插件保留导出,但新插件不应使用它们。 +核心负责决定是原生渲染该展示,还是将其降级为文本。 +不要从通用 message 工具中暴露提供商原生 UI 的逃生口。 +为兼容现有第三方插件而保留的旧版原生 schema SDK 辅助工具仍然会继续导出,但新插件不应使用它们。 ## 渠道目标解析 -渠道插件应拥有渠道专用的目标语义。保持共享 outbound host 的通用性,并使用消息适配器表面处理提供商规则: +渠道插件应拥有渠道特定的目标语义。保持共享出站宿主的通用性,并使用消息适配器表面承载提供商规则: -- `messaging.inferTargetChatType({ to })` 决定某个规范化目标在目录查找前应被视为 `direct`、`group` 还是 `channel` -- `messaging.targetResolver.looksLikeId(raw, normalized)` 告诉核心某个输入是否应跳过目录搜索,直接进入类 id 解析 -- `messaging.targetResolver.resolveTarget(...)` 是插件回退路径,用于在规范化之后或目录未命中之后,由核心进行最终的提供商自有解析 -- `messaging.resolveOutboundSessionRoute(...)` 在目标解析完成后拥有提供商专用的会话路由构造逻辑 +- `messaging.inferTargetChatType({ to })` 决定一个规范化目标在目录查找前应被视为 `direct`、`group` 还是 `channel` +- `messaging.targetResolver.looksLikeId(raw, normalized)` 告诉核心某个输入是否应跳过目录搜索,直接进入类似 id 的解析 +- `messaging.targetResolver.resolveTarget(...)` 是当核心在规范化之后或目录未命中后,仍需要最终由提供商拥有的解析时,插件提供的回退路径 +- `messaging.resolveOutboundSessionRoute(...)` 则在目标解析完成后,拥有提供商特定的会话路由构造逻辑 -推荐拆分: +推荐拆分方式: -- 对于应在搜索 peers / groups 之前发生的类别判定,使用 `inferTargetChatType` -- 对于“将其视为显式 / 原生目标 id”的判断,使用 `looksLikeId` -- 对于提供商专用的规范化回退,使用 `resolveTarget`,而不是用于广义目录搜索 -- 将提供商原生 id,例如 chat id、thread id、JID、handle 和 room id,保留在 `target` 值或提供商专用参数中,而不要放进通用 SDK 字段 +- 对于应在搜索 peers / groups 之前完成的类别判断,使用 `inferTargetChatType` +- 对于“将此视为显式 / 原生目标 id”的判断,使用 `looksLikeId` +- 将 `resolveTarget` 用于提供商特定的规范化回退,而不是用于广泛的目录搜索 +- 将 chat id、thread id、JID、handle 和 room id 这类提供商原生 id 保留在 `target` 值或提供商特定参数中,而不是放入通用 SDK 字段 -## 基于配置的目录 +## 配置支持的目录 -对于从配置派生目录条目的插件,应将该逻辑保留在插件内部,并复用 `openclaw/plugin-sdk/directory-runtime` 中的共享辅助工具。 +如果插件从配置中派生目录条目,应将该逻辑保留在插件内,并复用 +`openclaw/plugin-sdk/directory-runtime` 中的共享辅助工具。 -当某个渠道需要基于配置的 peers / groups 时,可使用这种方式,例如: +当渠道需要配置支持的 peers / groups 时,请使用这种方式,例如: -- 基于 allowlist 的私信 peers +- 由 allowlist 驱动的私信 peers - 已配置的渠道 / 群组映射 - 按账户划分的静态目录回退 -`directory-runtime` 中的共享辅助工具仅处理通用操作: +`directory-runtime` 中的共享辅助工具只处理通用操作: - 查询过滤 -- 应用限制 +- 限制应用 - 去重 / 规范化辅助工具 - 构建 `ChannelDirectoryEntry[]` -渠道专用的账户检查和 id 规范化应保留在插件实现中。 +渠道特定的账户检查和 id 规范化应保留在插件实现中。 ## 提供商目录 -提供商插件可以通过 `registerProvider({ catalog: { run(...) { ... } } })` 为推理定义模型目录。 +提供商插件可以通过 +`registerProvider({ catalog: { run(...) { ... } } })` +为推理定义模型目录。 -`catalog.run(...)` 返回与 OpenClaw 写入 `models.providers` 相同的结构: +`catalog.run(...)` 返回的结构与 OpenClaw 写入 +`models.providers` 的结构相同: -- `{ provider }`,表示一个提供商条目 -- `{ providers }`,表示多个提供商条目 +- `{ provider }` 表示一个提供商条目 +- `{ providers }` 表示多个提供商条目 -当插件拥有提供商专用的 model id、base URL 默认值或受认证门控的模型元数据时,请使用 `catalog`。 +当插件拥有提供商特定的模型 id、base URL 默认值或受认证控制的模型元数据时,请使用 `catalog`。 -`catalog.order` 控制某个插件目录相对于 OpenClaw 内置隐式提供商的合并时机: +`catalog.order` 控制插件目录相对于 OpenClaw 内置隐式提供商的合并时机: -- `simple`:普通 API 密钥或基于环境变量的提供商 -- `profile`:存在认证配置文件时出现的提供商 -- `paired`:合成多个相关提供商条目的提供商 +- `simple`:普通 API key 或环境变量驱动的提供商 +- `profile`:当存在认证 profile 时出现的提供商 +- `paired`:会合成多个相关提供商条目的提供商 - `late`:最后一轮,在其他隐式提供商之后 -后面的提供商在键冲突时会获胜,因此插件可以有意用相同 provider id 覆盖内置提供商条目。 +后出现的提供商会在键冲突时获胜,因此插件可以有意覆盖具有相同提供商 id 的内置提供商条目。 -兼容性: +兼容性说明: -- `discovery` 作为 legacy 别名仍然可用 +- `discovery` 仍可作为旧版别名使用 - 如果同时注册了 `catalog` 和 `discovery`,OpenClaw 会使用 `catalog` ## 只读渠道检查 -如果你的插件注册了一个渠道,除了 `resolveAccount(...)` 之外,还应优先实现 `plugin.config.inspectAccount(cfg, accountId)`。 +如果你的插件注册了一个渠道,除了实现 `resolveAccount(...)` 外,还应优先实现 +`plugin.config.inspectAccount(cfg, accountId)`。 -原因: +原因如下: -- `resolveAccount(...)` 是运行时路径。它可以假设凭证已被完整实体化,并且在缺少必需 secret 时快速失败。 -- 像 `openclaw status`、`openclaw status --all`、`openclaw channels status`、`openclaw channels resolve` 以及 doctor / 配置修复流程这样的只读命令路径,不应为了描述配置就必须实体化运行时凭证。 +- `resolveAccount(...)` 是运行时路径。它可以假定凭证已经完全实体化,并且在缺失必需 secret 时快速失败。 +- 像 `openclaw status`、`openclaw status --all`、 + `openclaw channels status`、`openclaw channels resolve` 以及 doctor / 配置修复流程这样的只读命令路径,不应为了描述配置而必须实体化运行时凭证。 推荐的 `inspectAccount(...)` 行为: -- 仅返回描述性账户状态。 +- 只返回描述性的账户状态。 - 保留 `enabled` 和 `configured`。 - 在相关时包含凭证来源 / 状态字段,例如: - `tokenSource`、`tokenStatus` - `botTokenSource`、`botTokenStatus` - `appTokenSource`、`appTokenStatus` - `signingSecretSource`、`signingSecretStatus` -- 你不需要为了报告只读可用性而返回原始令牌值。返回 `tokenStatus: "available"`(以及匹配的来源字段)就足以满足 status 风格命令。 +- 为了报告只读可用性,你不需要返回原始 token 值。返回 + `tokenStatus: "available"`(以及对应的 source 字段)就足以满足状态类命令。 - 当某个凭证通过 SecretRef 配置,但在当前命令路径中不可用时,请使用 `configured_unavailable`。 -这样可以让只读命令报告“已配置,但在此命令路径中不可用”,而不是崩溃或错误地将该账户报告为未配置。 +这使只读命令能够报告“已配置,但在当前命令路径中不可用”,而不是崩溃或误报该账户未配置。 -## 包集合 +## 包 pack -插件目录可以包含带有 `openclaw.extensions` 的 `package.json`: +一个插件目录可以包含带有 `openclaw.extensions` 的 `package.json`: ```json { @@ -984,37 +1049,48 @@ api.registerHttpRoute({ } ``` -每个条目都会成为一个插件。如果该包集合列出了多个扩展,则插件 id 将变为 `name/`。 +每个条目都会成为一个插件。如果该 pack 列出了多个 extension,则插件 id +会变为 `name/`。 -如果你的插件导入了 npm 依赖,请在该目录中安装它们,以便 `node_modules` 可用(`npm install` / `pnpm install`)。 +如果你的插件导入了 npm 依赖,请在该目录中安装它们,以便 +`node_modules` 可用(`npm install` / `pnpm install`)。 -安全护栏:每个 `openclaw.extensions` 条目在解析符号链接后都必须保留在插件目录内。任何逃逸出包目录的条目都会被拒绝。 +安全护栏:每个 `openclaw.extensions` 条目在解析符号链接后都必须仍位于插件目录内。任何逃逸出包目录的条目都会被拒绝。 -安全说明:`openclaw plugins install` 会使用 `npm install --omit=dev --ignore-scripts` 安装插件依赖(无生命周期脚本、运行时不安装开发依赖)。请保持插件依赖树为“纯 JS / TS”,并避免需要 `postinstall` 构建的包。 +安全说明:`openclaw plugins install` 会使用 +`npm install --omit=dev --ignore-scripts` 安装插件依赖 +(无生命周期脚本,且运行时不安装开发依赖)。请保持插件依赖树为“纯 JS/TS”,并避免使用那些需要 `postinstall` 构建的包。 -可选:`openclaw.setupEntry` 可以指向一个轻量级、仅 setup 的模块。当 OpenClaw 需要为已禁用的渠道插件提供 setup 表面,或某个渠道插件已启用但尚未配置时,它会加载 `setupEntry`,而不是完整插件入口。这样当主插件入口还会接线工具、hooks 或其他仅运行时代码时,就能让启动和 setup 更轻量。 +可选项:`openclaw.setupEntry` 可以指向一个轻量级的仅设置模块。 +当 OpenClaw 需要为已禁用的渠道插件提供设置表面,或者当某个渠道插件已启用但尚未配置时,它会加载 `setupEntry`,而不是完整插件入口。 +当你的主插件入口还会接线工具、钩子或其他仅运行时代码时,这可以让启动和设置更轻量。 -可选:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` 可让某个渠道插件在 Gateway 网关监听前的启动阶段,即使该渠道已配置,也采用同样的 `setupEntry` 路径。 +可选项:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` +可以让渠道插件在 Gateway 网关监听前启动阶段也选择进入同样的 `setupEntry` 路径,即使该渠道已经完成配置。 -只有当 `setupEntry` 完整覆盖了 gateway 开始监听前必须存在的启动表面时,才应使用此选项。实践中,这意味着 setup 入口必须注册启动所依赖的每一项渠道自有能力,例如: +只有当 `setupEntry` 能完整覆盖 Gateway 网关开始监听前必须存在的启动表面时,才应使用此选项。实际上,这意味着设置入口必须注册启动所依赖的每一项渠道拥有能力,例如: - 渠道注册本身 -- 任何必须在 gateway 开始监听前可用的 HTTP 路由 -- 在同一时间窗口内必须存在的任何 gateway 方法、工具或服务 +- 任何必须在 Gateway 网关开始监听前可用的 HTTP 路由 +- 在同一时间窗口内必须存在的任何 Gateway 网关方法、工具或服务 -如果你的完整入口仍然拥有任何必需的启动能力,请不要启用此标志。保持插件采用默认行为,并让 OpenClaw 在启动期间加载完整入口。 +如果你的完整入口仍然拥有任何必需的启动能力,就不要启用这个标志。应保持插件使用默认行为,并让 OpenClaw 在启动期间加载完整入口。 -内置渠道也可以发布仅 setup 的契约表面辅助工具,以便核心在完整渠道运行时加载之前进行查询。当前的 setup 提升表面包括: +内置渠道也可以发布仅设置用的契约表面辅助工具,以便核心在完整渠道运行时加载前进行查询。当前的设置提升表面包括: - `singleAccountKeysToMove` - `namedAccountPromotionKeys` - `resolveSingleAccountPromotionTarget(...)` -当核心需要在不加载完整插件入口的情况下,将 legacy 单账户渠道配置提升到 `channels..accounts.*` 时,就会使用该表面。Matrix 是当前的内置示例:当已存在命名账户时,它只会将认证 / 引导键移动到一个命名的已提升账户中,并且可以保留已配置的非规范默认账户键,而不是总是创建 `accounts.default`。 +当核心需要在不加载完整插件入口的情况下,将旧版单账户渠道配置提升到 +`channels..accounts.*` 时,就会使用该表面。Matrix 是当前的内置示例:当已存在命名账户时,它只会将认证 / 引导键移动到某个已命名的提升账户中,并且可以保留已配置的非规范默认账户键,而不是始终创建 +`accounts.default`。 -这些 setup 补丁适配器使内置契约表面发现保持懒加载。导入时开销保持轻量;提升表面只会在首次使用时加载,而不会在模块导入时重新进入内置渠道启动流程。 +这些设置补丁适配器让内置契约表面发现保持惰性。导入时开销保持轻量;提升表面只会在首次使用时加载,而不会在模块导入时重新进入内置渠道启动流程。 -当这些启动表面包含 gateway RPC 方法时,请将它们保留在插件专用前缀下。核心管理员命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)仍然是保留的,并且始终解析为 `operator.admin`,即使某个插件请求了更窄的作用域。 +当这些启动表面包含 Gateway 网关 RPC 方法时,请将它们保留在插件特定前缀下。核心管理命名空间(`config.*`、 +`exec.approvals.*`、`wizard.*`、`update.*`)始终保留,并且总会解析为 +`operator.admin`,即使插件请求了更窄的作用域也是如此。 示例: @@ -1033,7 +1109,8 @@ api.registerHttpRoute({ ### 渠道目录元数据 -渠道插件可以通过 `openclaw.channel` 声明 setup / 发现元数据,并通过 `openclaw.install` 声明安装提示。这样可以让核心目录保持无数据耦合。 +渠道插件可以通过 `openclaw.channel` 声明设置 / 发现元数据,并通过 +`openclaw.install` 声明安装提示。这样可以让核心目录保持无数据。 示例: @@ -1045,10 +1122,10 @@ api.registerHttpRoute({ "channel": { "id": "nextcloud-talk", "label": "Nextcloud Talk", - "selectionLabel": "Nextcloud Talk (self-hosted)", + "selectionLabel": "Nextcloud Talk(自托管)", "docsPath": "/channels/nextcloud-talk", "docsLabel": "nextcloud-talk", - "blurb": "通过 Nextcloud Talk webhook 机器人实现的自托管聊天。", + "blurb": "通过 Nextcloud Talk webhook 机器人提供自托管聊天。", "order": 65, "aliases": ["nc-talk", "nc"] }, @@ -1061,34 +1138,38 @@ api.registerHttpRoute({ } ``` -除最小示例外,有用的 `openclaw.channel` 字段还包括: +`openclaw.channel` 中除最小示例外还有一些有用字段: - `detailLabel`:用于更丰富目录 / 状态表面的次级标签 - `docsLabel`:覆盖文档链接的链接文本 -- `preferOver`:此目录条目应优先于的低优先级插件 / 渠道 id +- `preferOver`:此目录条目应优先于其上的低优先级插件 / 渠道 id - `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面的文案控制项 -- `markdownCapable`:将该渠道标记为支持 Markdown,以供出站格式化决策使用 -- `exposure.configured`:设为 `false` 时,在“已配置渠道”列表表面中隐藏该渠道 -- `exposure.setup`:设为 `false` 时,在交互式 setup / configure 选择器中隐藏该渠道 -- `exposure.docs`:将该渠道标记为内部 / 私有,用于文档导航表面 -- `showConfigured` / `showInSetup`:出于兼容性仍接受的 legacy 别名;优先使用 `exposure` -- `quickstartAllowFrom`:让该渠道接入标准快速开始 `allowFrom` 流程 +- `markdownCapable`:将该渠道标记为支持 Markdown,以用于出站格式决策 +- `exposure.configured`:当设为 `false` 时,在已配置渠道列表表面中隐藏该渠道 +- `exposure.setup`:当设为 `false` 时,在交互式设置 / 配置选择器中隐藏该渠道 +- `exposure.docs`:在文档导航表面中将该渠道标记为内部 / 私有 +- `showConfigured` / `showInSetup`:仍接受的旧版别名,仅用于兼容;优先使用 `exposure` +- `quickstartAllowFrom`:使该渠道选择加入标准快速开始 `allowFrom` 流程 - `forceAccountBinding`:即使只存在一个账户,也要求显式账户绑定 -- `preferSessionLookupForAnnounceTarget`:在解析 announce 目标时优先使用会话查找 +- `preferSessionLookupForAnnounceTarget`:在解析公告目标时优先使用会话查找 -OpenClaw 还可以合并**外部渠道目录**(例如 MPM 注册表导出)。将 JSON 文件放到以下任一位置: +OpenClaw 也可以合并**外部渠道目录**(例如 MPM 注册表导出)。 +将一个 JSON 文件放到以下任一位置: - `~/.openclaw/mpm/plugins.json` - `~/.openclaw/mpm/catalog.json` - `~/.openclaw/plugins/catalog.json` -或者将 `OPENCLAW_PLUGIN_CATALOG_PATHS`(或 `OPENCLAW_MPM_CATALOG_PATHS`)指向一个或多个 JSON 文件(以逗号 / 分号 / `PATH` 分隔)。每个文件应包含 `{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }`。解析器还接受 `"packages"` 或 `"plugins"` 作为 `"entries"` 键的 legacy 别名。 +或者,将 `OPENCLAW_PLUGIN_CATALOG_PATHS`(或 `OPENCLAW_MPM_CATALOG_PATHS`)指向一个或多个 JSON 文件(以逗号 / 分号 / `PATH` 分隔)。每个文件应包含 +`{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }`。解析器也接受 `"packages"` 或 `"plugins"` 作为 `"entries"` 键的旧版别名。 ## 上下文引擎插件 -上下文引擎插件拥有会话上下文编排,包括摄取、组装和压缩。可在你的插件中通过 `api.registerContextEngine(id, factory)` 注册它们,然后使用 `plugins.slots.contextEngine` 选择活动引擎。 +上下文引擎插件拥有会话上下文编排,用于摄取、组装和压缩。可在你的插件中通过 +`api.registerContextEngine(id, factory)` 注册它们,然后通过 +`plugins.slots.contextEngine` 选择活动引擎。 -当你的插件需要替换或扩展默认上下文流水线,而不只是添加 memory 搜索或 hooks 时,请使用此方式。 +当你的插件需要替换或扩展默认上下文流水线,而不仅仅是添加 memory 搜索或钩子时,请使用这种方式。 ```ts import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core"; @@ -1153,24 +1234,24 @@ export default function (api) { ## 添加新能力 -当插件需要当前 API 无法满足的行为时,不要通过私有内部访问绕过插件系统。请添加缺失的能力。 +当插件需要当前 API 无法容纳的行为时,不要通过私有内部调用绕过插件系统。应当添加缺失的能力。 推荐顺序: 1. 定义核心契约 - 决定核心应拥有哪些共享行为:策略、回退、配置合并、生命周期、面向渠道的语义以及运行时辅助工具结构。 + 决定核心应拥有哪些共享行为:策略、回退、配置合并、生命周期、面向渠道的语义以及运行时辅助工具形态。 2. 添加类型化的插件注册 / 运行时表面 - 以最小但有用的类型化能力表面扩展 `OpenClawPluginApi` 和 / 或 `api.runtime`。 -3. 对接核心 + 渠道 / 功能消费者 - 渠道和功能插件应通过核心消费新能力,而不是直接导入某个供应商实现。 + 使用最小且有用的类型化能力表面扩展 `OpenClawPluginApi` 和 / 或 `api.runtime`。 +3. 为核心 + 渠道 / 功能消费者完成接线 + 渠道和功能插件应通过核心消费这一新能力,而不是直接导入某个供应商实现。 4. 注册供应商实现 - 然后由供应商插件针对该能力注册其后端实现。 + 然后由供应商插件将其后端注册到该能力上。 5. 添加契约覆盖 - 添加测试,使归属和注册结构随着时间推移仍保持明确。 + 添加测试,以便让所有权和注册形态长期保持明确。 -这就是 OpenClaw 保持鲜明主张、又不会被某个供应商世界观硬编码绑死的方式。关于具体的文件清单和完整示例,请参阅[能力扩展手册](/zh-CN/plugins/architecture)。 +这正是 OpenClaw 在保持有主见的同时,又不被某个提供商世界观硬编码绑定的方式。具体文件检查清单和完整示例,请参阅[能力扩展手册](/zh-CN/plugins/architecture)。 -### 能力清单 +### 能力检查清单 当你添加一个新能力时,实现通常应同时涉及以下表面: @@ -1178,12 +1259,12 @@ export default function (api) { - `src//runtime.ts` 中的核心 runner / 运行时辅助工具 - `src/plugins/types.ts` 中的插件 API 注册表面 - `src/plugins/registry.ts` 中的插件注册表接线 -- 当功能 / 渠道插件需要消费它时,`src/plugins/runtime/*` 中的插件运行时暴露 +- 当功能 / 渠道插件需要消费它时,位于 `src/plugins/runtime/*` 中的插件运行时暴露 - `src/test-utils/plugin-registration.ts` 中的捕获 / 测试辅助工具 -- `src/plugins/contracts/registry.ts` 中的归属 / 契约断言 +- `src/plugins/contracts/registry.ts` 中的所有权 / 契约断言 - `docs/` 中面向操作员 / 插件的文档 -如果其中某个表面缺失,通常说明这个能力还没有完全集成。 +如果其中某个表面缺失,通常意味着该能力尚未完全集成。 ### 能力模板 @@ -1224,4 +1305,4 @@ expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]); - 核心拥有能力契约 + 编排 - 供应商插件拥有供应商实现 - 功能 / 渠道插件消费运行时辅助工具 -- 契约测试让归属保持明确 +- 契约测试让所有权保持明确