diff --git a/docs/zh-CN/gateway/bonjour.md b/docs/zh-CN/gateway/bonjour.md index f5bc73cda..552980d7c 100644 --- a/docs/zh-CN/gateway/bonjour.md +++ b/docs/zh-CN/gateway/bonjour.md @@ -2,37 +2,38 @@ read_when: - 在 macOS/iOS 上调试 Bonjour 发现问题 - 更改 mDNS 服务类型、TXT 记录或发现 UX -summary: Bonjour/mDNS 发现与调试(Gateway 网关信标、客户端和常见故障模式) +summary: Bonjour/mDNS 发现 + 调试(Gateway 网关信标、客户端以及常见故障模式) title: Bonjour 发现 x-i18n: - generated_at: "2026-04-23T20:48:11Z" + generated_at: "2026-04-24T06:33:27Z" model: gpt-5.4 provider: openai - source_hash: d5d9099ce178aca1e6e443281133928f886de965245ad0fb02ce91a27aad3989 + source_hash: 62961714a0c9880be457c254e1cfc1701020ea51b89f2582757cddc8b3dd2113 source_path: gateway/bonjour.md workflow: 15 --- # Bonjour / mDNS 发现 -OpenClaw 使用 Bonjour(mDNS / DNS-SD)来发现活动的 Gateway 网关(WebSocket 端点)。 -多播 `local.` 浏览是一种**仅限局域网的便利功能**。对于跨网络发现, -同一个信标也可以通过已配置的广域 DNS-SD 域发布。发现机制仍然是 -尽力而为的,**不能**替代 SSH 或基于 Tailnet 的连接。 +OpenClaw 使用 Bonjour(mDNS / DNS‑SD)来发现活动中的 Gateway 网关(WebSocket 端点)。 +多播 `local.` 浏览是一种**仅限局域网的便利机制**。内置的 `bonjour` +插件负责局域网广播,且默认启用。对于跨网络发现, +同一个信标也可以通过已配置的广域 DNS-SD 域发布。 +发现机制仍然是尽力而为,**不能**替代 SSH 或基于 Tailnet 的连接方式。 ## 通过 Tailscale 使用广域 Bonjour(单播 DNS-SD) -如果节点和 Gateway 网关位于不同网络,多播 mDNS 将无法跨越该 -边界。你可以通过在 Tailscale 上切换到**单播 DNS-SD** -(“Wide-Area Bonjour”)来保留同样的发现体验。 +如果节点和 Gateway 网关位于不同网络,多播 mDNS 不会跨越该 +边界。你可以切换到**单播 DNS‑SD** +(“广域 Bonjour”)并通过 Tailscale 使用它,从而保留相同的发现 UX。 -高层步骤: +高级步骤如下: -1. 在 Gateway 网关主机上运行一个 DNS 服务器(可通过 Tailnet 访问)。 -2. 在专用区域下为 `_openclaw-gw._tcp` 发布 DNS-SD 记录 - (例如:`openclaw.internal.`)。 -3. 配置 Tailscale **split DNS**,让客户端(包括 iOS) - 通过该 DNS 服务器解析你选择的域。 +1. 在 Gateway 网关主机上运行 DNS 服务器(可通过 Tailnet 访问)。 +2. 在专用区域下为 `_openclaw-gw._tcp` 发布 DNS‑SD 记录 + (示例:`openclaw.internal.`)。 +3. 配置 Tailscale **split DNS**,使你的选定域通过该 + DNS 服务器为客户端(包括 iOS)解析。 OpenClaw 支持任意发现域;`openclaw.internal.` 只是一个示例。 iOS/Android 节点会同时浏览 `local.` 和你配置的广域域名。 @@ -54,10 +55,10 @@ openclaw dns setup --apply 这会安装 CoreDNS 并将其配置为: -- 仅在 Gateway 网关的 Tailscale 接口上监听 53 端口 -- 从 `~/.openclaw/dns/.db` 提供你所选域(例如:`openclaw.internal.`) +- 仅在 Gateway 网关的 Tailscale 接口上的 53 端口监听 +- 从 `~/.openclaw/dns/.db` 为你选择的域(示例:`openclaw.internal.`)提供服务 -从一台已连接 tailnet 的机器上验证: +在已连接 tailnet 的机器上验证: ```bash dns-sd -B _openclaw-gw._tcp openclaw.internal. @@ -76,45 +77,47 @@ dig @ -p 53 _openclaw-gw._tcp.openclaw.internal PTR +short ### Gateway 网关监听器安全性(推荐) -Gateway 网关 WS 端口(默认 `18789`)默认绑定到 loopback。若要进行 LAN/tailnet -访问,请显式绑定并保持认证启用。 +Gateway 网关 WS 端口(默认 `18789`)默认绑定到 loopback。对于局域网/tailnet +访问,请显式绑定并保持身份验证启用。 对于仅 tailnet 的设置: - 在 `~/.openclaw/openclaw.json` 中设置 `gateway.bind: "tailnet"`。 - 重启 Gateway 网关(或重启 macOS 菜单栏应用)。 -## 谁会发布广告 +## 广播内容 -只有 Gateway 网关会发布 `_openclaw-gw._tcp`。 +只有 Gateway 网关会广播 `_openclaw-gw._tcp`。局域网多播广播由 +内置的 `bonjour` 插件提供;广域 DNS-SD 发布仍由 +Gateway 网关负责。 ## 服务类型 - `_openclaw-gw._tcp` — Gateway 网关传输信标(由 macOS/iOS/Android 节点使用)。 -## TXT 键(非秘密提示) +## TXT 键(非敏感提示) -Gateway 网关会发布一些小型非秘密提示,以便简化 UI 流程: +Gateway 网关会广播少量非敏感提示,以便让 UI 流程更方便: - `role=gateway` - `displayName=` - `lanHost=.local` - `gatewayPort=`(Gateway 网关 WS + HTTP) -- `gatewayTls=1`(仅当启用 TLS 时) -- `gatewayTlsSha256=`(仅当启用 TLS 且指纹可用时) -- `canvasPort=`(仅当启用 canvas host 时;当前与 `gatewayPort` 相同) +- `gatewayTls=1`(仅在启用 TLS 时) +- `gatewayTlsSha256=`(仅在启用 TLS 且指纹可用时) +- `canvasPort=`(仅在启用 canvas host 时;当前与 `gatewayPort` 相同) - `transport=gateway` -- `tailnetDns=`(当 Tailnet 可用时的可选提示) -- `sshPort=`(仅 mDNS 完整模式;广域 DNS-SD 可能省略它) -- `cliPath=`(仅 mDNS 完整模式;广域 DNS-SD 仍会将其写入为远程安装提示) +- `tailnetDns=`(仅限 mDNS 完整模式;当 Tailnet 可用时的可选提示) +- `sshPort=`(仅限 mDNS 完整模式;广域 DNS-SD 可能省略它) +- `cliPath=`(仅限 mDNS 完整模式;广域 DNS-SD 仍会将其写入,作为远程安装提示) 安全说明: -- Bonjour/mDNS TXT 记录是**未经认证的**。客户端不得将 TXT 视为权威路由依据。 -- 客户端应使用已解析的服务端点(SRV + A/AAAA)进行路由。`lanHost`、`tailnetDns`、`gatewayPort` 和 `gatewayTlsSha256` 仅应视为提示。 -- SSH 自动定位目标同样应使用已解析的服务主机,而不是仅依赖 TXT 提示。 -- TLS pinning 绝不能允许已发布的 `gatewayTlsSha256` 覆盖先前存储的 pin。 -- iOS/Android 节点应将基于发现的直接连接视为**仅 TLS**,并在信任首次出现的指纹前要求用户进行明确确认。 +- Bonjour/mDNS TXT 记录是**未经身份验证的**。客户端不得将 TXT 视为权威路由信息。 +- 客户端应使用解析后的服务端点(SRV + A/AAAA)进行路由。仅将 `lanHost`、`tailnetDns`、`gatewayPort` 和 `gatewayTlsSha256` 视为提示。 +- SSH 自动定向同样应使用解析后的服务主机,而不是仅依赖 TXT 提示。 +- TLS pinning 绝不能允许已广播的 `gatewayTlsSha256` 覆盖先前存储的 pin。 +- iOS/Android 节点应将基于发现的直连视为**仅限 TLS**,并在信任首次出现的指纹前要求用户明确确认。 ## 在 macOS 上调试 @@ -126,19 +129,19 @@ Gateway 网关会发布一些小型非秘密提示,以便简化 UI 流程: dns-sd -B _openclaw-gw._tcp local. ``` -- 解析某个实例(替换 ``): +- 解析单个实例(将 `` 替换为实际值): ```bash dns-sd -L "" _openclaw-gw._tcp local. ``` -如果浏览正常但解析失败,通常说明你遇到了局域网策略或 +如果浏览正常但解析失败,通常意味着你遇到了局域网策略或 mDNS 解析器问题。 ## 在 Gateway 网关日志中调试 Gateway 网关会写入滚动日志文件(启动时会打印为 -`gateway log file: ...`)。查找 `bonjour:` 行,尤其是: +`gateway log file: ...`)。请查找 `bonjour:` 日志行,尤其是: - `bonjour: advertise failed ...` - `bonjour: ... name conflict resolved` / `hostname conflict resolved` @@ -150,37 +153,39 @@ iOS 节点使用 `NWBrowser` 发现 `_openclaw-gw._tcp`。 要捕获日志: -- Settings → Gateway → Advanced → **Discovery Debug Logs** -- Settings → Gateway → Advanced → **Discovery Logs** → 复现问题 → **Copy** +- 设置 → Gateway 网关 → 高级 → **发现调试日志** +- 设置 → Gateway 网关 → 高级 → **发现日志** → 复现问题 → **复制** 日志包含浏览器状态转换和结果集变化。 ## 常见故障模式 -- **Bonjour 无法跨网络**:请使用 Tailnet 或 SSH。 +- **Bonjour 无法跨网络工作**:请使用 Tailnet 或 SSH。 - **多播被阻止**:某些 Wi‑Fi 网络会禁用 mDNS。 -- **休眠 / 接口波动**:macOS 可能会暂时丢失 mDNS 结果;请重试。 -- **浏览正常但解析失败**:请保持机器名简单(避免使用 emoji 或 - 标点),然后重启 Gateway 网关。服务实例名来源于 +- **睡眠 / 接口频繁变化**:macOS 可能会暂时丢失 mDNS 结果;请重试。 +- **浏览正常但解析失败**:请保持机器名简单(避免使用表情符号或 + 标点符号),然后重启 Gateway 网关。服务实例名称派生自 主机名,因此过于复杂的名称可能会让某些解析器混淆。 -## 转义实例名(`\032`) +## 转义的实例名称(`\032`) -Bonjour/DNS-SD 常会将服务实例名中的字节转义为十进制 `\DDD` -序列(例如空格会变成 `\032`)。 +Bonjour/DNS‑SD 通常会将服务实例名称中的字节转义为十进制 `\DDD` +序列(例如,空格会变成 `\032`)。 - 这在协议层面是正常现象。 -- UI 应解码后再显示(iOS 使用 `BonjourEscapes.decode`)。 +- UI 应为显示进行解码(iOS 使用 `BonjourEscapes.decode`)。 ## 禁用 / 配置 -- `OPENCLAW_DISABLE_BONJOUR=1` 会禁用广告发布(旧版:`OPENCLAW_DISABLE_BONJOUR`)。 -- `~/.openclaw/openclaw.json` 中的 `gateway.bind` 控制 Gateway 网关绑定模式。 -- `OPENCLAW_SSH_PORT` 会在发布 `sshPort` 时覆盖 SSH 端口(旧版:`OPENCLAW_SSH_PORT`)。 -- `OPENCLAW_TAILNET_DNS` 会在 TXT 中发布 MagicDNS 提示(旧版:`OPENCLAW_TAILNET_DNS`)。 -- `OPENCLAW_CLI_PATH` 会覆盖已发布的 CLI 路径(旧版:`OPENCLAW_CLI_PATH`)。 +- `openclaw plugins disable bonjour` 会通过禁用内置插件来禁用局域网多播广播。 +- `openclaw plugins enable bonjour` 会恢复默认的局域网发现插件。 +- `OPENCLAW_DISABLE_BONJOUR=1` 会在不更改插件配置的情况下禁用局域网多播广播;接受的真值包括 `1`、`true`、`yes` 和 `on`(旧版:`OPENCLAW_DISABLE_BONJOUR`)。 +- `gateway.bind`(位于 `~/.openclaw/openclaw.json`)控制 Gateway 网关绑定模式。 +- `OPENCLAW_SSH_PORT` 会在广播 `sshPort` 时覆盖 SSH 端口(旧版:`OPENCLAW_SSH_PORT`)。 +- `OPENCLAW_TAILNET_DNS` 会在启用 mDNS 完整模式时在 TXT 中发布 MagicDNS 提示(旧版:`OPENCLAW_TAILNET_DNS`)。 +- `OPENCLAW_CLI_PATH` 会覆盖已广播的 CLI 路径(旧版:`OPENCLAW_CLI_PATH`)。 ## 相关文档 -- 发现策略与传输选择:[设备发现](/zh-CN/gateway/discovery) -- 节点配对 + 批准:[Gateway 网关配对](/zh-CN/gateway/pairing) +- 设备发现策略和传输选择:[Discovery](/zh-CN/gateway/discovery) +- 节点配对 + 批准:[Gateway pairing](/zh-CN/gateway/pairing) diff --git a/docs/zh-CN/plugins/architecture-internals.md b/docs/zh-CN/plugins/architecture-internals.md index a40c9e642..6ce042b6c 100644 --- a/docs/zh-CN/plugins/architecture-internals.md +++ b/docs/zh-CN/plugins/architecture-internals.md @@ -1,85 +1,89 @@ --- read_when: - - 实现提供商运行时钩子、渠道生命周期或包打包功能 + - 实现提供商运行时钩子、渠道生命周期或软件包打包包 - 调试插件加载顺序或注册表状态 - 添加新的插件能力或上下文引擎插件 summary: 插件架构内部机制:加载流水线、注册表、运行时钩子、HTTP 路由和参考表格 title: 插件架构内部机制 x-i18n: - generated_at: "2026-04-24T05:09:37Z" + generated_at: "2026-04-24T06:33:28Z" model: gpt-5.4 provider: openai - source_hash: 01e258ab1666f7aff112fa3f897a40bf28dccaa8d06265fcf21e53479ee1ebda + source_hash: f6a99b7be56b7042a0e58a8119066ccfcb898279e6d6668f2aaa7351b188b88e source_path: plugins/architecture-internals.md workflow: 15 --- -关于公开能力模型、插件形态以及所有权/执行契约,请参见 [插件架构](/zh-CN/plugins/architecture)。本页是内部机制的参考:加载流水线、注册表、运行时钩子、Gateway 网关 HTTP 路由、导入路径和架构表格。 +关于公开能力模型、插件形状以及所有权/执行契约,请参阅 [插件架构](/zh-CN/plugins/architecture)。本页是内部机制的参考:加载流水线、注册表、运行时钩子、Gateway 网关 HTTP 路由、导入路径和模式表。 ## 加载流水线 在启动时,OpenClaw 大致会执行以下步骤: 1. 发现候选插件根目录 -2. 读取原生或兼容打包产物的清单和包元数据 +2. 读取原生或兼容包的清单和软件包元数据 3. 拒绝不安全的候选项 -4. 规范化插件配置(`plugins.enabled`、`allow`、`deny`、`entries`、`slots`、`load.paths`) +4. 规范化插件配置(`plugins.enabled`、`allow`、`deny`、`entries`、 + `slots`、`load.paths`) 5. 决定每个候选项是否启用 6. 加载已启用的原生模块:已构建的内置模块使用原生加载器;未构建的原生插件使用 `jiti` -7. 调用原生 `register(api)` 钩子,并将注册结果收集到插件注册表中 +7. 调用原生 `register(api)` 钩子,并将注册内容收集到插件注册表中 8. 将注册表暴露给命令/运行时表面 -`activate` 是 `register` 的旧别名——加载器会解析存在的那个(`def.register ?? def.activate`),并在相同时间点调用它。所有内置插件都使用 `register`;新插件请优先使用 `register`。 +`activate` 是 `register` 的旧别名——加载器会解析存在的那个(`def.register ?? def.activate`),并在同一时机调用。所有内置插件都使用 `register`;新插件请优先使用 `register`。 -安全检查会在运行时执行**之前**发生。当入口逃逸出插件根目录、路径对所有人可写,或对于非内置插件而言路径所有权看起来可疑时,候选项会被阻止。 +安全门禁会在运行时执行**之前**发生。当入口逃逸出插件根目录、路径对所有人可写,或对于非内置插件而言路径所有权看起来可疑时,候选项会被阻止。 ### 清单优先行为 清单是控制平面的事实来源。OpenClaw 使用它来: - 标识插件 -- 发现声明的渠道/Skills/配置架构或打包能力 +- 发现声明的渠道/Skills/配置模式或包能力 - 验证 `plugins.entries..config` -- 增强控制 UI 标签/占位符 +- 增强 Control UI 标签/占位符 - 显示安装/目录元数据 -- 在不加载插件运行时的情况下保留轻量的激活和设置描述符 +- 在不加载插件运行时的情况下保留轻量级激活和设置描述符 对于原生插件,运行时模块是数据平面部分。它会注册实际行为,例如钩子、工具、命令或提供商流程。 -可选的清单 `activation` 和 `setup` 块仍然留在控制平面。它们是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`。首批实时激活使用方现在会使用清单中的命令、渠道和提供商提示,在更广泛的注册表具体化之前缩小插件加载范围: +可选的清单 `activation` 和 `setup` 块仍然保留在控制平面。它们只是用于激活规划和设置发现的元数据描述符;不会替代运行时注册、`register(...)` 或 `setupEntry`。 +首批实时激活使用方现在会使用清单中的命令、渠道和提供商提示,在更广泛的注册表物化之前缩小插件加载范围: - CLI 加载会缩小到拥有所请求主命令的插件 - 渠道设置/插件解析会缩小到拥有所请求渠道 id 的插件 - 显式提供商设置/运行时解析会缩小到拥有所请求提供商 id 的插件 -激活规划器同时暴露面向现有调用方的仅 id API,以及面向新诊断的规划 API。规划条目会报告某个插件为何被选中,并将显式 `activation.*` 规划器提示与清单所有权回退原因区分开来,例如 `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子。这种原因拆分就是兼容性边界:现有插件元数据仍然可以正常工作,而新代码可以检测宽泛提示或回退行为,而无需改变运行时加载语义。 +激活规划器既为现有调用方提供仅含 id 的 API,也为新的诊断提供 plan API。Plan 条目会报告插件被选中的原因,将显式 `activation.*` 规划器提示与清单所有权回退分开,例如 `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子。这种原因拆分是兼容性边界:现有插件元数据仍可正常工作,而新代码可以检测宽泛提示或回退行为,而无需改变运行时加载语义。 -设置发现现在会优先使用描述符拥有的 id,例如 `setup.providers` 和 `setup.cliBackends`,在回退到 `setup-api` 之前先缩小候选插件范围;`setup-api` 用于那些仍然需要设置阶段运行时钩子的插件。如果发现的多个插件声明了同一个规范化设置提供商或 CLI 后端 id,设置查找会拒绝这个存在歧义的所有者,而不是依赖发现顺序。 +设置发现现在会优先使用由描述符拥有的 id,例如 `setup.providers` 和 `setup.cliBackends`,以便在回退到 `setup-api` 之前先缩小候选插件范围;`setup-api` 仅用于那些仍然需要设置时运行时钩子的插件。如果发现有多个插件声明了相同的规范化设置提供商或 CLI 后端 id,设置查找会拒绝这个模糊的所有者,而不是依赖发现顺序。 ### 加载器会缓存什么 -OpenClaw 会在进程内维护一些短期缓存,用于: +OpenClaw 会为以下内容保留短生命周期的进程内缓存: - 发现结果 - 清单注册表数据 - 已加载的插件注册表 -这些缓存可以减少突发启动和重复命令的开销。你可以安全地将它们视为短生命周期的性能缓存,而不是持久化机制。 +这些缓存可减少突发式启动成本和重复命令开销。可以将它们安全地视为短生命周期的性能缓存,而不是持久化。 性能说明: -- 设置 `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` 调整缓存窗口。 ## 注册表模型 -已加载的插件不会直接修改任意核心全局状态。它们会注册到一个中央插件注册表中。 +已加载的插件不会直接随意修改核心全局状态。它们会注册到一个中央插件注册表中。 注册表会跟踪: -- 插件记录(身份、来源、起源、状态、诊断) +- 插件记录(标识、来源、起源、状态、诊断) - 工具 - 旧版钩子和类型化钩子 - 渠道 @@ -90,18 +94,18 @@ OpenClaw 会在进程内维护一些短期缓存,用于: - 后台服务 - 插件拥有的命令 -然后,核心功能会从这个注册表中读取,而不是直接与插件模块交互。这使得加载保持单向: +然后,核心功能会从这个注册表中读取,而不是直接与插件模块交互。这样可使加载保持单向: - 插件模块 -> 注册表注册 - 核心运行时 -> 注册表消费 -这种分离对于可维护性很重要。这意味着大多数核心表面只需要一个集成点:“读取注册表”,而不是“为每个插件模块做特殊处理”。 +这种分离对于可维护性很重要。它意味着大多数核心表面只需要一个集成点:“读取注册表”,而不是“对每个插件模块做特殊处理”。 ## 会话绑定回调 -绑定会话的插件可以在批准结果确定后作出响应。 +绑定会话的插件可以在审批被解决时作出反应。 -使用 `api.onConversationBindingResolved(...)` 在绑定请求被批准或拒绝后接收回调: +使用 `api.onConversationBindingResolved(...)`,在绑定请求被批准或拒绝后接收回调: ```ts export default { @@ -109,12 +113,12 @@ export default { register(api) { api.onConversationBindingResolved(async (event) => { if (event.status === "approved") { - // A binding now exists for this plugin + conversation. + // 现在已为该插件 + 会话创建绑定。 console.log(event.binding?.conversationId); return; } - // The request was denied; clear any local pending state. + // 请求被拒绝;清理任何本地待处理状态。 console.log(event.request.conversation.conversationId); }); }, @@ -125,82 +129,86 @@ export default { - `status`:`"approved"` 或 `"denied"` - `decision`:`"allow-once"`、`"allow-always"` 或 `"deny"` -- `binding`:用于已批准请求的已解析绑定 +- `binding`:已批准请求的已解析绑定 - `request`:原始请求摘要、分离提示、发送者 id 和会话元数据 -这个回调仅用于通知。它不会改变谁被允许绑定会话,并且它会在核心批准处理完成后运行。 +此回调仅用于通知。它不会改变谁被允许绑定会话,并且会在核心审批处理完成后运行。 ## 提供商运行时钩子 提供商插件有三层: -- 用于低成本运行时前查找的**清单元数据**:`providerAuthEnvVars`、`providerAuthAliases`、`providerAuthChoices` 和 `channelEnvVars`。 -- **配置时钩子**:`catalog`(旧版 `discovery`)以及 `applyConfigDefaults`。 -- **运行时钩子**:40 多个可选钩子,涵盖凭证、模型解析、流包装、思考级别、重放策略和用量端点。完整列表见下方的[钩子顺序和用法](#hook-order-and-usage)。 +- **清单元数据**,用于廉价的运行时前查找:`providerAuthEnvVars`、 + `providerAuthAliases`、`providerAuthChoices` 和 `channelEnvVars`。 +- **配置时钩子**:`catalog`(旧版 `discovery`)以及 + `applyConfigDefaults`。 +- **运行时钩子**:40 多个可选钩子,覆盖认证、模型解析、 + 流包装、思考级别、重放策略和用量端点。完整列表见 + [钩子顺序和用法](#hook-order-and-usage)。 -OpenClaw 仍然负责通用智能体循环、故障转移、转录处理和工具策略。这些钩子是提供商特定行为的扩展表面,无需实现完整的自定义推理传输。 +OpenClaw 仍然负责通用智能体循环、故障转移、转录处理和工具策略。这些钩子是提供商特定行为的扩展表面,无需实现整套自定义推理传输。 -当提供商具有基于环境变量的凭证,并且通用凭证/状态/模型选择器路径需要在不加载插件运行时的情况下看到这些凭证时,请使用清单中的 `providerAuthEnvVars`。当某个提供商 id 需要复用另一个提供商 id 的环境变量、凭证配置文件、基于配置的凭证和 API 密钥新手引导选择时,请使用清单中的 `providerAuthAliases`。当新手引导/凭证选择 CLI 表面需要在不加载提供商运行时的情况下知道该提供商的选择 id、分组标签和简单单标志凭证接线时,请使用清单中的 `providerAuthChoices`。把提供商运行时的 `envVars` 保留给面向运维人员的提示,例如新手引导标签或 OAuth `client-id`/`client-secret` 设置变量。 +当提供商具有基于环境变量的凭证,并且希望通用认证/状态/模型选择路径在不加载插件运行时的情况下也能识别时,请使用清单 `providerAuthEnvVars`。当一个提供商 id 应复用另一个提供商 id 的环境变量、认证配置文件、基于配置的认证以及 API 密钥新手引导选择时,请使用清单 `providerAuthAliases`。当新手引导/认证选择 CLI 表面需要在不加载提供商运行时的情况下知道该提供商的选择 id、分组标签和简单单标志认证接线时,请使用清单 `providerAuthChoices`。请将提供商运行时 `envVars` 保留用于面向操作员的提示,例如新手引导标签或 OAuth client-id/client-secret 设置变量。 -当某个渠道具有由环境变量驱动的凭证或设置,并且通用 shell 环境变量回退、配置/状态检查或设置提示需要在不加载渠道运行时的情况下看到这些内容时,请使用清单中的 `channelEnvVars`。 +当某个渠道具有由环境变量驱动的认证或设置,并且希望通用 shell 环境变量回退、配置/状态检查或设置提示在不加载渠道运行时的情况下也能识别时,请使用清单 `channelEnvVars`。 ### 钩子顺序和用法 -对于模型/提供商插件,OpenClaw 大致会按以下顺序调用这些钩子。 -“何时使用”这一列是快速决策指南。 +对于模型/提供商插件,OpenClaw 会大致按以下顺序调用钩子。 +“何时使用”列是快速决策指南。 -| # | 钩子 | 作用 | 何时使用 | -| --- | --------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | `catalog` | 在生成 `models.json` 期间,将提供商配置发布到 `models.providers` 中 | 提供商拥有目录或基础 URL 默认值 | -| 2 | `applyConfigDefaults` | 在配置具体化期间应用由提供商拥有的全局配置默认值 | 默认值依赖于凭证模式、环境变量或提供商模型族语义 | -| -- | _(内置模型查找)_ | OpenClaw 会先尝试常规注册表/目录路径 | _(不是插件钩子)_ | -| 3 | `normalizeModelId` | 在查找之前规范化旧版或预览版 model-id 别名 | 提供商拥有在规范模型解析之前进行别名清理的逻辑 | -| 4 | `normalizeTransport` | 在通用模型组装之前规范化提供商族的 `api` / `baseUrl` | 提供商拥有同一传输族中自定义提供商 id 的传输清理逻辑 | -| 5 | `normalizeConfig` | 在运行时/提供商解析之前规范化 `models.providers.` | 提供商需要将配置清理逻辑保留在插件中;内置的 Google 系列辅助逻辑也会为受支持的 Google 配置条目提供兜底 | -| 6 | `applyNativeStreamingUsageCompat` | 对配置提供商应用原生流式用量兼容性改写 | 提供商需要基于端点驱动的原生流式用量元数据修复 | -| 7 | `resolveConfigApiKey` | 在加载运行时凭证之前,为配置提供商解析 env-marker 凭证 | 提供商拥有自己的 env-marker API 密钥解析逻辑;`amazon-bedrock` 在这里也有内置的 AWS env-marker 解析器 | -| 8 | `resolveSyntheticAuth` | 暴露 local/self-hosted 或基于配置的凭证,而不持久化明文 | 提供商可以使用 synthetic/local 凭证标记运行 | -| 9 | `resolveExternalAuthProfiles` | 叠加由提供商拥有的外部凭证配置文件;对于 CLI/应用拥有的凭证,默认 `persistence` 为 `runtime-only` | 提供商会复用外部凭证凭据,而不持久化复制的刷新令牌;请在清单中声明 `contracts.externalAuthProviders` | -| 10 | `shouldDeferSyntheticProfileAuth` | 将已存储的 synthetic 配置文件占位符降级到环境变量/基于配置的凭证之后 | 提供商会存储 synthetic 占位配置文件,而这些占位配置文件不应获得更高优先级 | -| 11 | `resolveDynamicModel` | 为本地注册表中尚不存在的提供商模型 id 提供同步回退 | 提供商接受任意上游模型 id | -| 12 | `prepareDynamicModel` | 先执行异步预热,然后再次运行 `resolveDynamicModel` | 提供商在解析未知 id 之前需要网络元数据 | -| 13 | `normalizeResolvedModel` | 在嵌入式运行器使用已解析模型之前执行最终改写 | 提供商需要进行传输改写,但仍使用核心传输 | -| 14 | `contributeResolvedModelCompat` | 为位于另一兼容传输之后的厂商模型提供兼容性标志 | 提供商可以在代理传输上识别自己的模型,而无需接管该提供商 | -| 15 | `capabilities` | 由共享核心逻辑使用的提供商自有转录/工具元数据 | 提供商需要处理转录/提供商族特有行为 | -| 16 | `normalizeToolSchemas` | 在嵌入式运行器看到工具架构之前规范化工具架构 | 提供商需要针对传输族清理架构 | -| 17 | `inspectToolSchemas` | 在规范化之后暴露由提供商拥有的架构诊断 | 提供商希望提供关键字警告,而无需让核心理解提供商特定规则 | -| 18 | `resolveReasoningOutputMode` | 选择原生或带标签的 reasoning-output 契约 | 提供商需要带标签的推理/最终输出,而不是原生字段 | -| 19 | `prepareExtraParams` | 在通用流选项包装器之前规范化请求参数 | 提供商需要默认请求参数或按提供商清理参数 | -| 20 | `createStreamFn` | 用自定义传输完全替换常规流路径 | 提供商需要自定义线协议,而不只是包装器 | -| 21 | `wrapStreamFn` | 在应用通用包装器之后再对流进行包装 | 提供商需要请求头/请求体/模型兼容性包装器,而不是自定义传输 | -| 22 | `resolveTransportTurnState` | 附加原生的逐轮传输请求头或元数据 | 提供商希望通用传输发送提供商原生的轮次标识 | -| 23 | `resolveWebSocketSessionPolicy` | 附加原生 WebSocket 请求头或会话冷却策略 | 提供商希望通用 WS 传输能够调整会话请求头或回退策略 | -| 24 | `formatApiKey` | 凭证配置文件格式化器:已存储配置文件会变为运行时 `apiKey` 字符串 | 提供商会存储额外凭证元数据,并需要自定义运行时令牌形态 | -| 25 | `refreshOAuth` | 为自定义刷新端点或刷新失败策略覆盖 OAuth 刷新逻辑 | 提供商不适配共享的 `pi-ai` 刷新器 | -| 26 | `buildAuthDoctorHint` | 当 OAuth 刷新失败时追加修复提示 | 提供商需要在刷新失败后提供由自己维护的凭证修复指导 | -| 27 | `matchesContextOverflowError` | 由提供商维护的上下文窗口溢出匹配器 | 提供商存在通用启发式无法捕获的原始溢出错误 | -| 28 | `classifyFailoverReason` | 由提供商维护的故障转移原因分类 | 提供商可以将原始 API/传输错误映射为速率限制、过载等 | -| 29 | `isCacheTtlEligible` | 面向代理/回传提供商的提示缓存策略 | 提供商需要面向代理的缓存 TTL 控制 | -| 30 | `buildMissingAuthMessage` | 替换通用的缺失凭证恢复消息 | 提供商需要提供商特定的缺失凭证恢复提示 | -| 31 | `suppressBuiltInModel` | 过时上游模型抑制,以及可选的面向用户错误提示 | 提供商需要隐藏过时的上游条目,或用厂商提示替换它们 | -| 32 | `augmentModelCatalog` | 在发现之后追加 synthetic/最终目录条目 | 提供商需要在 `models list` 和选择器中加入 synthetic 的前向兼容条目 | -| 33 | `resolveThinkingProfile` | 设置特定模型的 `/think` 级别、显示标签和默认值 | 提供商为选定模型暴露自定义思考梯度或二元标签 | -| 34 | `isBinaryThinking` | 开/关推理切换兼容性钩子 | 提供商只暴露二元的思考开/关 | -| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性钩子 | 提供商只希望在部分模型上启用 `xhigh` | -| 36 | `resolveDefaultThinkingLevel` | 默认 `/think` 级别兼容性钩子 | 提供商拥有某个模型族的默认 `/think` 策略 | -| 37 | `isModernModelRef` | 用于实时配置文件筛选和冒烟选择的现代模型匹配器 | 提供商拥有实时/冒烟首选模型匹配逻辑 | -| 38 | `prepareRuntimeAuth` | 在推理之前,将已配置凭证交换为实际运行时令牌/密钥 | 提供商需要令牌交换或短期请求凭证 | -| 39 | `resolveUsageAuth` | 为 `/usage` 及相关状态表面解析用量/计费凭证 | 提供商需要自定义用量/配额令牌解析,或使用不同的用量凭证 | -| 40 | `fetchUsageSnapshot` | 在凭证解析完成后,获取并规范化提供商特定的用量/配额快照 | 提供商需要提供商特定的用量端点或负载解析器 | -| 41 | `createEmbeddingProvider` | 为内存/搜索构建由提供商拥有的嵌入适配器 | Memory 嵌入行为应归属于提供商插件 | -| 42 | `buildReplayPolicy` | 返回一个重放策略,用于控制该提供商的转录处理 | 提供商需要自定义转录策略(例如剥离 thinking 块) | -| 43 | `sanitizeReplayHistory` | 在通用转录清理之后重写重放历史 | 提供商需要超出共享压缩辅助函数之外的提供商特定重放改写 | -| 44 | `validateReplayTurns` | 在嵌入式运行器之前,对重放轮次进行最终验证或重塑 | 在通用净化之后,提供商传输需要更严格的轮次验证 | -| 45 | `onModelSelected` | 在模型被选中后运行由提供商拥有的副作用 | 当模型变为活动状态时,提供商需要遥测或由提供商拥有的状态 | +| # | 钩子 | 作用 | 何时使用 | +| --- | --------------------------------- | ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | `catalog` | 在生成 `models.json` 期间,将提供商配置发布到 `models.providers` 中 | 提供商拥有目录或基础 `base URL` 默认值 | +| 2 | `applyConfigDefaults` | 在配置物化期间应用提供商拥有的全局配置默认值 | 默认值依赖于认证模式、环境变量或提供商模型家族语义 | +| -- | _(内置模型查找)_ | OpenClaw 会先尝试常规注册表/目录路径 | _(不是插件钩子)_ | +| 3 | `normalizeModelId` | 在查找前规范化旧版或预览版 model-id 别名 | 提供商负责在规范模型解析前清理别名 | +| 4 | `normalizeTransport` | 在通用模型组装前规范化提供商家族的 `api` / `baseUrl` | 提供商负责清理同一传输家族中自定义提供商 id 的传输配置 | +| 5 | `normalizeConfig` | 在运行时/提供商解析前规范化 `models.providers.` | 提供商需要让配置清理逻辑与插件共置;内置的 Google 家族辅助逻辑也会为受支持的 Google 配置条目提供兜底 | +| 6 | `applyNativeStreamingUsageCompat` | 将原生流式用量兼容性重写应用到配置提供商 | 提供商需要针对端点驱动的原生流式用量元数据修复 | +| 7 | `resolveConfigApiKey` | 在加载运行时认证之前,为配置提供商解析环境变量标记认证 | 提供商拥有自己的环境变量标记 API 密钥解析逻辑;`amazon-bedrock` 在这里也有内置的 AWS 环境变量标记解析器 | +| 8 | `resolveSyntheticAuth` | 在不持久化明文的情况下暴露本地/自托管或基于配置的认证 | 提供商可使用合成/本地凭证标记运行 | +| 9 | `resolveExternalAuthProfiles` | 叠加提供商拥有的外部认证配置文件;CLI/应用拥有的凭证默认 `persistence` 为 `runtime-only` | 提供商复用外部认证凭证,而不持久化复制的刷新令牌;请在清单中声明 `contracts.externalAuthProviders` | +| 10 | `shouldDeferSyntheticProfileAuth` | 将已存储的合成配置文件占位符排在环境变量/基于配置的认证之后 | 提供商会存储不应具有更高优先级的合成占位配置文件 | +| 11 | `resolveDynamicModel` | 为尚未出现在本地注册表中的提供商自有模型 id 提供同步回退 | 提供商接受任意上游模型 id | +| 12 | `prepareDynamicModel` | 异步预热,然后再次运行 `resolveDynamicModel` | 提供商在解析未知 id 之前需要网络元数据 | +| 13 | `normalizeResolvedModel` | 在嵌入式运行器使用已解析模型前进行最终重写 | 提供商需要传输重写,但仍使用核心传输 | +| 14 | `contributeResolvedModelCompat` | 为位于其他兼容传输之后的厂商模型提供兼容标记 | 提供商可在不接管提供商本身的情况下,于代理传输上识别自己的模型 | +| 15 | `capabilities` | 由共享核心逻辑使用的提供商自有转录/工具元数据 | 提供商需要处理转录/提供商家族特有行为 | +| 16 | `normalizeToolSchemas` | 在嵌入式运行器看到工具模式之前先规范化 | 提供商需要传输家族级的模式清理 | +| 17 | `inspectToolSchemas` | 在规范化后暴露提供商自有的模式诊断 | 提供商希望给出关键字警告,而不需要让核心学习提供商特定规则 | +| 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 刷新失败时附加修复提示 | 提供商在刷新失败后需要提供商自有的认证修复指导 | +| 27 | `matchesContextOverflowError` | 提供商自有的上下文窗口溢出匹配器 | 提供商存在通用启发式无法捕获的原始溢出错误 | +| 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` | 用于实时配置文件过滤和 smoke 选择的现代模型匹配器 | 提供商拥有实时/smoke 首选模型匹配逻辑 | +| 38 | `prepareRuntimeAuth` | 在推理前将已配置凭证交换为实际运行时令牌/密钥 | 提供商需要令牌交换或短期请求凭证 | +| 39 | `resolveUsageAuth` | 为 `/usage` 及相关状态表面解析用量/计费凭证 | 提供商需要自定义用量/配额令牌解析,或使用不同的用量凭证 | +| 40 | `fetchUsageSnapshot` | 在认证解析完成后获取并规范化提供商特定的用量/配额快照 | 提供商需要提供商特定的用量端点或负载解析器 | +| 41 | `createEmbeddingProvider` | 为 memory/搜索构建提供商自有的嵌入适配器 | Memory 嵌入行为应归属于提供商插件 | +| 42 | `buildReplayPolicy` | 返回一个重放策略,用于控制该提供商的转录处理 | 提供商需要自定义转录策略(例如剥离 thinking 块) | +| 43 | `sanitizeReplayHistory` | 在通用转录清理后重写重放历史 | 提供商需要在共享压缩辅助工具之外进行提供商特定的重放重写 | +| 44 | `validateReplayTurns` | 在嵌入式运行器之前对重放轮次进行最终验证或重塑 | 提供商传输在通用清理后需要更严格的轮次验证 | +| 45 | `onModelSelected` | 在模型被选中后运行提供商自有的副作用 | 当模型变为活动状态时,提供商需要遥测或提供商自有状态 | -`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配到的提供商插件,然后再依次回退到其他支持这些钩子的提供商插件,直到有插件实际更改了模型 id 或传输/配置。这样可以让别名/兼容性提供商垫片继续工作,而不要求调用方知道哪个内置插件拥有该改写逻辑。如果没有任何提供商钩子改写受支持的 Google 系列配置条目,内置的 Google 配置规范化器仍会应用该兼容性清理。 +`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配到的提供商插件,然后再继续尝试其他支持该钩子的提供商插件,直到某个插件实际更改了模型 id 或传输/配置为止。这样可以让别名/兼容性提供商垫片继续工作,而不要求调用方知道是哪个内置插件拥有该重写逻辑。如果没有任何提供商钩子重写受支持的 Google 家族配置条目,内置的 Google 配置规范化器仍会应用该兼容性清理。 -如果提供商需要完全自定义的线协议或自定义请求执行器,那就是另一类扩展了。这些钩子适用于仍运行在 OpenClaw 常规推理循环上的提供商行为。 +如果提供商需要完全自定义的线路协议或自定义请求执行器,那属于另一类扩展。这些钩子适用于仍在 OpenClaw 常规推理循环上运行的提供商行为。 ### 提供商示例 @@ -258,29 +266,40 @@ api.registerProvider({ ### 内置示例 -内置提供商插件会组合使用上述钩子,以适配各个厂商在目录、凭证、思考、重放和用量方面的需求。权威的钩子集合与各个 `extensions/` 下的插件放在一起;本页展示的是这些形态,而不是镜像列出完整清单。 +内置提供商插件会组合使用上述钩子,以适配各个厂商的目录、认证、思考、重放和用量需求。权威的钩子集合位于各插件在 `extensions/` 下的实现中;本页仅说明其形状,而不是镜像完整列表。 - - OpenRouter、Kilocode、Z.AI、xAI 注册 `catalog` 以及 `resolveDynamicModel` / `prepareDynamicModel`,这样它们就能在 OpenClaw 的静态目录之前暴露上游模型 id。 + + OpenRouter、Kilocode、Z.AI、xAI 会注册 `catalog` 以及 + `resolveDynamicModel` / `prepareDynamicModel`,这样它们就可以在 OpenClaw 的静态目录之前暴露上游模型 id。 - GitHub Copilot、Gemini CLI、ChatGPT Codex、MiniMax、Xiaomi、z.ai 将 `prepareRuntimeAuth` 或 `formatApiKey` 与 `resolveUsageAuth` + `fetchUsageSnapshot` 配合使用,以接管令牌交换和 `/usage` 集成。 + 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` 选择转录策略,而不必让每个插件都重新实现清理逻辑。 + + 共享的命名家族(`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`,并使用共享推理循环。 + `byteplus`、`cloudflare-ai-gateway`、`huggingface`、`kimi-coding`、`nvidia`、 + `qianfan`、`synthetic`、`together`、`venice`、`vercel-ai-gateway` 和 + `volcengine` 仅注册 `catalog`,并复用共享推理循环。 - - Beta 请求头、`/fast` / `serviceTier` 和 `context1m` 位于 Anthropic 插件公开的 `api.ts` / `contract-api.ts` 接口中(`wrapAnthropicProviderStream`、`resolveAnthropicBetas`、`resolveAnthropicFastMode`、`resolveAnthropicServiceTier`),而不是放在通用 SDK 中。 + + Beta 头、`/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({ @@ -301,11 +320,11 @@ const voices = await api.runtime.tts.listVoices({ 说明: -- `textToSpeech` 返回普通核心 TTS 输出负载,用于文件/语音消息表面。 -- 使用核心 `messages.tts` 配置和提供商选择逻辑。 -- 返回 PCM 音频缓冲区 + 采样率。插件必须为提供商自行重采样/编码。 -- `listVoices` 对每个提供商来说是可选的。将其用于厂商自有语音选择器或设置流程。 -- 语音列表可以包含更丰富的元数据,例如区域设置、性别和个性标签,供感知提供商的选择器使用。 +- `textToSpeech` 返回适用于文件/语音便笺表面的常规核心 TTS 输出负载。 +- 使用核心 `messages.tts` 配置和提供商选择。 +- 返回 PCM 音频缓冲区 + 采样率。插件必须为各提供商自行重采样/编码。 +- `listVoices` 对每个提供商而言是可选的。可用于厂商自有的语音选择器或设置流程。 +- 语音列表可以包含更丰富的元数据,例如区域设置、性别和个性标签,供提供商感知的选择器使用。 - 目前 OpenAI 和 ElevenLabs 支持电话语音。Microsoft 不支持。 插件也可以通过 `api.registerSpeechProvider(...)` 注册语音提供商。 @@ -329,11 +348,12 @@ api.registerSpeechProvider({ 说明: - 将 TTS 策略、回退和回复投递保留在核心中。 -- 使用语音提供商来承载厂商自有的合成行为。 +- 语音提供商用于厂商自有的合成行为。 - 旧版 Microsoft `edge` 输入会被规范化为 `microsoft` 提供商 id。 -- 推荐的所有权模型是面向公司的:随着 OpenClaw 增加这些能力契约,一个厂商插件可以拥有文本、语音、图像以及未来的媒体提供商。 +- 首选的所有权模型是面向公司的:随着 OpenClaw 增加这些能力契约,一个厂商插件可以统一拥有 + 文本、语音、图像以及未来的媒体提供商。 -对于图像/音频/视频理解,插件会注册一个类型化的媒体理解提供商,而不是使用通用的键值包: +对于图像/音频/视频理解,插件会注册一个类型化的媒体理解提供商,而不是通用的键值袋: ```ts api.registerMediaUnderstandingProvider({ @@ -349,13 +369,13 @@ api.registerMediaUnderstandingProvider({ - 将编排、回退、配置和渠道接线保留在核心中。 - 将厂商行为保留在提供商插件中。 -- 增量扩展应保持类型化:新的可选方法、新的可选结果字段、新的可选能力。 +- 增量扩展应保持类型化:新增可选方法、新增可选结果字段、新增可选能力。 - 视频生成已经遵循同样的模式: - - 核心拥有能力契约和运行时辅助函数 + - 核心拥有能力契约和运行时辅助工具 - 厂商插件注册 `api.registerVideoGenerationProvider(...)` - 功能/渠道插件消费 `api.runtime.videoGeneration.*` -对于媒体理解运行时辅助函数,插件可以调用: +对于媒体理解运行时辅助工具,插件可以调用: ```ts const image = await api.runtime.mediaUnderstanding.describeImageFile({ @@ -376,7 +396,7 @@ const video = await api.runtime.mediaUnderstanding.describeVideoFile({ const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ filePath: "/tmp/inbound-audio.ogg", cfg: api.config, - // Optional when MIME cannot be inferred reliably: + // 当无法可靠推断 MIME 时可选: mime: "audio/ogg", }); ``` @@ -385,7 +405,7 @@ const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ - `api.runtime.mediaUnderstanding.*` 是图像/音频/视频理解的首选共享表面。 - 使用核心媒体理解音频配置(`tools.media.audio`)和提供商回退顺序。 -- 当未产生转录输出时(例如输入被跳过/不受支持),返回 `{ text: undefined }`。 +- 当未产生转录输出时,返回 `{ text: undefined }`(例如输入被跳过/不受支持)。 - `api.runtime.stt.transcribeAudioFile(...)` 仍保留为兼容性别名。 插件还可以通过 `api.runtime.subagent` 启动后台子智能体运行: @@ -402,13 +422,13 @@ const result = await api.runtime.subagent.run({ 说明: -- `provider` 和 `model` 是单次运行的可选覆盖项,不是持久性会话变更。 -- OpenClaw 只会对受信任调用方尊重这些覆盖字段。 -- 对于插件拥有的回退运行,运维人员必须通过 `plugins.entries..subagent.allowModelOverride: true` 显式启用。 -- 使用 `plugins.entries..subagent.allowedModels` 将受信任插件限制到特定的规范 `provider/model` 目标,或设为 `"*"` 以显式允许任意目标。 -- 不受信任的插件子智能体运行仍然可用,但覆盖请求会被拒绝,而不是静默回退。 +- `provider` 和 `model` 是每次运行的可选覆盖项,不是持久性会话更改。 +- OpenClaw 仅对受信任调用方接受这些覆盖字段。 +- 对于插件拥有的回退运行,操作员必须通过 `plugins.entries..subagent.allowModelOverride: true` 显式启用。 +- 使用 `plugins.entries..subagent.allowedModels` 将受信任插件限制为特定的规范 `provider/model` 目标,或使用 `"*"` 显式允许任意目标。 +- 不受信任插件的子智能体运行仍可工作,但覆盖请求会被拒绝,而不是静默回退。 -对于 Web 搜索,插件可以消费共享运行时辅助函数,而不是深入智能体工具接线: +对于 Web 搜索,插件可以消费共享运行时辅助工具,而不是深入到智能体工具接线中: ```ts const providers = api.runtime.webSearch.listProviders({ @@ -424,13 +444,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` @@ -450,7 +471,7 @@ const providers = api.runtime.imageGeneration.listProviders({ ## Gateway 网关 HTTP 路由 -插件可以通过 `api.registerHttpRoute(...)` 暴露 HTTP 端点。 +插件可以使用 `api.registerHttpRoute(...)` 暴露 HTTP 端点。 ```ts api.registerHttpRoute({ @@ -468,137 +489,154 @@ 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` 级别的重叠路由会被拒绝。仅在相同凭证级别上保留 `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 凭证保护的插件路由天然就是隐式管理表面。如果你的路由需要仅管理员可用的行为,请要求使用携带身份的凭证模式,并记录显式的 `x-openclaw-scopes` 请求头契约。 +- 除非设置 `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 网关认证的插件路由就是隐式的管理员表面。如果你的路由需要仅管理员可用的行为,请要求使用带身份的认证模式,并记录显式的 `x-openclaw-scopes` 请求头契约。 ## 插件 SDK 导入路径 -在编写新插件时,请使用窄化的 SDK 子路径,而不是单体的 `openclaw/plugin-sdk` 根 barrel。核心子路径包括: +编写新插件时,请使用窄化的 SDK 子路径,而不是单体式的 `openclaw/plugin-sdk` 根 barrel。核心子路径包括: -| 子路径 | 用途 | +| 子路径 | 用途 | | ----------------------------------- | -------------------------------------------------- | -| `openclaw/plugin-sdk/plugin-entry` | 插件注册基础能力 | -| `openclaw/plugin-sdk/channel-core` | 渠道入口/构建辅助函数 | -| `openclaw/plugin-sdk/core` | 通用共享辅助函数和总括契约 | -| `openclaw/plugin-sdk/config-schema` | 根 `openclaw.json` Zod 架构(`OpenClawSchema`) | +| `openclaw/plugin-sdk/plugin-entry` | 插件注册原语 | +| `openclaw/plugin-sdk/channel-core` | 渠道入口/构建辅助工具 | +| `openclaw/plugin-sdk/core` | 通用共享辅助工具和总括契约 | +| `openclaw/plugin-sdk/config-schema` | 根 `openclaw.json` Zod 模式(`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` 已弃用——它是为旧插件保留的兼容性垫片。新代码应改为导入更窄化的通用基础能力。 +`openclaw/plugin-sdk/channel-runtime` 已弃用——它只是为旧插件提供的兼容性垫片。 +新代码应改为导入更窄的通用原语。 仓库内部入口点(每个内置插件包根目录): -- `index.js` — 内置插件入口 -- `api.js` — 辅助函数/类型 barrel -- `runtime-api.js` — 仅运行时 barrel -- `setup-entry.js` — 设置插件入口 +- `index.js` —— 内置插件入口 +- `api.js` —— 辅助工具/类型 barrel +- `runtime-api.js` —— 仅运行时 barrel +- `setup-entry.js` —— 设置插件入口 -外部插件应只导入 `openclaw/plugin-sdk/*` 子路径。绝不要从核心或另一个插件中导入其他插件包的 `src/*`。由 facade 加载的入口点在存在活动运行时配置快照时会优先使用它,否则回退到磁盘上的已解析配置文件。 +外部插件只能导入 `openclaw/plugin-sdk/*` 子路径。绝不要从核心或其他插件中导入另一个插件包的 `src/*`。 -像 `image-generation`、`media-understanding` 和 `speech` 这样的能力专用子路径之所以存在,是因为内置插件当前在使用它们。它们并不自动成为长期冻结的外部契约——在依赖它们时,请查阅相应的 SDK 参考页。 +由 facade 加载的入口点会优先使用当前活动的运行时配置快照;如果不存在,再回退到磁盘上已解析的配置文件。 -## 消息工具架构 +诸如 `image-generation`、`media-understanding` 和 `speech` 这类能力特定子路径之所以存在,是因为内置插件当前在使用它们。它们并不自动意味着长期冻结的外部契约——在依赖它们之前,请查阅相应的 SDK 参考页面。 -对于反应、已读和投票这类非消息原语,插件应拥有各自渠道专用的 `describeMessageTool(...)` 架构贡献。共享发送展示应使用通用 `MessagePresentation` 契约,而不是提供商原生的按钮、组件、块或卡片字段。有关契约、回退规则、提供商映射和插件作者检查清单,请参见 [Message Presentation](/zh-CN/plugins/message-presentation)。 +## 消息工具模式 -具备发送能力的插件通过消息能力声明它们可以渲染的内容: +对于反应、已读和投票等非消息原语,插件应自行拥有渠道特定的 `describeMessageTool(...)` 模式贡献。 +共享发送展示应使用通用 `MessagePresentation` 契约,而不是提供商原生的按钮、组件、块或卡片字段。 +有关契约、回退规则、提供商映射和插件作者检查清单,请参阅 [Message Presentation](/zh-CN/plugins/message-presentation)。 -- `presentation` 用于语义化展示块(`text`、`context`、`divider`、`buttons`、`select`) -- `delivery-pin` 用于固定投递请求 +支持发送的插件通过消息能力声明其可渲染内容: -核心负责决定是原生渲染该展示,还是将其降级为文本。不要从通用消息工具中暴露提供商原生 UI 的逃逸接口。面向旧版原生架构的已弃用 SDK 辅助函数仍然会为现有第三方插件导出,但新插件不应使用它们。 +- `presentation`:用于语义化展示块(`text`、`context`、`divider`、`buttons`、`select`) +- `delivery-pin`:用于固定投递请求 + +核心会决定是原生渲染该展示,还是将其降级为文本。不要从通用消息工具暴露提供商原生 UI 逃生口。 +为旧版原生模式保留的已弃用 SDK 辅助工具仍会继续导出,以兼容现有第三方插件,但新插件不应使用它们。 ## 渠道目标解析 -渠道插件应拥有渠道专用的目标语义。保持共享出站主机的通用性,并使用消息适配器表面来承载提供商规则: +渠道插件应自行拥有渠道特定的目标语义。保持共享出站主机通用,并使用消息适配器表面处理提供商规则: -- `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(...)` 在目标解析完成后负责构建提供商特定的会话路由。 推荐拆分方式: -- 对于应在搜索联系人/群组之前发生的分类决策,使用 `inferTargetChatType` -- 对于“将其视为显式/原生目标 id”的判断,使用 `looksLikeId` -- 将 `resolveTarget` 用于提供商专用的规范化回退,而不是广泛的目录搜索 -- 将 chat id、thread id、JID、handle 和 room id 这类提供商原生 id 保留在 `target` 值或提供商专用参数中,而不是放进通用 SDK 字段中 +- 对于应在搜索联系人/群组之前发生的类别判断,使用 `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` 中的共享辅助工具。 -当渠道需要基于配置的联系人/群组时,请使用这一方式,例如: +适用于渠道需要基于配置的联系人/群组时,例如: -- 基于 allowlist 的私信联系人 +- 由 allowlist 驱动的私信联系人 - 已配置的渠道/群组映射 -- 基于账号作用域的静态目录回退 +- 按账户范围的静态目录回退 -`directory-runtime` 中的共享辅助函数只处理通用操作: +`directory-runtime` 中的共享辅助工具仅处理通用操作: - 查询过滤 -- 限制应用 -- 去重/规范化辅助函数 +- limit 应用 +- 去重/规范化辅助工具 - 构建 `ChannelDirectoryEntry[]` -渠道专用的账号检查和 id 规范化应保留在插件实现中。 +渠道特定的账户检查和 id 规范化应保留在插件实现中。 ## 提供商目录 -提供商插件可以通过 `registerProvider({ catalog: { run(...) { ... } } })` 为推理定义模型目录。 +提供商插件可以通过 +`registerProvider({ catalog: { run(...) { ... } } })` 定义用于推理的模型目录。 -`catalog.run(...)` 返回与 OpenClaw 写入 `models.providers` 相同的结构: +`catalog.run(...)` 返回与 OpenClaw 写入 +`models.providers` 相同的形状: -- `{ provider }` 表示一个提供商条目 -- `{ providers }` 表示多个提供商条目 +- `{ provider }`:单个提供商条目 +- `{ providers }`:多个提供商条目 -当插件拥有提供商专用模型 id、基础 URL 默认值或受凭证控制的模型元数据时,请使用 `catalog`。 +当插件拥有提供商特定的模型 id、基础 `base URL` 默认值或受认证门控的模型元数据时,请使用 `catalog`。 `catalog.order` 控制插件目录相对于 OpenClaw 内置隐式提供商的合并时机: -- `simple`:普通 API 密钥或基于环境变量的提供商 -- `profile`:存在凭证配置文件时出现的提供商 -- `paired`:合成多个相关提供商条目的提供商 +- `simple`:普通 API 密钥或由环境变量驱动的提供商 +- `profile`:当存在认证配置文件时出现的提供商 +- `paired`:会合成多个相关提供商条目的提供商 - `late`:最后一轮,在其他隐式提供商之后 -在键冲突时,后面的提供商会获胜,因此插件可以有意用相同提供商 id 覆盖内置提供商条目。 +后面的提供商在键冲突时会胜出,因此插件可以有意用相同的提供商 id 覆盖内置提供商条目。 兼容性: -- `discovery` 仍然可作为旧别名使用 +- `discovery` 仍可作为旧别名使用 - 如果同时注册了 `catalog` 和 `discovery`,OpenClaw 会使用 `catalog` ## 只读渠道检查 -如果你的插件注册了一个渠道,除了 `resolveAccount(...)` 之外,优先同时实现 `plugin.config.inspectAccount(cfg, accountId)`。 +如果你的插件注册了一个渠道,建议在实现 `resolveAccount(...)` 的同时实现 +`plugin.config.inspectAccount(cfg, accountId)`。 原因: -- `resolveAccount(...)` 是运行时路径。它可以假定凭证已经完全具体化,并且在缺少必要密钥时快速失败。 -- 像 `openclaw status`、`openclaw status --all`、`openclaw channels status`、`openclaw channels resolve` 以及 doctor/配置修复流程这样的只读命令路径,不应仅为了描述配置就必须具体化运行时凭证。 +- `resolveAccount(...)` 是运行时路径。它可以假定凭证已经完全物化,并在缺少必需机密时快速失败。 +- `openclaw status`、`openclaw status --all`、 + `openclaw channels status`、`openclaw channels resolve` 以及 doctor/配置修复流程等只读命令路径,不应为了描述配置而必须物化运行时凭证。 推荐的 `inspectAccount(...)` 行为: -- 只返回描述性的账号状态。 +- 只返回描述性的账户状态。 - 保留 `enabled` 和 `configured`。 - 在相关时包含凭证来源/状态字段,例如: - `tokenSource`、`tokenStatus` @@ -606,11 +644,11 @@ api.registerHttpRoute({ - `appTokenSource`、`appTokenStatus` - `signingSecretSource`、`signingSecretStatus` - 你不需要为了报告只读可用性而返回原始令牌值。返回 `tokenStatus: "available"`(以及对应的来源字段)就足以支持状态类命令。 -- 当凭证通过 SecretRef 配置但在当前命令路径中不可用时,请使用 `configured_unavailable`。 +- 当凭证通过 SecretRef 配置,但在当前命令路径中不可用时,请使用 `configured_unavailable`。 -这样只读命令就可以报告“已配置但在当前命令路径中不可用”,而不是崩溃或错误地将账号报告为未配置。 +这样一来,只读命令就能报告“已配置,但在此命令路径中不可用”,而不是崩溃或错误地把该账户报告为未配置。 -## 包打包功能 +## 软件包打包包 插件目录可以包含一个带有 `openclaw.extensions` 的 `package.json`: @@ -624,37 +662,46 @@ api.registerHttpRoute({ } ``` -每个条目都会变成一个插件。如果该打包列出了多个扩展,插件 id 会变为 `name/`。 +每个条目都会成为一个插件。如果该打包包列出了多个扩展,插件 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` 可以指向一个轻量级、仅用于设置的模块。当 OpenClaw 需要为已禁用的渠道插件提供设置表面时,或者当渠道插件已启用但尚未配置时,它会加载 `setupEntry` 而不是完整插件入口。这样在你的主插件入口还会接入工具、钩子或其他仅运行时代码时,可以让启动和设置更轻量。 +可选:`openclaw.setupEntry` 可以指向一个轻量级、仅用于设置的模块。 +当 OpenClaw 需要为已禁用的渠道插件提供设置表面,或者某个渠道插件已启用但尚未配置时,它会加载 `setupEntry` 而不是完整插件入口。这样在主插件入口还会接入工具、钩子或其他仅运行时代码时,可以让启动和设置更轻量。 -可选:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` 可以让渠道插件在 Gateway 网关的监听前启动阶段,即使渠道已经配置好,也选择同样的 `setupEntry` 路径。 +可选:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` +可让渠道插件在 Gateway 网关的监听前启动阶段也走相同的 `setupEntry` 路径,即使该渠道已经配置完成。 -仅当 `setupEntry` 完全覆盖 Gateway 网关开始监听之前必须存在的启动表面时,才应使用它。实际中,这意味着设置入口必须注册启动所依赖的每一项由渠道拥有的能力,例如: +仅当 `setupEntry` 完整覆盖了 Gateway 网关开始监听前必须存在的启动表面时,才应使用此项。 +在实践中,这意味着设置入口必须注册启动依赖的每项渠道自有能力,例如: - 渠道注册本身 -- 任何必须在 Gateway 网关开始监听之前可用的 HTTP 路由 -- 在同一时间窗口内必须存在的任何 Gateway 网关方法、工具或服务 +- 任何必须在 Gateway 网关开始监听前可用的 HTTP 路由 +- 在同一窗口内必须存在的任何 Gateway 网关方法、工具或服务 -如果你的完整入口仍然拥有任何必需的启动能力,请不要启用此标志。保持插件的默认行为,让 OpenClaw 在启动期间加载完整入口。 +如果你的完整入口仍拥有任何必需的启动能力,请不要启用此标志。保持插件使用默认行为,并让 OpenClaw 在启动期间加载完整入口。 -内置渠道还可以发布仅设置阶段使用的契约表面辅助函数,供核心在完整渠道运行时加载之前查询。当前的设置提升表面包括: +内置渠道还可以发布仅用于设置的契约表面辅助工具,供核心在完整渠道运行时加载之前查询。当前的设置提升表面包括: - `singleAccountKeysToMove` - `namedAccountPromotionKeys` - `resolveSingleAccountPromotionTarget(...)` -当核心需要在不加载完整插件入口的情况下,将旧版单账号渠道配置提升到 `channels..accounts.*` 时,会使用这个表面。Matrix 是当前的内置示例:当命名账号已经存在时,它只会把凭证/引导键移动到一个已命名的提升账号中,并且它可以保留已配置的非规范默认账号键,而不是总是创建 `accounts.default`。 +当核心需要在不加载完整插件入口的情况下,将旧版单账户渠道配置提升到 `channels..accounts.*` 时,就会使用该表面。 +Matrix 是当前的内置示例:当已存在命名账户时,它只会把认证/引导键移动到某个命名提升账户中,并且它可以保留已配置的非规范默认账户键,而不是总是创建 `accounts.default`。 -这些设置补丁适配器会让内置契约表面发现保持惰性。导入时间保持轻量;提升表面只会在首次使用时加载,而不是在模块导入时重新进入内置渠道启动流程。 +这些设置补丁适配器会让内置契约表面发现保持惰性。导入时开销保持轻量;提升表面只会在首次使用时加载,而不是在模块导入时重新进入内置渠道启动流程。 -当这些启动表面包含 Gateway 网关 RPC 方法时,请将它们保留在插件专用前缀下。核心管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)仍然保留,并且始终解析为 `operator.admin`,即使插件请求了更窄的作用域。 +当这些启动表面包含 Gateway 网关 RPC 方法时,请将它们保留在插件特定前缀下。核心管理命名空间(`config.*`、 +`exec.approvals.*`、`wizard.*`、`update.*`)仍然保留,并始终解析为 `operator.admin`,即使某个插件请求了更窄的作用域也是如此。 示例: @@ -673,7 +720,7 @@ api.registerHttpRoute({ ### 渠道目录元数据 -渠道插件可以通过 `openclaw.channel` 宣告设置/发现元数据,并通过 `openclaw.install` 宣告安装提示。这样可以让核心目录保持无数据状态。 +渠道插件可以通过 `openclaw.channel` 宣传设置/发现元数据,并通过 `openclaw.install` 提供安装提示。这样可以让核心目录保持无数据化。 示例: @@ -685,10 +732,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"] }, @@ -701,34 +748,41 @@ api.registerHttpRoute({ } ``` -除了最小示例外,有用的 `openclaw.channel` 字段还包括: +除了最小示例外,其他有用的 `openclaw.channel` 字段包括: - `detailLabel`:用于更丰富目录/状态表面的次级标签 - `docsLabel`:覆盖文档链接的链接文本 -- `preferOver`:该目录条目应优先于的低优先级插件/渠道 id -- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面文案控制 +- `preferOver`:此目录条目应优先于的低优先级插件/渠道 id +- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面的文案控制项 - `markdownCapable`:将该渠道标记为支持 Markdown,以用于出站格式决策 -- `exposure.configured`:当设置为 `false` 时,在已配置渠道列表表面中隐藏该渠道 -- `exposure.setup`:当设置为 `false` 时,在交互式设置/配置选择器中隐藏该渠道 +- `exposure.configured`:设为 `false` 时,在已配置渠道列表表面中隐藏该渠道 +- `exposure.setup`:设为 `false` 时,在交互式设置/配置选择器中隐藏该渠道 - `exposure.docs`:将该渠道标记为内部/私有,以用于文档导航表面 - `showConfigured` / `showInSetup`:为兼容性仍接受的旧别名;优先使用 `exposure` - `quickstartAllowFrom`:让该渠道加入标准快速开始 `allowFrom` 流程 -- `forceAccountBinding`:即使只存在一个账号,也要求显式账号绑定 +- `forceAccountBinding`:即使只存在一个账户,也要求显式账户绑定 - `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"` 键的旧别名。 +或者将 `OPENCLAW_PLUGIN_CATALOG_PATHS`(或 `OPENCLAW_MPM_CATALOG_PATHS`)指向一个或多个 JSON 文件(以逗号/分号/`PATH` 分隔)。每个文件应包含 `{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }`。解析器也接受 `"packages"` 或 `"plugins"` 作为 `"entries"` 键的旧别名。 + +生成的渠道目录条目和提供商安装目录条目会在原始 `openclaw.install` 块旁边暴露规范化后的安装源事实。规范化事实会标识 npm spec 是精确版本还是浮动选择器、是否存在预期的完整性元数据,以及是否也提供本地源路径。使用方应将 `installSource` 视为附加的可选字段,这样较旧的手工构建条目和兼容性垫片就不必合成它。这让新手引导和诊断能够在不导入插件运行时的情况下解释源平面状态。 + +官方外部 npm 条目应优先使用精确的 `npmSpec` 加上 `expectedIntegrity`。裸包名和 dist-tag 为兼容性仍然可用,但它们会暴露源平面警告,以便目录能够逐步迁移到固定版本、带完整性校验的安装方式,而不会破坏现有插件。 ## 上下文引擎插件 -上下文引擎插件负责会话上下文编排,包括摄取、组装和压缩。通过 `api.registerContextEngine(id, factory)` 从你的插件中注册它们,然后使用 `plugins.slots.contextEngine` 选择活动引擎。 +上下文引擎插件负责会话上下文编排,包括摄取、组装和压缩。请在你的插件中使用 +`api.registerContextEngine(id, factory)` 注册它们,然后使用 +`plugins.slots.contextEngine` 选择活动引擎。 -当你的插件需要替换或扩展默认上下文流水线,而不只是添加内存搜索或钩子时,请使用这个方式。 +当你的插件需要替换或扩展默认上下文流水线,而不仅仅是添加 memory 搜索或钩子时,请使用此功能。 ```ts import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core"; @@ -793,37 +847,39 @@ export default function (api) { ## 添加新的能力 -当插件需要当前 API 无法适配的行为时,不要通过私有深入访问绕过插件系统。应添加缺失的能力。 +当插件需要当前 API 无法容纳的行为时,不要通过私有深入访问绕过插件系统。应添加缺失的能力。 推荐顺序: -1. 定义核心契约 - 确定哪些共享行为应由核心负责:策略、回退、配置合并、生命周期、面向渠道的语义以及运行时辅助函数形态。 -2. 添加类型化的插件注册/运行时表面 - 使用最小但有用的类型化能力表面扩展 `OpenClawPluginApi` 和/或 `api.runtime`。 -3. 连接核心 + 渠道/功能使用方 - 渠道和功能插件应通过核心消费新能力,而不是直接导入某个厂商实现。 -4. 注册厂商实现 - 然后由厂商插件针对该能力注册它们的后端。 -5. 添加契约覆盖 - 添加测试,以便随着时间推移,所有权和注册形态仍然保持明确。 +1. 定义核心契约 + 决定哪些共享行为应由核心拥有:策略、回退、配置合并、 + 生命周期、面向渠道的语义,以及运行时辅助工具形状。 +2. 添加类型化的插件注册/运行时表面 + 用最小但足够有用的类型化能力表面扩展 `OpenClawPluginApi` 和/或 `api.runtime`。 +3. 接入核心 + 渠道/功能使用方 + 渠道和功能插件应通过核心消费该新能力, + 而不是直接导入某个厂商实现。 +4. 注册厂商实现 + 然后由厂商插件针对该能力注册其后端实现。 +5. 添加契约覆盖 + 添加测试,使所有权和注册形状随着时间推移保持明确。 -这就是 OpenClaw 在保持鲜明立场的同时,不会被硬编码到某个提供商世界观中的方式。有关具体文件清单和完整示例,请参见[能力扩展手册](/zh-CN/plugins/architecture)。 +这就是 OpenClaw 保持有主张、同时又不被硬编码到某个提供商世界观中的方式。有关具体文件清单和完整示例,请参阅 [能力扩展手册](/zh-CN/plugins/architecture)。 ### 能力检查清单 -当你添加一个新能力时,通常实现应同时涉及这些表面: +当你添加新能力时,实现通常应一起覆盖以下表面: - `src//types.ts` 中的核心契约类型 -- `src//runtime.ts` 中的核心运行器/运行时辅助函数 +- `src//runtime.ts` 中的核心运行器/运行时辅助工具 - `src/plugins/types.ts` 中的插件 API 注册表面 - `src/plugins/registry.ts` 中的插件注册表接线 -- 当功能/渠道插件需要消费它时,位于 `src/plugins/runtime/*` 中的插件运行时暴露 -- `src/test-utils/plugin-registration.ts` 中的捕获/测试辅助函数 +- 当功能/渠道插件需要消费该能力时,位于 `src/plugins/runtime/*` 中的插件运行时暴露 +- `src/test-utils/plugin-registration.ts` 中的捕获/测试辅助工具 - `src/plugins/contracts/registry.ts` 中的所有权/契约断言 -- `docs/` 中的运维人员/插件文档 +- `docs/` 中面向操作员/插件的文档 -如果这些表面中缺少某一个,通常说明该能力尚未完全集成。 +如果其中某个表面缺失,通常说明该能力尚未真正完整集成。 ### 能力模板 @@ -846,7 +902,7 @@ api.registerVideoGenerationProvider({ }, }); -// shared runtime helper for feature/channel plugins +// feature/channel 插件共享运行时辅助工具 const clip = await api.runtime.videoGeneration.generate({ prompt: "Show the robot walking through the lab.", cfg, @@ -859,16 +915,16 @@ const clip = await api.runtime.videoGeneration.generate({ expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]); ``` -这样规则就很简单: +这样规则就保持简单: - 核心拥有能力契约 + 编排 - 厂商插件拥有厂商实现 -- 功能/渠道插件消费运行时辅助函数 -- 契约测试使所有权保持明确 +- 功能/渠道插件消费运行时辅助工具 +- 契约测试保持所有权明确 ## 相关内容 -- [插件架构](/zh-CN/plugins/architecture) — 公开能力模型和形态 -- [插件 SDK 子路径](/zh-CN/plugins/sdk-subpaths) +- [插件架构](/zh-CN/plugins/architecture) —— 公开能力模型和形状 +- [Plugin SDK 子路径](/zh-CN/plugins/sdk-subpaths) - [插件 SDK 设置](/zh-CN/plugins/sdk-setup) - [构建插件](/zh-CN/plugins/building-plugins) diff --git a/docs/zh-CN/plugins/architecture.md b/docs/zh-CN/plugins/architecture.md index 682909045..b9a1d351f 100644 --- a/docs/zh-CN/plugins/architecture.md +++ b/docs/zh-CN/plugins/architecture.md @@ -1,29 +1,29 @@ --- read_when: - 构建或调试原生 OpenClaw 插件 - - 理解插件能力模型或归属边界 - - 处理插件加载流水线或注册表 + - 理解插件能力模型或所有权边界 + - 处理插件加载流程或注册表 - 实现提供商运行时钩子或渠道插件 sidebarTitle: Internals -summary: 插件内部机制:能力模型、归属、契约、加载流水线和运行时辅助工具 +summary: 插件内部机制:能力模型、所有权、契约、加载流程和运行时辅助工具 title: 插件内部机制 x-i18n: - generated_at: "2026-04-24T05:09:38Z" + generated_at: "2026-04-24T06:33:30Z" model: gpt-5.4 provider: openai - source_hash: 344c02f9f0bb19780d262929e665fcaf8093ac08cda30b61af56857368b0b07a + source_hash: d05891966669e599b1aa0165f20f913bfa82c22436356177436fba5d1be31e7b source_path: plugins/architecture.md workflow: 15 --- -这是 OpenClaw 插件系统的**深度架构参考**。如需实用指南,请先从下面的专题页面之一开始。 +这是 OpenClaw 插件系统的**深度架构参考**。如需实用指南,请先从下面的聚焦页面之一开始。 - 面向终端用户的指南,介绍如何添加、启用和排查插件问题。 + 面向终端用户的指南,介绍如何添加、启用和故障排除插件。 - 以最小可用清单为起点的首个插件教程。 + 首个插件教程,包含最小可工作的清单。 构建一个消息渠道插件。 @@ -36,11 +36,11 @@ x-i18n: -## 公开能力模型 +## 公共能力模型 -能力是 OpenClaw 内部公开的**原生插件**模型。每个原生 OpenClaw 插件都会针对一种或多种能力类型进行注册: +能力是 OpenClaw 内部公开的**原生插件**模型。每个原生 OpenClaw 插件都会针对一个或多个能力类型进行注册: -| 能力 | 注册方法 | 示例插件 | +| 能力 | 注册方式 | 示例插件 | | ---------------------- | ------------------------------------------------ | ------------------------------------ | | 文本推理 | `api.registerProvider(...)` | `openai`, `anthropic` | | CLI 推理后端 | `api.registerCliBackend(...)` | `openai`, `anthropic` | @@ -53,44 +53,45 @@ x-i18n: | 视频生成 | `api.registerVideoGenerationProvider(...)` | `qwen` | | 网页抓取 | `api.registerWebFetchProvider(...)` | `firecrawl` | | 网页搜索 | `api.registerWebSearchProvider(...)` | `google` | -| 渠道 / 消息 | `api.registerChannel(...)` | `msteams`, `matrix` | +| 渠道 / 消息传递 | `api.registerChannel(...)` | `msteams`, `matrix` | +| Gateway 网关发现 | `api.registerGatewayDiscoveryService(...)` | `bonjour` | -注册零个能力,但提供 hooks、工具或服务的插件,属于**仅 legacy hook** 插件。这种模式目前仍被完全支持。 +如果某个插件注册了零个能力,但提供了钩子、工具、发现服务或后台服务,那么它就是一个**仅 legacy 钩子**插件。该模式目前仍然得到完整支持。 -### 对外兼容性立场 +### 外部兼容性立场 -能力模型已经在核心中落地,并已被当前的内置 / 原生插件使用,但外部插件兼容性仍需要比“已导出,因此已冻结”更严格的标准。 +能力模型已经在核心中落地,并被当前的内置 / 原生插件使用,但外部插件兼容性仍需要比“它已导出,因此它已冻结”更严格的标准。 -| 插件情况 | 指南 | +| 插件情况 | 指引 | | ------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -| 现有外部插件 | 保持基于 hook 的集成可用;这是兼容性的基线。 | -| 新的内置 / 原生插件 | 优先使用显式能力注册,而不是特定厂商的内部访问方式或新的仅 hook 设计。 | -| 采用能力注册的外部插件 | 允许,但除非文档将其标记为稳定,否则应将特定能力的辅助接口视为仍在演进中。 | +| 现有外部插件 | 保持基于钩子的集成继续工作;这是兼容性基线。 | +| 新的内置 / 原生插件 | 优先使用显式能力注册,而不是面向特定厂商的直连方式,或新的仅钩子设计。 | +| 采用能力注册的外部插件 | 允许,但除非文档明确标记为稳定,否则应将特定能力的辅助接口视为仍在演进中。 | -能力注册是预期的发展方向。在过渡期间,对于外部插件来说,legacy hooks 仍然是最安全、最不容易破坏兼容性的路径。导出的辅助子路径并不完全等价——优先使用范围明确、已有文档说明的契约,而不是偶然暴露出来的辅助导出。 +能力注册是预期的发展方向。在过渡期间,legacy 钩子仍然是对外部插件最安全、最不容易破坏的路径。导出的辅助子路径并不完全等价——相比偶然暴露的辅助导出,应优先使用范围更窄、文档化的契约。 ### 插件形态 -OpenClaw 会根据每个已加载插件的实际注册行为来分类其形态(而不只是依据静态元数据): +OpenClaw 会根据每个已加载插件的实际注册行为(而不仅仅是静态元数据)将其归类为某种形态: -- **plain-capability**:只注册恰好一种能力类型(例如像 `mistral` 这样的仅提供商插件)。 -- **hybrid-capability**:注册多种能力类型(例如 `openai` 同时拥有文本推理、语音、媒体理解和图像生成)。 -- **hook-only**:只注册 hooks(类型化或自定义),不注册能力、工具、命令或服务。 -- **non-capability**:注册工具、命令、服务或路由,但不注册能力。 +- **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 +### Legacy 钩子 -`before_agent_start` hook 仍然作为仅 hook 插件的兼容路径受到支持。现实中的 legacy 插件仍然依赖它。 +`before_agent_start` 钩子仍然作为仅钩子插件的兼容路径而受到支持。现实中的 legacy 插件仍然依赖它。 方向如下: - 保持其可用 -- 在文档中标记为 legacy -- 对于模型 / 提供商覆写工作,优先使用 `before_model_resolve` -- 对于提示词修改工作,优先使用 `before_prompt_build` -- 仅在真实使用量下降且 fixture 覆盖证明迁移安全后再移除 +- 在文档中将其标记为 legacy +- 对于模型 / 提供商覆盖工作,优先使用 `before_model_resolve` +- 对于提示词变更工作,优先使用 `before_prompt_build` +- 只有在真实使用量下降,并且夹具覆盖证明迁移安全后,才移除它 ### 兼容性信号 @@ -98,70 +99,70 @@ OpenClaw 会根据每个已加载插件的实际注册行为来分类其形态 | 信号 | 含义 | | -------------------------- | ------------------------------------------------------------ | -| **config valid** | 配置解析正常,且插件可成功解析 | +| **config valid** | 配置解析正常,插件可解析 | | **compatibility advisory** | 插件使用了受支持但较旧的模式(例如 `hook-only`) | -| **legacy warning** | 插件使用了 `before_agent_start`,该接口已弃用 | -| **hard error** | 配置无效,或插件加载失败 | +| **legacy warning** | 插件使用了已弃用的 `before_agent_start` | +| **hard error** | 配置无效或插件加载失败 | -`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. **清单 + 设备发现** OpenClaw 会从已配置路径、工作区根目录、全局插件根目录以及内置插件中查找候选插件。设备发现会优先读取原生 `openclaw.plugin.json` 清单以及受支持的 bundle 清单。 2. **启用 + 验证** - 核心决定某个已发现插件是启用、禁用、阻止,还是被选入诸如 memory 之类的独占槽位。 + 核心会决定某个已发现插件是启用、禁用、阻止,还是被选中用于某个独占槽位(例如 memory)。 3. **运行时加载** - 原生 OpenClaw 插件通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容的 bundle 会在不导入运行时代码的情况下被规范化为注册表记录。 -4. **表面消费** - OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、hooks、HTTP 路由、CLI 命令和服务。 + 原生 OpenClaw 插件会通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容的 bundle 会被规范化为注册表记录,而无需导入运行时代码。 +4. **接口消费** + OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、钩子、HTTP 路由、CLI 命令和服务。 -对于插件 CLI 而言,根命令的设备发现专门拆分为两个阶段: +对于插件 CLI,根命令发现会拆分为两个阶段: -- 解析阶段元数据来自 `registerCli(..., { descriptors: [...] })` -- 实际的插件 CLI 模块可以保持惰性加载,并在首次调用时再注册 +- 解析时元数据来自 `registerCli(..., { descriptors: [...] })` +- 真正的插件 CLI 模块可以保持惰性,并在首次调用时注册 -这样可以让插件自有的 CLI 代码保持在插件内部,同时仍允许 OpenClaw 在解析之前预留根命令名称。 +这样既能让插件拥有的 CLI 代码保留在插件内部,又能让 OpenClaw 在解析前预留根命令名称。 重要的设计边界是: -- 设备发现 + 配置验证应当基于**清单 / schema 元数据**工作,而不执行插件代码 +- 设备发现 + 配置验证应当依赖**清单 / schema 元数据**完成,而无需执行插件代码 - 原生运行时行为来自插件模块的 `register(api)` 路径 -这种拆分让 OpenClaw 能在完整运行时尚未激活之前,就验证配置、解释缺失 / 已禁用的插件,并构建 UI / schema 提示信息。 +这种拆分使 OpenClaw 能够在完整运行时尚未激活前,就验证配置、解释缺失 / 已禁用插件,并构建 UI / schema 提示。 ### 激活规划 -激活规划是控制平面的一部分。调用方可以在加载更广泛的运行时注册表之前,先询问哪些插件与某个具体命令、提供商、渠道、路由、智能体 harness 或能力相关。 +激活规划属于控制平面的一部分。调用方可以在加载更广泛的运行时注册表之前,先询问哪些插件与某个具体命令、提供商、渠道、路由、智能体 harness 或能力相关。 -规划器保持与当前清单行为兼容: +规划器会保持当前清单行为的兼容性: - `activation.*` 字段是显式的规划器提示 -- `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 以及 hooks 仍然作为清单归属关系的后备来源 -- 仅返回 id 的规划器 API 仍然对现有调用方可用 -- 规划 API 会报告 reason 标签,以便诊断区分显式提示与归属关系后备来源 +- `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子仍然是清单所有权回退来源 +- 仅 id 的规划器 API 仍然对现有调用方可用 +- 规划 API 会报告原因标签,以便诊断区分显式提示和所有权回退 -不要把 `activation` 视为生命周期 hook,也不要把它当作 `register(...)` 的替代品。它只是用于缩小加载范围的元数据。如果已有归属字段可以描述这种关系,就优先使用归属字段;只有在需要额外规划提示时才使用 `activation`。 +不要把 `activation` 视为生命周期钩子,也不要把它视为 `register(...)` 的替代品。它只是用于缩小加载范围的元数据。当现有所有权字段已经足以描述关系时,应优先使用它们;只有在需要额外规划器提示时,才使用 `activation`。 -### 渠道插件与共享 message 工具 +### 渠道插件和共享 message 工具 -对于常规聊天操作,渠道插件不需要单独注册发送 / 编辑 / 响应工具。OpenClaw 在核心中保留了一个共享的 `message` 工具,而渠道插件负责其背后的渠道特定设备发现和执行。 +对于常规聊天操作,渠道插件不需要单独注册发送 / 编辑 / 响应工具。OpenClaw 在核心中保留了一个共享的 `message` 工具,而渠道插件负责其背后的渠道特定发现与执行。 当前边界如下: -- 核心负责共享 `message` 工具宿主、提示词接线、session / thread 记账以及执行分发 -- 渠道插件负责作用域内操作发现、能力发现,以及任何渠道特定的 schema 片段 -- 渠道插件负责提供商特定的 session 会话语法,例如会话 id 如何编码 thread id,或如何从父会话继承 -- 渠道插件通过其 action adapter 执行最终操作 +- 核心拥有共享 `message` 工具宿主、提示词接线、会话 / 线程簿记和执行分派 +- 渠道插件拥有作用域动作发现、能力发现以及任何渠道特定的 schema 片段 +- 渠道插件拥有提供商特定的会话对话语法,例如对话 id 如何编码线程 id,或如何从父对话继承 +- 渠道插件通过其动作适配器执行最终动作 -对于渠道插件,SDK 接口为 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用让插件可以一起返回其可见操作、能力以及 schema 贡献,从而避免这些部分彼此漂移。 +对于渠道插件,SDK 接口是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用允许插件将其可见动作、能力和 schema 扩展一起返回,从而避免这些部分彼此漂移。 -当某个渠道特定的 message-tool 参数携带媒体来源,例如本地路径或远程媒体 URL 时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心会使用这份显式列表来应用沙箱路径规范化和出站媒体访问提示,而无需硬编码插件自有的参数名称。 -这里应优先使用按操作划分的映射,而不是整个渠道共用的一份扁平列表,这样仅用于 profile 的媒体参数就不会在 `send` 这类无关操作中被规范化。 +当某个渠道特定的消息工具参数携带媒体来源,例如本地路径或远程媒体 URL 时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心会使用这份显式列表来应用沙箱路径规范化和出站媒体访问提示,而不是硬编码插件拥有的参数名。 +这里应优先使用按动作划分的映射,而不是一个按渠道统一的扁平列表,这样仅用于 profile 的媒体参数就不会在 `send` 之类的不相关动作上被规范化。 -核心会把运行时作用域传入该发现步骤。重要字段包括: +核心会将运行时作用域传入这个发现步骤。重要字段包括: - `accountId` - `currentChannelId` @@ -172,80 +173,80 @@ OpenClaw 的插件系统分为四层: - `agentId` - 受信任的入站 `requesterSenderId` -这对于上下文敏感型插件很重要。一个渠道可以根据当前账户、当前房间 / thread / 消息,或受信任的请求方身份来隐藏或暴露消息操作,而无需在核心 `message` 工具中硬编码渠道特定分支。 +这对于上下文敏感型插件很重要。渠道可以根据活动账户、当前房间 / 线程 / 消息,或受信任的请求者身份,隐藏或暴露消息动作,而无需在核心 `message` 工具中硬编码渠道特定分支。 -这也是为什么嵌入式 runner 路由变更仍然属于插件工作:runner 负责把当前聊天 / session 身份转发到插件发现边界,从而让共享的 `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")` 是处理渠道特定投票语义或额外投票参数的首选路径 +- `actions.handleAction("poll")` 是用于渠道特定投票语义或额外投票参数的首选路径 -现在,核心会在插件投票分发拒绝该操作之后,才延迟执行共享投票解析,这样插件自有的投票处理器就能接受渠道特定的投票字段,而不会先被通用投票解析器拦住。 +现在,核心会在插件投票分发拒绝该动作之后,才回退到共享投票解析,因此由插件拥有的投票处理器可以接受渠道特定的投票字段,而不会先被通用投票解析器拦住。 完整启动顺序请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。 -## 能力归属模型 +## 能力所有权模型 -OpenClaw 将原生插件视为某个**公司**或某个**功能**的归属边界,而不是一堆互不相关集成的杂货袋。 +OpenClaw 将原生插件视为**公司**或**功能**的所有权边界,而不是一堆彼此无关的集成的集合。 这意味着: -- 一个公司插件通常应拥有该公司的所有面向 OpenClaw 的表面 -- 一个功能插件通常应拥有其引入的完整功能表面 +- 一个公司插件通常应拥有该公司的所有面向 OpenClaw 的接口 +- 一个功能插件通常应拥有它引入的完整功能接口 - 渠道应消费共享的核心能力,而不是临时重新实现提供商行为 - - - **厂商多能力**:`openai` 拥有文本推理、语音、实时语音、媒体理解和图像生成。`google` 拥有文本推理,以及媒体理解、图像生成和网页搜索。`qwen` 拥有文本推理,以及媒体理解和视频生成。 - - **厂商单能力**:`elevenlabs` 和 `microsoft` 拥有语音;`firecrawl` 拥有网页抓取;`minimax` / `mistral` / `moonshot` / `zai` 拥有媒体理解后端。 - - **功能插件**:`voice-call` 拥有通话传输、工具、CLI、路由和 Twilio 媒体流桥接,但它会消费共享的语音、实时转录和实时语音能力,而不是直接导入厂商插件。 + + - **供应商多能力**:`openai` 拥有文本推理、语音、实时语音、媒体理解和图像生成。`google` 拥有文本推理以及媒体理解、图像生成和网页搜索。`qwen` 拥有文本推理以及媒体理解和视频生成。 + - **供应商单能力**:`elevenlabs` 和 `microsoft` 拥有语音;`firecrawl` 拥有网页抓取;`minimax` / `mistral` / `moonshot` / `zai` 拥有媒体理解后端。 + - **功能插件**:`voice-call` 拥有通话传输、工具、CLI、路由和 Twilio 媒体流桥接,但它消费共享的语音、实时转录和实时语音能力,而不是直接导入供应商插件。 预期的最终状态是: -- 即使 OpenAI 横跨文本模型、语音、图像以及未来的视频,它也只存在于一个插件中 -- 其他厂商也可以对自己的表面区域采用同样方式 -- 渠道不需要关心哪个厂商插件拥有该提供商;它们消费的是由核心暴露的共享能力契约 +- 即使 OpenAI 横跨文本模型、语音、图像和未来的视频,也应存在于一个插件中 +- 其他供应商也可以对自己的接口范围采用相同方式 +- 渠道不关心哪个供应商插件拥有该提供商;它们只消费核心暴露的共享能力契约 这是关键区别: -- **plugin** = 归属边界 +- **plugin** = 所有权边界 - **capability** = 可由多个插件实现或消费的核心契约 -因此,如果 OpenClaw 新增一个领域,例如视频,首要问题不是“哪个提供商应该硬编码视频处理?”首要问题是“核心视频能力契约是什么?”一旦该契约存在,厂商插件就可以对其注册,渠道 / 功能插件也可以消费它。 +因此,如果 OpenClaw 添加了一个新领域,例如视频,第一个问题不应该是“哪个提供商应该硬编码视频处理?”第一个问题应该是“核心的视频能力契约是什么?”一旦该契约存在,供应商插件就可以针对它进行注册,而渠道 / 功能插件也可以消费它。 如果该能力尚不存在,通常正确的做法是: 1. 在核心中定义缺失的能力 -2. 通过插件 API / 运行时以类型化方式暴露它 -3. 让渠道 / 功能围绕该能力完成接线 -4. 让厂商插件注册实现 +2. 通过插件 API / 运行时以类型化方式将其暴露出来 +3. 让渠道 / 功能对接该能力 +4. 让供应商插件注册实现 -这样既能保持归属关系清晰,又能避免依赖单一厂商或一次性插件专用代码路径的核心行为。 +这样既能保持所有权明确,又能避免核心行为依赖于某个单一供应商或某条一次性的插件特定代码路径。 ### 能力分层 -在决定代码应放在哪里时,可使用以下思维模型: +在决定代码归属位置时,可使用以下心智模型: - **核心能力层**:共享编排、策略、回退、配置合并规则、交付语义和类型化契约 -- **厂商插件层**:厂商特定 API、认证、模型目录、语音合成、图像生成、未来的视频后端、使用量端点 -- **渠道 / 功能插件层**:Slack / Discord / voice-call / 等集成,负责消费核心能力并将其呈现在某个表面上 +- **供应商插件层**:供应商特定 API、认证、模型目录、语音合成、图像生成、未来的视频后端、用量端点 +- **渠道 / 功能插件层**:Slack / Discord / voice-call / 等集成,它们消费核心能力并将其呈现在某个界面上 -例如,TTS 采用如下结构: +例如,TTS 遵循以下结构: -- 核心负责回复时 TTS 策略、回退顺序、偏好设置和渠道交付 -- `openai`、`elevenlabs` 和 `microsoft` 负责合成实现 -- `voice-call` 消费电话 TTS 运行时辅助接口 +- 核心拥有回复时 TTS 策略、回退顺序、偏好设置和渠道交付 +- `openai`、`elevenlabs` 和 `microsoft` 拥有合成实现 +- `voice-call` 消费电话 TTS 运行时辅助工具 -未来的新能力也应优先采用相同模式。 +未来能力也应优先采用同样的模式。 ### 多能力公司插件示例 -一个公司插件从外部看应当是内聚的。如果 OpenClaw 为模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、网页抓取和网页搜索提供了共享契约,那么某个厂商就可以在一个地方拥有其所有表面: +从外部看,一个公司插件应当具有一致性。如果 OpenClaw 具有用于模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、网页抓取和网页搜索的共享契约,那么某个供应商可以在一个地方拥有其全部接口: ```ts import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry"; @@ -299,107 +300,112 @@ 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)。 ## 契约与强制执行 -插件 API 表面有意通过 `OpenClawPluginApi` 进行类型化和集中化。该契约定义了受支持的注册点,以及插件可依赖的运行时辅助接口。 +插件 API 接口被有意设计为类型化,并集中在 +`OpenClawPluginApi` 中。这个契约定义了受支持的注册点,以及插件可依赖的运行时辅助工具。 -这很重要,原因如下: +这很重要,因为: -- 插件作者获得一套稳定的内部标准 -- 核心可以拒绝重复归属,例如两个插件注册相同的提供商 id -- 启动过程可以为格式错误的注册提供可操作的诊断信息 -- 契约测试可以强制执行内置插件归属,防止无声漂移 +- 插件作者可以获得一个稳定的内部标准 +- 核心可以拒绝重复所有权,例如两个插件注册同一个 provider id +- 启动过程可以为格式错误的注册暴露可操作的诊断信息 +- 契约测试可以强制执行内置插件的所有权,并防止无声漂移 这里有两层强制执行: 1. **运行时注册强制执行** - 插件注册表会在插件加载时验证注册内容。例如:重复的提供商 id、重复的语音提供商 id,以及格式错误的注册,都会产出插件诊断,而不是导致未定义行为。 + 插件注册表会在插件加载时验证注册内容。例如:重复的 provider id、重复的语音提供商 id,以及格式错误的注册,都会产生插件诊断,而不是导致未定义行为。 2. **契约测试** - 在测试运行期间,内置插件会被捕获到契约注册表中,以便 OpenClaw 可以显式断言归属关系。目前这已用于模型提供商、语音提供商、网页搜索提供商以及内置注册归属。 + 内置插件会在测试运行期间被记录到契约注册表中,因此 OpenClaw 可以显式断言所有权。如今,这已被用于模型提供商、语音提供商、网页搜索提供商以及内置注册所有权。 -实际效果是,OpenClaw 能在一开始就知道哪个插件拥有哪个表面。这样核心和渠道就能无缝组合,因为归属是声明式、类型化且可测试的,而不是隐式的。 +实际效果是,OpenClaw 可以预先知道哪个插件拥有哪个接口。这使得核心和渠道可以无缝组合,因为所有权是声明式、类型化且可测试的,而不是隐式的。 ### 什么内容应属于契约 -好的插件契约应当具备以下特点: +好的插件契约应当是: -- 有类型 -- 小而精 -- 能力特定 -- 由核心拥有 +- 类型化的 +- 小而精的 +- 能力特定的 +- 由核心拥有的 - 可被多个插件复用 -- 可在不了解厂商细节的前提下被渠道 / 功能消费 +- 可被渠道 / 功能消费,而无需了解供应商细节 不好的插件契约包括: -- 隐藏在核心中的厂商特定策略 -- 绕过注册表的一次性插件逃逸口 -- 直接探入厂商实现的渠道代码 -- 不属于 `OpenClawPluginApi` 或 `api.runtime` 的临时运行时对象 +- 隐藏在核心中的供应商特定策略 +- 绕过注册表的一次性插件逃生口 +- 直接深入供应商实现的渠道代码 +- 不属于 `OpenClawPluginApi` 或 + `api.runtime` 的临时运行时对象 -如果拿不准,应提高抽象层级:先定义能力,再让插件接入它。 +如果有疑问,请提升抽象层级:先定义能力,再让插件接入它。 ## 执行模型 -原生 OpenClaw 插件与 Gateway 网关**在同一进程内**运行。它们不在沙箱中。已加载的原生插件与核心代码处于相同的进程级信任边界内。 +原生 OpenClaw 插件会与 Gateway 网关**在同一进程内**运行。它们不是沙箱隔离的。已加载的原生插件与核心代码具有相同的进程级信任边界。 -其含义包括: +这意味着: -- 原生插件可以注册工具、网络处理器、hooks 和服务 -- 原生插件中的 bug 可能导致 Gateway 网关崩溃或失稳 +- 原生插件可以注册工具、网络处理器、钩子和服务 +- 原生插件中的 bug 可能导致 Gateway 网关崩溃或不稳定 - 恶意原生插件等同于在 OpenClaw 进程内执行任意代码 -兼容 bundle 默认更安全,因为 OpenClaw 当前将它们视为元数据 / 内容包。在当前版本中,这主要意味着内置 Skills。 +兼容的 bundle 默认更安全,因为 OpenClaw 目前将其视为元数据 / 内容包。在当前版本中,这主要意味着内置 Skills。 -对于非内置插件,请使用 allowlist 和显式安装 / 加载路径。将工作区插件视为开发期代码,而不是生产环境默认项。 +对于非内置插件,请使用 allowlist 和显式的安装 / 加载路径。应将工作区插件视为开发阶段代码,而不是生产默认值。 -对于内置工作区包名,请让插件 id 默认锚定在 npm 名称中:`@openclaw/`,或者使用经过批准的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`,前提是该包有意暴露更窄的插件角色。 +对于内置工作区包名,应让插件 id 默认锚定在 npm 名称中:默认使用 `@openclaw/`,或者在包有意暴露更窄插件角色时,使用经批准的类型化后缀,例如 +`-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`。 重要的信任说明: - `plugins.allow` 信任的是**插件 id**,而不是来源出处。 -- 与内置插件拥有相同 id 的工作区插件,在该工作区插件被启用 / 加入 allowlist 时,会有意遮蔽内置副本。 -- 这属于正常且有用的行为,适用于本地开发、补丁测试和热修复。 -- 内置插件信任是根据源码快照解析的——即加载时磁盘上的清单和代码——而不是根据安装元数据解析。损坏或被替换的安装记录,不能在实际源码声明之外静默扩大内置插件的信任表面。 +- 与内置插件具有相同 id 的工作区插件,在被启用 / 加入 allowlist 时,会有意覆盖内置副本。 +- 这对于本地开发、补丁测试和热修复来说是正常且有用的。 +- 内置插件的信任是根据源快照来解析的——即加载时磁盘上的清单和代码——而不是根据安装元数据。损坏或被替换的安装记录不能在实际源码声明范围之外,悄悄扩大内置插件的信任接口。 ## 导出边界 -OpenClaw 导出的是能力,而不是实现便利接口。 +OpenClaw 导出的是能力,而不是实现便利性。 -保持能力注册公开。应裁剪非契约辅助导出: +应保持能力注册公开。应精简非契约辅助导出: - 内置插件特定的辅助子路径 -- 不打算作为公开 API 的运行时管线子路径 -- 厂商特定的便捷辅助函数 -- 属于实现细节的设置 / 新手引导辅助函数 +- 无意作为公共 API 的运行时管线子路径 +- 供应商特定的便捷辅助工具 +- 属于实现细节的设置 / 新手引导辅助工具 -为了兼容性和内置插件维护,某些内置插件辅助子路径仍保留在生成的 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 模式。 ## 内部机制与参考 -关于加载流水线、注册表模型、提供商运行时钩子、Gateway 网关 HTTP 路由、message 工具 schema、渠道目标解析、提供商目录、上下文引擎插件,以及新增能力的指南,请参见 +有关加载流程、注册表模型、提供商运行时钩子、Gateway 网关 HTTP 路由、消息工具 schema、渠道目标解析、提供商目录、上下文引擎插件,以及新增能力的指南,请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。 ## 相关内容 diff --git a/docs/zh-CN/plugins/manifest.md b/docs/zh-CN/plugins/manifest.md index 2da98438b..a41e211c5 100644 --- a/docs/zh-CN/plugins/manifest.md +++ b/docs/zh-CN/plugins/manifest.md @@ -1,19 +1,19 @@ --- read_when: - 你正在构建一个 OpenClaw 插件 - - 你需要提供插件配置 schema,或调试插件验证错误 -summary: 插件清单 + JSON schema 要求(严格配置验证) + - 你需要发布一个插件配置模式,或调试插件验证错误 +summary: 插件清单 + JSON 模式要求(严格配置验证) title: 插件清单 x-i18n: - generated_at: "2026-04-24T05:09:38Z" + generated_at: "2026-04-24T06:33:29Z" model: gpt-5.4 provider: openai - source_hash: d27765f1efc9720bd68c73d3ede796a91e9afec479f89eda531dd14adc708e53 + source_hash: e680a978c4f0bc8fec099462a6e08585f39dfd72e0c159ecfe5162586e7d7258 source_path: plugins/manifest.md workflow: 15 --- -本页仅适用于**原生 OpenClaw 插件清单**。 +此页面仅适用于**原生 OpenClaw 插件清单**。 关于兼容的 bundle 布局,请参阅 [Plugin bundles](/zh-CN/plugins/bundles)。 @@ -23,29 +23,29 @@ x-i18n: - Claude bundle:`.claude-plugin/plugin.json`,或不带清单的默认 Claude 组件布局 - Cursor bundle:`.cursor-plugin/plugin.json` -OpenClaw 也会自动检测这些 bundle 布局,但不会按照这里描述的 `openclaw.plugin.json` schema 对它们进行验证。 +OpenClaw 也会自动检测这些 bundle 布局,但不会根据这里描述的 `openclaw.plugin.json` 模式对其进行验证。 -对于兼容 bundle,当前在布局符合 OpenClaw 运行时预期时,OpenClaw 会读取 bundle 元数据、声明的 skill 根目录、Claude 命令根目录、Claude bundle 的 `settings.json` 默认值、Claude bundle 的 LSP 默认值,以及受支持的 hook pack。 +对于兼容 bundle,OpenClaw 当前会在布局符合 OpenClaw 运行时预期时,读取 bundle 元数据以及已声明的 skill 根目录、Claude 命令根目录、Claude bundle `settings.json` 默认值、Claude bundle LSP 默认值,以及受支持的 hook pack。 -每个原生 OpenClaw 插件**都必须**在**插件根目录**中提供一个 `openclaw.plugin.json` 文件。OpenClaw 使用此清单在**不执行插件代码的情况下**验证配置。缺失或无效的清单会被视为插件错误,并阻止配置验证。 +每个原生 OpenClaw 插件**必须**在**插件根目录**中提供一个 `openclaw.plugin.json` 文件。OpenClaw 使用此清单在**不执行插件代码的情况下**验证配置。缺失或无效的清单会被视为插件错误,并阻止配置验证。 -请参阅完整的插件系统指南:[Plugins](/zh-CN/tools/plugin)。 -关于原生能力模型及当前的外部兼容性指导,请参阅: +查看完整的插件系统指南:[Plugins](/zh-CN/tools/plugin)。 +关于原生能力模型和当前的外部兼容性指引,请参阅: [Capability model](/zh-CN/plugins/architecture#public-capability-model)。 ## 此文件的作用 -`openclaw.plugin.json` 是 OpenClaw 在**加载你的插件代码之前**读取的元数据。下面的所有内容都必须足够轻量,能够在不启动插件运行时的情况下进行检查。 +`openclaw.plugin.json` 是 OpenClaw 在**加载你的插件代码之前**读取的元数据。以下所有内容都必须足够轻量,以便在不启动插件运行时的情况下进行检查。 **用于:** - 插件标识、配置验证,以及配置 UI 提示 -- 凭证、onboarding 和设置元数据(别名、自动启用、provider 环境变量、认证选项) +- 凭证、onboarding 和设置元数据(别名、自动启用、provider 环境变量、凭证选择) - 控制平面界面的激活提示 - 简写的模型家族归属 - 静态能力归属快照(`contracts`) -- 共享 `openclaw qa` 主机可检查的 QA runner 元数据 -- 合并到目录和验证界面中的特定于渠道的配置元数据 +- 供共享 `openclaw qa` 主机检查的 QA 运行器元数据 +- 合并到目录和验证界面的渠道专用配置元数据 **不要用于:**注册运行时行为、声明代码入口点,或 npm 安装元数据。这些应放在你的插件代码和 `package.json` 中。 @@ -129,64 +129,64 @@ OpenClaw 也会自动检测这些 bundle 布局,但不会按照这里描述的 | 字段 | 必填 | 类型 | 含义 | | ------------------------------------ | -------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `id` | 是 | `string` | 规范的插件 id。这是 `plugins.entries.` 中使用的 id。 | +| `id` | 是 | `string` | 规范的插件 id。这是在 `plugins.entries.` 中使用的 id。 | | `configSchema` | 是 | `object` | 此插件配置的内联 JSON Schema。 | -| `enabledByDefault` | 否 | `true` | 将内置插件标记为默认启用。省略此字段,或将其设置为任何非 `true` 的值,则该插件默认禁用。 | -| `legacyPluginIds` | 否 | `string[]` | 会规范化为此规范插件 id 的旧版 id。 | +| `enabledByDefault` | 否 | `true` | 将内置插件标记为默认启用。省略它,或设置为任何非 `true` 的值,都会使该插件默认保持禁用。 | +| `legacyPluginIds` | 否 | `string[]` | 会被规范化为此规范插件 id 的旧版 id。 | | `autoEnableWhenConfiguredProviders` | 否 | `string[]` | 当凭证、配置或模型引用提到这些 provider id 时,应自动启用此插件。 | -| `kind` | 否 | `"memory"` \| `"context-engine"` | 声明 `plugins.slots.*` 使用的独占插件类型。 | -| `channels` | 否 | `string[]` | 此插件拥有的渠道 id。用于设备发现和配置验证。 | -| `providers` | 否 | `string[]` | 此插件拥有的 provider id。 | -| `providerDiscoveryEntry` | 否 | `string` | 轻量级 provider 发现模块路径,相对于插件根目录,用于可在不激活完整插件运行时的情况下加载的、受清单作用域约束的 provider 目录元数据。 | +| `kind` | 否 | `"memory"` \| `"context-engine"` | 声明一个由 `plugins.slots.*` 使用的排他性插件类型。 | +| `channels` | 否 | `string[]` | 由此插件拥有的渠道 id。用于发现和配置验证。 | +| `providers` | 否 | `string[]` | 由此插件拥有的 provider id。 | +| `providerDiscoveryEntry` | 否 | `string` | 轻量级 provider 发现模块路径,相对于插件根目录,用于可在不激活完整插件运行时的情况下加载的、限定于清单作用域的 provider 目录元数据。 | | `modelSupport` | 否 | `object` | 由清单拥有的简写模型家族元数据,用于在运行时之前自动加载插件。 | -| `providerEndpoints` | 否 | `object[]` | 由清单拥有的 endpoint 主机 / `baseUrl` 元数据,用于核心在 provider 运行时加载前必须分类的 provider 路由。 | -| `cliBackends` | 否 | `string[]` | 此插件拥有的 CLI 推理后端 id。用于根据显式配置引用在启动时自动激活。 | -| `syntheticAuthRefs` | 否 | `string[]` | provider 或 CLI 后端引用,在运行时加载前的冷启动模型发现期间,应探测其插件拥有的 synthetic auth hook。 | -| `nonSecretAuthMarkers` | 否 | `string[]` | 由内置插件拥有的占位 API key 值,表示非秘密的本地、OAuth 或环境凭证状态。 | -| `commandAliases` | 否 | `object[]` | 此插件拥有的命令名称,在运行时加载前应生成带有插件感知能力的配置和 CLI 诊断信息。 | -| `providerAuthEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级 provider 认证环境变量元数据。 | -| `providerAuthAliases` | 否 | `Record` | 应复用另一个 provider id 进行认证查找的 provider id,例如共享基础 provider API key 和认证配置文件的 coding provider。 | -| `channelEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级渠道环境变量元数据。将其用于由环境变量驱动的渠道设置,或通用启动 / 配置辅助工具应识别的认证界面。 | -| `providerAuthChoices` | 否 | `object[]` | 用于 onboarding 选择器、首选 provider 解析和简单 CLI 标志接线的轻量级认证选项元数据。 | -| `activation` | 否 | `object` | 用于 provider、命令、渠道、路由和能力触发加载的轻量级激活规划器元数据。仅为元数据;实际行为仍由插件运行时负责。 | -| `setup` | 否 | `object` | 可供设备发现和设置界面在不加载插件运行时的情况下检查的轻量级设置 / onboarding 描述符。 | -| `qaRunners` | 否 | `object[]` | 共享 `openclaw qa` 主机在插件运行时加载前使用的轻量级 QA runner 描述符。 | -| `contracts` | 否 | `object` | 用于 external auth hook、语音、实时转录、实时语音、媒体理解、图像生成、音乐生成、视频生成、web-fetch、网页搜索和工具归属的静态内置能力快照。 | +| `providerEndpoints` | 否 | `object[]` | 由清单拥有的 endpoint host/baseUrl 元数据,用于核心在 provider 运行时加载前对 provider 路由进行分类。 | +| `cliBackends` | 否 | `string[]` | 由此插件拥有的 CLI 推理后端 id。用于基于显式配置引用在启动时自动激活。 | +| `syntheticAuthRefs` | 否 | `string[]` | provider 或 CLI 后端引用;在运行时加载前的冷启动模型发现期间,应探测其由插件拥有的 synthetic auth hook。 | +| `nonSecretAuthMarkers` | 否 | `string[]` | 由内置插件拥有的占位 API key 值,用于表示非机密的本地、OAuth 或环境凭证状态。 | +| `commandAliases` | 否 | `object[]` | 由此插件拥有的命令名称;在运行时加载前,这些命令应生成具备插件感知能力的配置和 CLI 诊断信息。 | +| `providerAuthEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级 provider 凭证环境变量元数据。 | +| `providerAuthAliases` | 否 | `Record` | 应复用另一个 provider id 进行凭证查找的 provider id,例如共享基础 provider API key 和凭证配置文件的 coding provider。 | +| `channelEnvVars` | 否 | `Record` | OpenClaw 可在不加载插件代码的情况下检查的轻量级渠道环境变量元数据。将其用于由环境变量驱动的渠道设置,或用于通用启动/配置辅助工具应看到的凭证界面。 | +| `providerAuthChoices` | 否 | `object[]` | 用于 onboarding 选择器、首选 provider 解析和简单 CLI flag 绑定的轻量级凭证选择元数据。 | +| `activation` | 否 | `object` | 用于 provider、命令、渠道、路由和由能力触发的加载的轻量级激活规划器元数据。仅限元数据;实际行为仍由插件运行时负责。 | +| `setup` | 否 | `object` | 供发现和设置界面在不加载插件运行时的情况下检查的轻量级设置 / onboarding 描述符。 | +| `qaRunners` | 否 | `object[]` | 共享 `openclaw qa` 主机在插件运行时加载前使用的轻量级 QA 运行器描述符。 | +| `contracts` | 否 | `object` | 面向外部凭证 hook、语音、实时转录、实时语音、媒体理解、图像生成、音乐生成、视频生成、网页抓取、网页搜索和工具归属的静态内置能力快照。 | | `mediaUnderstandingProviderMetadata` | 否 | `Record` | 为 `contracts.mediaUnderstandingProviders` 中声明的 provider id 提供的轻量级媒体理解默认值。 | -| `channelConfigs` | 否 | `Record` | 由清单拥有的渠道配置元数据,在运行时加载前合并到设备发现和验证界面中。 | -| `skills` | 否 | `string[]` | 要加载的 Skill 目录,相对于插件根目录。 | +| `channelConfigs` | 否 | `Record` | 由清单拥有的渠道配置元数据,会在运行时加载前合并到发现和验证界面中。 | +| `skills` | 否 | `string[]` | 要加载的 Skills 目录,相对于插件根目录。 | | `name` | 否 | `string` | 人类可读的插件名称。 | | `description` | 否 | `string` | 显示在插件界面中的简短摘要。 | -| `version` | 否 | `string` | 仅供参考的插件版本。 | +| `version` | 否 | `string` | 信息性插件版本。 | | `uiHints` | 否 | `Record` | 配置字段的 UI 标签、占位符和敏感性提示。 | ## `providerAuthChoices` 参考 -每个 `providerAuthChoices` 条目描述一个 onboarding 或认证选项。 -OpenClaw 会在 provider 运行时加载前读取它。 +每个 `providerAuthChoices` 条目描述一个 onboarding 或凭证选择。 +OpenClaw 会在 provider 运行时加载前读取这些内容。 | 字段 | 必填 | 类型 | 含义 | | --------------------- | -------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -| `provider` | 是 | `string` | 此选项所属的 provider id。 | -| `method` | 是 | `string` | 要分派到的认证方法 id。 | -| `choiceId` | 是 | `string` | onboarding 和 CLI 流程使用的稳定认证选项 id。 | +| `provider` | 是 | `string` | 此选择所属的 provider id。 | +| `method` | 是 | `string` | 要分发到的凭证方法 id。 | +| `choiceId` | 是 | `string` | onboarding 和 CLI 流程中使用的稳定凭证选择 id。 | | `choiceLabel` | 否 | `string` | 面向用户的标签。如果省略,OpenClaw 会回退到 `choiceId`。 | -| `choiceHint` | 否 | `string` | 选择器的简短辅助文本。 | -| `assistantPriority` | 否 | `number` | 在由智能体驱动的交互式选择器中,值越小排序越靠前。 | -| `assistantVisibility` | 否 | `"visible"` \| `"manual-only"` | 在智能体选择器中隐藏该选项,但仍允许通过手动 CLI 进行选择。 | -| `deprecatedChoiceIds` | 否 | `string[]` | 应将用户重定向到此替代选项的旧版选项 id。 | -| `groupId` | 否 | `string` | 用于对相关选项进行分组的可选组 id。 | -| `groupLabel` | 否 | `string` | 该组面向用户的标签。 | -| `groupHint` | 否 | `string` | 该组的简短辅助文本。 | -| `optionKey` | 否 | `string` | 用于简单单标志认证流程的内部选项键。 | -| `cliFlag` | 否 | `string` | CLI 标志名称,例如 `--openrouter-api-key`。 | +| `choiceHint` | 否 | `string` | 选择器中的简短帮助文本。 | +| `assistantPriority` | 否 | `number` | 在由 assistant 驱动的交互式选择器中,值越小排序越靠前。 | +| `assistantVisibility` | 否 | `"visible"` \| `"manual-only"` | 在 assistant 选择器中隐藏此选择,但仍允许手动通过 CLI 选择。 | +| `deprecatedChoiceIds` | 否 | `string[]` | 应将用户重定向到此替代选择的旧版 choice id。 | +| `groupId` | 否 | `string` | 用于对相关选择分组的可选分组 id。 | +| `groupLabel` | 否 | `string` | 该分组面向用户的标签。 | +| `groupHint` | 否 | `string` | 该分组的简短帮助文本。 | +| `optionKey` | 否 | `string` | 用于简单单 flag 凭证流程的内部选项键。 | +| `cliFlag` | 否 | `string` | CLI flag 名称,例如 `--openrouter-api-key`。 | | `cliOption` | 否 | `string` | 完整的 CLI 选项形式,例如 `--openrouter-api-key `。 | -| `cliDescription` | 否 | `string` | 在 CLI 帮助中使用的说明。 | -| `onboardingScopes` | 否 | `Array<"text-inference" \| "image-generation">` | 此选项应出现在哪些 onboarding 界面中。如果省略,默认值为 `["text-inference"]`。 | +| `cliDescription` | 否 | `string` | CLI 帮助中使用的描述。 | +| `onboardingScopes` | 否 | `Array<"text-inference" \| "image-generation">` | 此选择应出现在哪些 onboarding 界面中。如果省略,默认值为 `["text-inference"]`。 | ## `commandAliases` 参考 -当插件拥有一个运行时命令名称,而用户可能会误将其放入 `plugins.allow`,或尝试将其作为根 CLI 命令运行时,请使用 `commandAliases`。OpenClaw 使用这些元数据来生成诊断信息,而无需导入插件运行时代码。 +当插件拥有某个运行时命令名,而用户可能会误将其放入 `plugins.allow`,或尝试将其作为根 CLI 命令运行时,请使用 `commandAliases`。OpenClaw 使用这些元数据提供诊断,而无需导入插件运行时代码。 ```json { @@ -204,17 +204,17 @@ OpenClaw 会在 provider 运行时加载前读取它。 | ------------ | -------- | ----------------- | ----------------------------------------------------------------------- | | `name` | 是 | `string` | 属于此插件的命令名称。 | | `kind` | 否 | `"runtime-slash"` | 将该别名标记为聊天斜杠命令,而不是根 CLI 命令。 | -| `cliCommand` | 否 | `string` | 若存在,用于 CLI 操作时建议的相关根 CLI 命令。 | +| `cliCommand` | 否 | `string` | 若存在,用于建议 CLI 操作的相关根 CLI 命令。 | ## `activation` 参考 当插件可以以低成本声明哪些控制平面事件应将其纳入激活 / 加载计划时,请使用 `activation`。 -此块是规划器元数据,而不是生命周期 API。它不会注册运行时行为,不会替代 `register(...)`,也不保证插件代码已经执行。激活规划器使用这些字段来缩小候选插件范围,然后才回退到现有的清单归属元数据,例如 `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和 hooks。 +此块是规划器元数据,而不是生命周期 API。它不会注册运行时行为,不会替代 `register(...)`,也不保证插件代码已经执行。激活规划器使用这些字段在回退到现有清单归属元数据(如 `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和 hooks)之前缩小候选插件范围。 -优先使用已经能够描述归属关系的最窄元数据。如果 `providers`、`channels`、`commandAliases`、设置描述符或 `contracts` 已能表达这种关系,请使用这些字段。只有当这些归属字段无法表示额外的规划器提示时,才使用 `activation`。 +优先使用已经能描述归属关系的最窄元数据。当这些字段能够表达关系时,请使用 `providers`、`channels`、`commandAliases`、设置描述符或 `contracts`。仅在这些归属字段无法表示额外的规划器提示时,才使用 `activation`。 -此块仅为元数据。它不会注册运行时行为,也不会替代 `register(...)`、`setupEntry` 或其他运行时 / 插件入口点。当前使用方将其用作更广泛插件加载前的缩小范围提示,因此缺少激活元数据通常只会带来性能成本;在旧版清单归属回退仍然存在的情况下,不应改变正确性。 +此块仅包含元数据。它不会注册运行时行为,也不会替代 `register(...)`、`setupEntry` 或其他运行时 / 插件入口点。当前使用方会在更广泛的插件加载之前,将其作为缩小范围的提示,因此缺少激活元数据通常只会带来性能成本;在旧版清单归属回退仍存在时,它不应影响正确性。 ```json { @@ -234,22 +234,23 @@ OpenClaw 会在 provider 运行时加载前读取它。 | `onCommands` | 否 | `string[]` | 应将此插件纳入激活 / 加载计划的命令 id。 | | `onChannels` | 否 | `string[]` | 应将此插件纳入激活 / 加载计划的渠道 id。 | | `onRoutes` | 否 | `string[]` | 应将此插件纳入激活 / 加载计划的路由类型。 | -| `onCapabilities` | 否 | `Array<"provider" \| "channel" \| "tool" \| "hook">` | 控制平面激活规划使用的宽泛能力提示。能用更窄字段时应优先使用更窄字段。 | +| `onCapabilities` | 否 | `Array<"provider" \| "channel" \| "tool" \| "hook">` | 控制平面激活规划中使用的宽泛能力提示。若可能,优先使用更窄的字段。 | 当前在线使用方: - 由命令触发的 CLI 规划会回退到旧版 `commandAliases[].cliCommand` 或 `commandAliases[].name` -- 由渠道触发的设置 / 渠道规划在缺少显式渠道激活元数据时, - 会回退到旧版 `channels[]` 归属 +- 由渠道触发的设置 / 渠道规划在缺少显式渠道激活元数据时,会回退到旧版 `channels[]` + 归属 - 由 provider 触发的设置 / 运行时规划在缺少显式 provider - 激活元数据时,会回退到旧版 `providers[]` 和顶层 `cliBackends[]` 归属 + 激活元数据时,会回退到旧版 + `providers[]` 和顶层 `cliBackends[]` 归属 -规划器诊断可以区分显式激活提示和清单归属回退。例如,`activation-command-hint` 表示匹配了 `activation.onCommands`,而 `manifest-command-alias` 表示规划器改用了 `commandAliases` 归属。这些原因标签用于主机诊断和测试;插件作者应继续声明最能描述归属关系的元数据。 +规划器诊断可以区分显式激活提示和清单归属回退。例如,`activation-command-hint` 表示匹配了 `activation.onCommands`,而 `manifest-command-alias` 表示规划器改为使用 `commandAliases` 归属。这些原因标签用于主机诊断和测试;插件作者应继续声明最能描述归属关系的元数据。 ## `qaRunners` 参考 -当插件在共享 `openclaw qa` 根命令下贡献一个或多个传输 runner 时,请使用 `qaRunners`。保持这些元数据轻量且静态;实际的 CLI 注册仍由插件运行时通过导出 `qaRunnerCliRegistrations` 的轻量级 `runtime-api.ts` 界面负责。 +当插件在共享的 `openclaw qa` 根命令下提供一个或多个传输运行器时,请使用 `qaRunners`。保持这些元数据轻量且静态;实际的 CLI 注册仍由插件运行时通过导出 `qaRunnerCliRegistrations` 的轻量级 `runtime-api.ts` 接口负责。 ```json { @@ -265,11 +266,11 @@ OpenClaw 会在 provider 运行时加载前读取它。 | 字段 | 必填 | 类型 | 含义 | | ------------- | -------- | -------- | ------------------------------------------------------------------ | | `commandName` | 是 | `string` | 挂载在 `openclaw qa` 下的子命令,例如 `matrix`。 | -| `description` | 否 | `string` | 当共享主机需要 stub 命令时使用的回退帮助文本。 | +| `description` | 否 | `string` | 当共享主机需要一个 stub 命令时使用的回退帮助文本。 | ## `setup` 参考 -当设置和 onboarding 界面在运行时加载前需要插件拥有的轻量级元数据时,请使用 `setup`。 +当设置和 onboarding 界面需要在运行时加载前读取由插件拥有的轻量级元数据时,请使用 `setup`。 ```json { @@ -288,18 +289,18 @@ OpenClaw 会在 provider 运行时加载前读取它。 } ``` -顶层 `cliBackends` 仍然有效,并继续描述 CLI 推理后端。`setup.cliBackends` 是面向控制平面 / 设置流程、应保持仅元数据形式的设置专用描述符界面。 +顶层 `cliBackends` 依然有效,并继续描述 CLI 推理后端。`setup.cliBackends` 是用于控制平面 / 设置流程的、仅元数据的设置专用描述符界面。 -存在时,`setup.providers` 和 `setup.cliBackends` 是设置发现的首选描述符优先查找界面。如果描述符仅用于缩小候选插件范围,而设置仍需要更丰富的设置时运行时 hook,请将 `requiresRuntime` 设为 `true`,并保留 `setup-api` 作为回退执行路径。 +如果存在,`setup.providers` 和 `setup.cliBackends` 是设置发现时优先使用的描述符优先查找界面。如果该描述符只能缩小候选插件范围,而设置仍需要更丰富的设置时运行时 hook,请将 `requiresRuntime` 设为 `true`,并保留 `setup-api` 作为回退执行路径。 -由于设置查找可能会执行插件拥有的 `setup-api` 代码,规范化后的 `setup.providers[].id` 和 `setup.cliBackends[]` 值在已发现插件之间必须保持唯一。归属关系不明确时会采用失败即关闭的方式,而不是根据发现顺序选择一个“赢家”。 +由于设置查找可能会执行由插件拥有的 `setup-api` 代码,规范化后的 `setup.providers[].id` 和 `setup.cliBackends[]` 值在所有已发现插件之间必须保持唯一。归属不明确时会以封闭失败处理,而不是按发现顺序选出一个获胜者。 ### `setup.providers` 参考 | 字段 | 必填 | 类型 | 含义 | | ------------- | -------- | ---------- | ------------------------------------------------------------------------------------ | | `id` | 是 | `string` | 在设置或 onboarding 期间暴露的 provider id。保持规范化 id 在全局范围内唯一。 | -| `authMethods` | 否 | `string[]` | 此 provider 在不加载完整运行时的情况下支持的设置 / 认证方法 id。 | +| `authMethods` | 否 | `string[]` | 此 provider 在不加载完整运行时的情况下支持的设置 / 凭证方法 id。 | | `envVars` | 否 | `string[]` | 通用设置 / 状态界面可在插件运行时加载前检查的环境变量。 | ### `setup` 字段 @@ -308,8 +309,8 @@ OpenClaw 会在 provider 运行时加载前读取它。 | ------------------ | -------- | ---------- | --------------------------------------------------------------------------------------------------- | | `providers` | 否 | `object[]` | 在设置和 onboarding 期间暴露的 provider 设置描述符。 | | `cliBackends` | 否 | `string[]` | 用于描述符优先设置查找的设置时后端 id。保持规范化 id 在全局范围内唯一。 | -| `configMigrations` | 否 | `string[]` | 由此插件设置界面拥有的配置迁移 id。 | -| `requiresRuntime` | 否 | `boolean` | 在描述符查找之后,设置是否仍需要执行 `setup-api`。 | +| `configMigrations` | 否 | `string[]` | 由此插件的设置界面拥有的配置迁移 id。 | +| `requiresRuntime` | 否 | `boolean` | 描述符查找后,设置是否仍需要执行 `setup-api`。 | ## `uiHints` 参考 @@ -333,15 +334,15 @@ OpenClaw 会在 provider 运行时加载前读取它。 | 字段 | 类型 | 含义 | | ------------- | ---------- | --------------------------------------- | | `label` | `string` | 面向用户的字段标签。 | -| `help` | `string` | 简短辅助文本。 | +| `help` | `string` | 简短帮助文本。 | | `tags` | `string[]` | 可选的 UI 标签。 | -| `advanced` | `boolean` | 将该字段标记为高级项。 | -| `sensitive` | `boolean` | 将该字段标记为秘密或敏感项。 | +| `advanced` | `boolean` | 将该字段标记为高级字段。 | +| `sensitive` | `boolean` | 将该字段标记为机密或敏感字段。 | | `placeholder` | `string` | 表单输入的占位文本。 | ## `contracts` 参考 -仅当 OpenClaw 可以在不导入插件运行时的情况下读取静态能力归属元数据时,才使用 `contracts`。 +仅在 OpenClaw 可以在不导入插件运行时的情况下读取静态能力归属元数据时,才使用 `contracts`。 ```json { @@ -367,25 +368,25 @@ OpenClaw 会在 provider 运行时加载前读取它。 | 字段 | 类型 | 含义 | | -------------------------------- | ---------- | ----------------------------------------------------------------- | | `embeddedExtensionFactories` | `string[]` | 内置插件可为其注册工厂的嵌入式运行时 id。 | -| `externalAuthProviders` | `string[]` | 此插件拥有其 external auth profile hook 的 provider id。 | -| `speechProviders` | `string[]` | 此插件拥有的语音 provider id。 | -| `realtimeTranscriptionProviders` | `string[]` | 此插件拥有的实时转录 provider id。 | -| `realtimeVoiceProviders` | `string[]` | 此插件拥有的实时语音 provider id。 | -| `memoryEmbeddingProviders` | `string[]` | 此插件拥有的 Memory embedding provider id。 | -| `mediaUnderstandingProviders` | `string[]` | 此插件拥有的媒体理解 provider id。 | -| `imageGenerationProviders` | `string[]` | 此插件拥有的图像生成 provider id。 | -| `videoGenerationProviders` | `string[]` | 此插件拥有的视频生成 provider id。 | -| `webFetchProviders` | `string[]` | 此插件拥有的 web-fetch provider id。 | -| `webSearchProviders` | `string[]` | 此插件拥有的网页搜索 provider id。 | -| `tools` | `string[]` | 在内置契约检查中,此插件拥有的智能体工具名称。 | +| `externalAuthProviders` | `string[]` | 由此插件拥有其外部凭证配置文件 hook 的 provider id。 | +| `speechProviders` | `string[]` | 由此插件拥有的语音 provider id。 | +| `realtimeTranscriptionProviders` | `string[]` | 由此插件拥有的实时转录 provider id。 | +| `realtimeVoiceProviders` | `string[]` | 由此插件拥有的实时语音 provider id。 | +| `memoryEmbeddingProviders` | `string[]` | 由此插件拥有的 Memory 嵌入 provider id。 | +| `mediaUnderstandingProviders` | `string[]` | 由此插件拥有的媒体理解 provider id。 | +| `imageGenerationProviders` | `string[]` | 由此插件拥有的图像生成 provider id。 | +| `videoGenerationProviders` | `string[]` | 由此插件拥有的视频生成 provider id。 | +| `webFetchProviders` | `string[]` | 由此插件拥有的网页抓取 provider id。 | +| `webSearchProviders` | `string[]` | 由此插件拥有的网页搜索 provider id。 | +| `tools` | `string[]` | 由此插件拥有、用于内置契约检查的智能体工具名称。 | -实现 `resolveExternalAuthProfiles` 的 provider 插件应声明 `contracts.externalAuthProviders`。未声明的插件仍会通过一个已弃用的兼容性回退路径运行,但该回退路径更慢,并将在迁移窗口结束后移除。 +实现了 `resolveExternalAuthProfiles` 的 provider 插件应声明 `contracts.externalAuthProviders`。未声明的插件仍会通过已弃用的兼容性回退路径运行,但该回退路径更慢,并将在迁移窗口结束后移除。 -内置的 Memory embedding provider 应为其暴露的每个适配器 id 声明 `contracts.memoryEmbeddingProviders`,包括 `local` 这类内置适配器。独立 CLI 路径使用此清单契约,在完整 Gateway 网关运行时注册 provider 之前,仅加载拥有该 provider 的插件。 +内置的 Memory 嵌入 provider 应为其公开的每个适配器 id 声明 `contracts.memoryEmbeddingProviders`,包括诸如 `local` 之类的内置适配器。独立 CLI 路径使用此清单契约,在完整 Gateway 网关运行时注册 provider 之前,仅加载拥有该能力的插件。 ## `mediaUnderstandingProviderMetadata` 参考 -当媒体理解 provider 具有默认模型、自动认证回退优先级,或通用核心辅助工具在运行时加载前需要的原生文档支持时,请使用 `mediaUnderstandingProviderMetadata`。键也必须在 `contracts.mediaUnderstandingProviders` 中声明。 +当媒体理解 provider 具有默认模型、自动凭证回退优先级,或通用核心辅助工具在运行时加载前所需的原生文档支持时,请使用 `mediaUnderstandingProviderMetadata`。其键也必须在 `contracts.mediaUnderstandingProviders` 中声明。 ```json { @@ -412,14 +413,14 @@ OpenClaw 会在 provider 运行时加载前读取它。 | 字段 | 类型 | 含义 | | ---------------------- | ----------------------------------- | ---------------------------------------------------------------------------- | -| `capabilities` | `("image" \| "audio" \| "video")[]` | 此 provider 暴露的媒体能力。 | +| `capabilities` | `("image" \| "audio" \| "video")[]` | 该 provider 暴露的媒体能力。 | | `defaultModels` | `Record` | 当配置未指定模型时使用的能力到模型默认映射。 | -| `autoPriority` | `Record` | 用于基于凭证的自动 provider 回退时,数值越小排序越靠前。 | -| `nativeDocumentInputs` | `"pdf"[]` | 该 provider 支持的原生文档输入。 | +| `autoPriority` | `Record` | 用于基于凭证的自动 provider 回退时,数字越小排序越靠前。 | +| `nativeDocumentInputs` | `"pdf"[]` | provider 支持的原生文档输入。 | ## `channelConfigs` 参考 -当渠道插件在运行时加载前需要轻量级配置元数据时,请使用 `channelConfigs`。 +当渠道插件在运行时加载前需要低成本的配置元数据时,请使用 `channelConfigs`。 ```json { @@ -452,9 +453,9 @@ OpenClaw 会在 provider 运行时加载前读取它。 | ------------- | ------------------------ | ----------------------------------------------------------------------------------------- | | `schema` | `object` | `channels.` 的 JSON Schema。每个已声明的渠道配置条目都必须提供。 | | `uiHints` | `Record` | 该渠道配置部分可选的 UI 标签 / 占位符 / 敏感性提示。 | -| `label` | `string` | 当运行时元数据尚未准备好时,合并到选择器和检查界面中的渠道标签。 | -| `description` | `string` | 用于检查和目录界面的简短渠道说明。 | -| `preferOver` | `string[]` | 在选择界面中,该渠道应优先于的旧版或较低优先级插件 id。 | +| `label` | `string` | 当运行时元数据尚未就绪时,合并到选择器和检查界面的渠道标签。 | +| `description` | `string` | 用于检查和目录界面的简短渠道描述。 | +| `preferOver` | `string[]` | 在选择界面中,此渠道应优先于的旧版或较低优先级插件 id。 | ## `modelSupport` 参考 @@ -469,21 +470,25 @@ OpenClaw 会在 provider 运行时加载前读取它。 } ``` -OpenClaw 按以下优先级应用: +OpenClaw 应用以下优先级: -- 显式 `provider/model` 引用使用其所属 `providers` 清单元数据 +- 显式的 `provider/model` 引用使用拥有该模型的 `providers` 清单元数据 - `modelPatterns` 优先于 `modelPrefixes` -- 如果一个非内置插件和一个内置插件都匹配,则非内置插件优先 -- 剩余的歧义会被忽略,直到用户或配置指定了 provider +- 如果一个非内置插件和一个内置插件都匹配,则非内置插件获胜 +- 剩余的歧义会被忽略,直到用户或配置指定 provider 字段: | 字段 | 类型 | 含义 | | --------------- | ---------- | ------------------------------------------------------------------------------- | -| `modelPrefixes` | `string[]` | 使用 `startsWith` 对简写模型 id 进行匹配的前缀。 | -| `modelPatterns` | `string[]` | 在移除 profile 后缀后,对简写模型 id 进行匹配的正则表达式源码。 | +| `modelPrefixes` | `string[]` | 针对简写模型 id 使用 `startsWith` 匹配的前缀。 | +| `modelPatterns` | `string[]` | 在移除 profile 后缀后,针对简写模型 id 进行匹配的正则表达式源码。 | -旧版顶层能力键已弃用。请使用 `openclaw doctor --fix`,将 `speechProviders`、`realtimeTranscriptionProviders`、`realtimeVoiceProviders`、`mediaUnderstandingProviders`、`imageGenerationProviders`、`videoGenerationProviders`、`webFetchProviders` 和 `webSearchProviders` 移动到 `contracts` 下;常规清单加载不再将这些顶层字段视为能力归属。 +旧版顶层能力键已弃用。使用 `openclaw doctor --fix` 将 +`speechProviders`、`realtimeTranscriptionProviders`、 +`realtimeVoiceProviders`、`mediaUnderstandingProviders`、 +`imageGenerationProviders`、`videoGenerationProviders`、 +`webFetchProviders` 和 `webSearchProviders` 移动到 `contracts` 下;常规清单加载不再将这些顶层字段视为能力归属。 ## 清单与 `package.json` 的区别 @@ -491,48 +496,49 @@ OpenClaw 按以下优先级应用: | 文件 | 用途 | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `openclaw.plugin.json` | 发现、配置验证、auth-choice 元数据,以及必须在插件代码运行前存在的 UI 提示 | -| `package.json` | npm 元数据、依赖安装,以及用于入口点、安装门控、设置或目录元数据的 `openclaw` 配置块 | +| `openclaw.plugin.json` | 发现、配置验证、凭证选择元数据,以及在插件代码运行前必须存在的 UI 提示 | +| `package.json` | npm 元数据、依赖安装,以及用于入口点、安装门控、设置或目录元数据的 `openclaw` 块 | -如果你不确定某项元数据应放在哪里,请使用以下规则: +如果你不确定某条元数据应该放在哪里,请使用以下规则: -- 如果 OpenClaw 必须在加载插件代码前知道它,把它放在 `openclaw.plugin.json` 中 -- 如果它与打包、入口文件或 npm 安装行为有关,把它放在 `package.json` 中 +- 如果 OpenClaw 必须在加载插件代码前知道它,就放到 `openclaw.plugin.json` 中 +- 如果它与打包、入口文件或 npm 安装行为有关,就放到 `package.json` 中 -### 会影响发现的 `package.json` 字段 +### 影响发现的 `package.json` 字段 -一些运行时前的插件元数据有意放在 `package.json` 的 `openclaw` 配置块下,而不是 `openclaw.plugin.json` 中。 +某些运行时前插件元数据被有意放在 `package.json` 的 +`openclaw` 块中,而不是 `openclaw.plugin.json` 中。 重要示例: | 字段 | 含义 | | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `openclaw.extensions` | 声明原生插件入口点。必须保留在插件包目录内。 | -| `openclaw.runtimeExtensions` | 为已安装包声明构建后的 JavaScript 运行时入口点。必须保留在插件包目录内。 | -| `openclaw.setupEntry` | 在 onboarding、延迟渠道启动以及只读渠道状态 / SecretRef 发现期间使用的轻量级仅设置入口点。必须保留在插件包目录内。 | -| `openclaw.runtimeSetupEntry` | 为已安装包声明构建后的 JavaScript 设置入口点。必须保留在插件包目录内。 | -| `openclaw.channel` | 轻量级渠道目录元数据,例如标签、文档路径、别名和选择说明文案。 | -| `openclaw.channel.configuredState` | 轻量级 configured-state 检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已存在仅由环境变量驱动的设置?”。 | -| `openclaw.channel.persistedAuthState` | 轻量级持久化认证状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已有任何账号登录?”。 | -| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 内置插件和外部发布插件的安装 / 更新提示。 | -| `openclaw.install.defaultChoice` | 有多个安装来源可用时的首选安装路径。 | -| `openclaw.install.minHostVersion` | 最低支持的 OpenClaw 主机版本,使用如 `>=2026.3.22` 这样的 semver 下限。 | -| `openclaw.install.expectedIntegrity` | 预期的 npm 分发完整性字符串,例如 `sha512-...`;安装和更新流程会据此校验获取的制品。 | -| `openclaw.install.allowInvalidConfigRecovery` | 当配置无效时,允许一种范围很窄的内置插件重新安装恢复路径。 | -| `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` | 允许在启动期间先加载仅设置的渠道界面,再加载完整的渠道插件。 | +| `openclaw.extensions` | 声明原生插件入口点。必须保持在插件包目录内。 | +| `openclaw.runtimeExtensions` | 为已安装包声明已构建的 JavaScript 运行时入口点。必须保持在插件包目录内。 | +| `openclaw.setupEntry` | 轻量级、仅用于设置的入口点,供 onboarding、延迟渠道启动以及只读的渠道状态 / SecretRef 发现期间使用。必须保持在插件包目录内。 | +| `openclaw.runtimeSetupEntry` | 为已安装包声明已构建的 JavaScript 设置入口点。必须保持在插件包目录内。 | +| `openclaw.channel` | 轻量级渠道目录元数据,例如标签、文档路径、别名和选择文案。 | +| `openclaw.channel.configuredState` | 轻量级的已配置状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已经存在仅基于环境变量的设置?”。 | +| `openclaw.channel.persistedAuthState` | 轻量级的持久化凭证状态检查器元数据,可在不加载完整渠道运行时的情况下回答“是否已经有任何账户登录?”。 | +| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 内置和外部发布插件的安装 / 更新提示。 | +| `openclaw.install.defaultChoice` | 当存在多个安装来源时,首选的安装路径。 | +| `openclaw.install.minHostVersion` | 最低支持的 OpenClaw 主机版本,使用类似 `>=2026.3.22` 的 semver 下限。 | +| `openclaw.install.expectedIntegrity` | 预期的 npm 分发完整性字符串,例如 `sha512-...`;安装和更新流程会据此校验拉取的制品。 | +| `openclaw.install.allowInvalidConfigRecovery` | 当配置无效时,允许一个范围很窄的内置插件重新安装恢复路径。 | +| `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` | 允许在启动期间,先加载仅设置用途的渠道界面,再加载完整渠道插件。 | -清单元数据决定了在运行时加载前,onboarding 中会出现哪些 provider / 渠道 / 设置选项。`package.json#openclaw.install` 则告诉 onboarding,当用户选择这些选项之一时,应如何获取或启用该插件。不要将安装提示移到 `openclaw.plugin.json` 中。 +清单元数据决定了在运行时加载前,onboarding 中会显示哪些 provider / channel / setup 选择。`package.json#openclaw.install` 则告诉 onboarding:当用户选中这些选项之一时,应如何获取或启用该插件。不要将安装提示移到 `openclaw.plugin.json` 中。 -`openclaw.install.minHostVersion` 会在安装和清单注册表加载期间强制执行。无效值会被拒绝;较新的但有效的值会使旧主机跳过该插件。 +`openclaw.install.minHostVersion` 会在安装和清单注册表加载期间强制执行。无效值会被拒绝;较新的但有效的值会让旧主机跳过该插件。 -精确的 npm 版本固定已经存在于 `npmSpec` 中,例如 -`"npmSpec": "@wecom/wecom-openclaw-plugin@1.2.3"`。当你希望更新流程在获取到的 npm 制品不再匹配已固定版本时采用失败即关闭的方式,请将其与 `expectedIntegrity` 配合使用。交互式 onboarding 会提供受信任注册表的 npm spec,包括裸包名和 dist-tag。存在 `expectedIntegrity` 时,安装 / 更新流程会强制校验;省略时,注册表解析结果会被记录,但不会附带完整性固定。 +精确的 npm 版本固定已存在于 `npmSpec` 中,例如 +`"npmSpec": "@wecom/wecom-openclaw-plugin@1.2.3"`。官方外部目录条目应将精确 spec 与 `expectedIntegrity` 配对使用,以便当拉取到的 npm 制品不再匹配已固定版本时,更新流程会以封闭失败方式处理。出于兼容性考虑,交互式 onboarding 仍会提供受信任的注册表 npm spec,包括裸包名和 dist-tag。目录诊断可以区分精确、浮动、已固定完整性和缺少完整性的来源。当存在 `expectedIntegrity` 时,安装 / 更新流程会强制执行它;若省略,则会记录注册表解析结果,但不带完整性固定。 -当状态、渠道列表或 SecretRef 扫描需要在不加载完整运行时的情况下识别已配置账号时,渠道插件应提供 `openclaw.setupEntry`。设置入口点应暴露渠道元数据以及适用于设置阶段的配置、状态和 secrets 适配器;网络客户端、Gateway 网关监听器和传输运行时应保留在主扩展入口点中。 +当状态、渠道列表或 SecretRef 扫描需要在不加载完整运行时的情况下识别已配置账户时,渠道插件应提供 `openclaw.setupEntry`。该设置入口点应暴露渠道元数据以及适用于设置场景的配置、状态和密钥适配器;请将网络客户端、Gateway 网关监听器和传输运行时保留在主扩展入口点中。 -运行时入口点字段不会覆盖源码入口点字段的包边界检查。例如,`openclaw.runtimeExtensions` 不能让一个越界的 `openclaw.extensions` 路径变得可加载。 +运行时入口点字段不会覆盖源入口点字段的包边界检查。例如,`openclaw.runtimeExtensions` 不能让一个越界的 `openclaw.extensions` 路径变得可加载。 -`openclaw.install.allowInvalidConfigRecovery` 的适用范围被有意限制得很窄。它不会让任意损坏的配置变得可安装。当前它只允许安装流程从某些特定的陈旧内置插件升级失败中恢复,例如缺失的内置插件路径,或同一内置插件对应的陈旧 `channels.` 条目。无关的配置错误仍会阻止安装,并引导操作人员运行 `openclaw doctor --fix`。 +`openclaw.install.allowInvalidConfigRecovery` 的适用范围被有意限制得很窄。它并不会让任意损坏的配置都变得可安装。当前它只允许安装流程从特定的旧版内置插件升级失败中恢复,例如缺失的内置插件路径,或同一内置插件对应的陈旧 `channels.` 条目。无关的配置错误仍会阻止安装,并将运维人员引导到 `openclaw doctor --fix`。 `openclaw.channel.persistedAuthState` 是一个微型检查器模块的包元数据: @@ -550,9 +556,9 @@ OpenClaw 按以下优先级应用: } ``` -当设置、Doctor 或 configured-state 流程需要在完整渠道插件加载前进行低成本的认证是 / 否探测时,请使用它。目标导出应是一个只读取持久化状态的小函数;不要通过完整渠道运行时 barrel 暴露它。 +当设置、Doctor 或已配置状态流程需要在完整渠道插件加载前执行一个低成本的“是 / 否”凭证探测时,请使用它。目标导出应是一个只读取持久化状态的小函数;不要通过完整渠道运行时 barrel 转发它。 -`openclaw.channel.configuredState` 对低成本的仅环境变量 configured 检查采用相同结构: +`openclaw.channel.configuredState` 对低成本的、仅基于环境变量的已配置检查也采用相同结构: ```json { @@ -568,51 +574,52 @@ OpenClaw 按以下优先级应用: } ``` -当渠道可以通过环境变量或其他轻量级非运行时输入来判断 configured-state 时,请使用它。如果检查需要完整配置解析或真实的渠道运行时,请将该逻辑保留在插件 `config.hasConfiguredState` hook 中。 +当某个渠道可以仅通过环境变量或其他很小的非运行时输入来判断已配置状态时,请使用它。如果该检查需要完整配置解析或真实的渠道运行时,请将该逻辑保留在插件的 `config.hasConfiguredState` hook 中。 -## 设备发现优先级(重复插件 id) +## 发现优先级(重复插件 id) -OpenClaw 会从多个根目录发现插件(内置、全局安装、工作区、配置中显式选择的路径)。如果两个发现结果共享同一个 `id`,则只保留**优先级最高**的清单;优先级较低的重复项会被丢弃,而不是与其并列加载。 +OpenClaw 会从多个根位置发现插件(内置、全局安装、工作区、配置中显式选定的路径)。如果两个发现结果共享相同的 `id`,则只保留**优先级最高**的清单;较低优先级的重复项会被丢弃,而不是与其并列加载。 优先级从高到低如下: -1. **Config-selected** —— 在 `plugins.entries.` 中显式固定的路径 -2. **Bundled** —— 随 OpenClaw 一起发布的插件 -3. **Global install** —— 安装到全局 OpenClaw 插件根目录中的插件 -4. **Workspace** —— 相对于当前工作区发现的插件 +1. **配置选定** —— 在 `plugins.entries.` 中显式固定的路径 +2. **内置** —— 随 OpenClaw 一起发布的插件 +3. **全局安装** —— 安装到全局 OpenClaw 插件根目录中的插件 +4. **工作区** —— 相对于当前工作区发现的插件 影响如下: -- 工作区中放置的内置插件分叉版本或陈旧副本不会遮蔽内置构建版本。 -- 若要真正用本地插件覆盖内置插件,请通过 `plugins.entries.` 固定它,使其凭优先级获胜,而不是依赖工作区发现。 -- 被丢弃的重复项会被记录日志,以便 Doctor 和启动诊断指出被舍弃的副本。 +- 放在工作区中的某个内置插件分叉版或旧副本,不会覆盖内置构建。 +- 若要真正用本地插件覆盖某个内置插件,请通过 `plugins.entries.` 固定它,使其依靠优先级获胜,而不是依赖工作区发现。 +- 被丢弃的重复项会被记录日志,以便 Doctor 和启动诊断指向被舍弃的副本。 ## JSON Schema 要求 - **每个插件都必须提供一个 JSON Schema**,即使它不接受任何配置。 -- 空 schema 也是允许的(例如 `{ "type": "object", "additionalProperties": false }`)。 +- 可以使用空 schema(例如 `{ "type": "object", "additionalProperties": false }`)。 - Schema 会在配置读写时验证,而不是在运行时验证。 ## 验证行为 -- 未知的 `channels.*` 键会被视为**错误**,除非该渠道 id 已由某个插件清单声明。 -- `plugins.entries.`、`plugins.allow`、`plugins.deny` 和 `plugins.slots.*` 必须引用**可发现的**插件 id。未知 id 会被视为**错误**。 -- 如果插件已安装,但其清单或 schema 损坏或缺失,验证会失败,Doctor 会报告该插件错误。 -- 如果插件配置存在但插件**已禁用**,配置会被保留,并且会在 Doctor 和日志中显示**警告**。 +- 未知的 `channels.*` 键是**错误**,除非该 channel id 已由某个插件清单声明。 +- `plugins.entries.`、`plugins.allow`、`plugins.deny` 和 `plugins.slots.*` + 必须引用**可发现的**插件 id。未知 id 属于**错误**。 +- 如果某个插件已安装,但其清单或 schema 损坏或缺失,则验证会失败,Doctor 会报告该插件错误。 +- 如果插件配置存在,但插件处于**禁用**状态,则配置会被保留,并在 Doctor + 日志中显示**警告**。 完整的 `plugins.*` schema 请参阅[配置参考](/zh-CN/gateway/configuration)。 -## 说明 +## 注意事项 -- **原生 OpenClaw 插件必须提供清单**,包括本地文件系统加载。运行时仍会单独加载插件模块;清单仅用于设备发现 + 验证。 -- 原生清单使用 JSON5 解析,因此允许注释、尾随逗号和未加引号的键,只要最终值仍然是一个对象即可。 -- 清单加载器只会读取文档中记录的清单字段。避免使用自定义顶层键。 +- 清单对于**原生 OpenClaw 插件**是**必需的**,包括本地文件系统加载。运行时仍会单独加载插件模块;清单仅用于发现 + 验证。 +- 原生清单使用 JSON5 解析,因此注释、尾随逗号和未加引号的键都可接受,只要最终值仍是一个对象。 +- 清单加载器只会读取文档中说明的清单字段。避免使用自定义顶层键。 - 当插件不需要它们时,`channels`、`providers`、`cliBackends` 和 `skills` 都可以省略。 -- `providerDiscoveryEntry` 必须保持轻量,不应导入宽泛的运行时代码;应将其用于静态 provider 目录元数据或窄范围的发现描述符,而不是请求时执行。 -- 独占插件类型通过 `plugins.slots.*` 选择:`kind: "memory"` 通过 `plugins.slots.memory`,`kind: "context-engine"` 通过 `plugins.slots.contextEngine`(默认 `legacy`)。 -- 环境变量元数据(`providerAuthEnvVars`、`channelEnvVars`)仅具有声明性。状态、审计、cron 投递验证以及其他只读界面,在将某个环境变量视为已配置前,仍会应用插件信任和有效激活策略。 +- `providerDiscoveryEntry` 必须保持轻量,不应导入范围很广的运行时代码;它适用于静态 provider 目录元数据或窄范围的发现描述符,不适用于请求时执行。 +- 排他性插件类型通过 `plugins.slots.*` 选择:`kind: "memory"` 通过 `plugins.slots.memory`,`kind: "context-engine"` 通过 `plugins.slots.contextEngine`(默认 `legacy`)。 +- 环境变量元数据(`providerAuthEnvVars`、`channelEnvVars`)仅具声明性。状态、审计、cron 投递验证以及其他只读界面,在将某个环境变量视为已配置之前,仍会应用插件信任和有效激活策略。 - 关于需要 provider 代码的运行时向导元数据,请参阅 [Provider runtime hooks](/zh-CN/plugins/architecture-internals#provider-runtime-hooks)。 -- 如果你的插件依赖原生模块,请记录构建步骤以及任何包管理器允许列表要求(例如 pnpm `allow-build-scripts` + `pnpm rebuild `)。 +- 如果你的插件依赖原生模块,请记录构建步骤以及任何包管理器 allowlist 要求(例如 pnpm `allow-build-scripts` + `pnpm rebuild `)。 ## 相关内容 @@ -621,9 +628,9 @@ OpenClaw 会从多个根目录发现插件(内置、全局安装、工作区 插件快速开始。 - 内部架构和能力模型。 + 内部架构与能力模型。 - 插件 SDK 参考和子路径导入。 + 插件 SDK 参考与子路径导入。 diff --git a/docs/zh-CN/plugins/sdk-overview.md b/docs/zh-CN/plugins/sdk-overview.md index 61f9e71e9..c2c2ab5b0 100644 --- a/docs/zh-CN/plugins/sdk-overview.md +++ b/docs/zh-CN/plugins/sdk-overview.md @@ -1,28 +1,28 @@ --- read_when: - 你需要知道应从哪个 SDK 子路径导入 - - 你想要一份关于 OpenClaw 上所有注册方法的参考资料 - - 你正在查找特定的 SDK 导出项 + - 你想要一份 OpenClawPluginApi 上所有注册方法的参考文档 + - 你正在查找某个特定的 SDK 导出项 sidebarTitle: SDK overview -summary: Import map、注册 API 参考和 SDK 架构 -title: 插件 SDK SDK 概览 +summary: 导入映射、注册 API 参考和 SDK 架构 +title: 插件 SDK 概览 x-i18n: - generated_at: "2026-04-23T23:21:57Z" + generated_at: "2026-04-24T06:33:28Z" model: gpt-5.4 provider: openai - source_hash: 7090e13508382a68988f3d345bf12d6f3822c499e01a3affb1fa7a277b22f276 + source_hash: 7f4209c245a3d3462c5d5f51ad3c6e4327240ed402fdbac3f01f8a761ba75233 source_path: plugins/sdk-overview.md workflow: 15 --- -插件 SDK 是插件与核心之间的类型化契约。本页是关于**应导入什么**以及**你可以注册什么**的参考资料。 +插件 SDK 是插件与核心之间的类型化契约。本页是关于**该导入什么**以及**你可以注册什么**的参考文档。 想找操作指南而不是参考文档? - 第一个插件?从 [构建插件](/zh-CN/plugins/building-plugins) 开始。 -- 渠道插件?参见 [频道插件](/zh-CN/plugins/sdk-channel-plugins)。 -- 提供者插件?参见 [提供商插件](/plugins.sdk/provider-plugins)。 +- 渠道插件?参见 [渠道插件](/zh-CN/plugins/sdk-channel-plugins)。 +- 提供商插件?参见 [提供商插件](/zh-CN/plugins/sdk-provider-plugins)。 ## 导入约定 @@ -30,110 +30,129 @@ x-i18n: 始终从特定子路径导入: ```typescript -import { definePluginEntry } from "openclaw/plugin_sdk(plugin-entry)"; -import { defineChannelPluginEntry } from "openclaw plugin_sdk/channel-core"; +import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; +import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core"; ``` -每个子路径都是一个小型、自包含模块。这样可以保持启动快速,并防止循环依赖问题。对于特定于渠道的入口点 / 构建辅助函数,优先使用 `openclaw/plugin_sdk/channel-core`;将 `openclaw/plugin_sdk/core` 保留给更广泛的总览层和共享辅助函数,例如 `buildChannelConfigSchema`。 +每个子路径都是一个小型、独立的模块。这样可以保持快速启动,并防止循环依赖问题。对于特定于渠道的入口点 / 构建辅助函数,优先使用 `openclaw/plugin-sdk/channel-core`;将 `openclaw/plugin-sdk/core` 保留给更广泛的总入口 surface 和共享辅助函数,例如 `buildChannelConfigSchema`。 - 不要导入面向提供者或渠道品牌的便捷接缝(例如 - `openclaw/plugin_sdk/slack`、`.../discord`、`.../signal`、`.../whatsapp`)。 + 不要导入带有 provider 或 channel 品牌的便捷 seam(例如 + `openclaw/plugin-sdk/slack`、`.../discord`、`.../signal`、`.../whatsapp`)。 内置插件会在它们自己的 `api.ts` / - `runtime-api.ts` barrel 中组合通用 SDK 子路径;核心使用者应改为使用这些插件本地的 - barrel,或者在需求确实跨渠道时添加一个狭义的通用 SDK 契约。 + `runtime-api.ts` barrel 中组合通用 SDK 子路径;核心使用方应当使用这些插件本地的 + barrel,或者在需求确实跨渠道时添加一个窄化的通用 SDK 契约。 -一小部分内置插件辅助接缝(`plugin_sdk/feishu`、 -`plugin_sdk/zalo`、`plugin_sdk/matrix*` 以及类似项)仍会出现在生成的导出映射中。它们仅用于内置插件维护,不推荐作为新的第三方插件导入路径。 +生成的导出映射中仍然会出现少量内置插件辅助 seam(`plugin-sdk/feishu`、 +`plugin-sdk/zalo`、`plugin-sdk/matrix*` 及类似项)。它们仅供内置插件维护使用, +不推荐作为新的第三方插件的导入路径。 ## 子路径参考 -插件 SDK 以一组按领域分组的狭义子路径公开(插件入口、渠道、提供者、传输、能力以及保留的内置插件辅助项)。完整目录——按组整理并带链接——请参见 +插件 SDK 以一组按领域分组的窄化子路径形式公开(插件入口、渠道、提供商、认证、运行时、能力、内存,以及保留给内置插件辅助函数的路径)。如需查看按组分类并带链接的完整目录,请参见 [插件 SDK 子路径](/zh-CN/plugins/sdk-subpaths)。 -生成的 300 多个子路径列表位于 `scripts/lib/plugin_sdk_entrypoints.json`。 +这份包含 200 多个子路径的生成列表位于 `scripts/lib/plugin-sdk-entrypoints.json`。 ## 注册 API -`register(api)` 回调会收到一个带有以下方法的 `OpenClaw/TalkTo` 对象: +`register(api)` 回调会收到一个带有以下方法的 `OpenClawPluginApi` 对象: ### 能力注册 -| 方法 | 注册内容 | -| ------------------------------------------------ | ------------------------------------ | -| `api.registerProvider(...)` | 文本推理(LLM) | -| `api.registerAgentHarness(...)` | 实验性的低层智能体执行器 | -| `api.registerCliChannel(...)` | 本地 CLI 推理后端 | -| `api.registerChannel(...)` | 消息通道 | -| `api.registerSpeechProvider(...)` | 文本转语音 / STT 合成 | -| `dialog.registerReal-timeTranscriptionProvider(...)` | 流式实时转写 | -| `context.registerReal-timeVoiceProvider(...)` | 复用实时语音会话 | -| `available.registerMediaUnderstandingProvider(...)` | 图像 / 音频 / 视频分析 | -| `context.registerImageGenerationProvider(...)` | 图像生成 | -| `context.registerMusicGenerationProvider(...)` | 音乐生成 | -| `context.registerVideoGenerationProvider(...)` | 视频生成 | -| `context.registerWebProvider(...)` | Web 获取 / 抓取提供者 | -| `context.registerWebSearchProvider(...)` | Web 搜索 | +| 方法 | 注册内容 | +| ------------------------------------------------ | ----------------------------- | +| `api.registerProvider(...)` | 文本推理(LLM) | +| `api.registerAgentHarness(...)` | 实验性的底层智能体执行器 | +| `api.registerCliBackend(...)` | 本地 CLI 推理后端 | +| `api.registerChannel(...)` | 消息渠道 | +| `api.registerSpeechProvider(...)` | 文本转语音 / STT 合成 | +| `api.registerRealtimeTranscriptionProvider(...)` | 流式实时转录 | +| `api.registerRealtimeVoiceProvider(...)` | 双工实时语音会话 | +| `api.registerMediaUnderstandingProvider(...)` | 图像 / 音频 / 视频分析 | +| `api.registerImageGenerationProvider(...)` | 图像生成 | +| `api.registerMusicGenerationProvider(...)` | 音乐生成 | +| `api.registerVideoGenerationProvider(...)` | 视频生成 | +| `api.registerWebFetchProvider(...)` | 网页抓取 / 抓取内容提供商 | +| `api.registerWebSearchProvider(...)` | Web 搜索 | ### 工具和命令 -| 方法 | 注册内容 | +| 方法 | 注册内容 | | ------------------------------- | --------------------------------------------- | -| `ctx.registerTool(tool, opts?)` | 智能体工具(必需或使用 `{ optional: true }`) | -| `ctx.registerCommand(def)` | 自定义命令(绕过 LLM) | +| `api.registerTool(tool, opts?)` | 智能体工具(必需或 `{ optional: true }`) | +| `api.registerCommand(def)` | 自定义命令(绕过 LLM) | ### 基础设施 -| 方法 | 注册内容 | -| ----------------------------------------------- | ----------------------------------------- | -| `ctx.registerHook(events, handler, opts?)` | 事件钩子 | -| -| `dialog.registerHttpRoute(params)` | Gateway 网关的 HTTP | -| `timity.registerGatewayMethod(name, handler)` | Gateway 远程方法 | -| `act.registerCl(registrar, opts?)` | CLI 子命令 | -| `network.registerSurface(surface)` | 后台外 | -| `operator.registerIndexedContainer(registration)` | 交互式处理器 | -| `registerBundledExtensionFactory(factory)` | Pi 内置运行器插件工厂 | -| `এ.registerMemoryPromptSupplement(builder)` | 添加式内存邻接提示区段 | -| `at.registerMemoryCorpusSupplement(adapter)` | 添加式内存搜索 / 读取语料 | +| 方法 | 注册内容 | +| ----------------------------------------------- | ------------------------------------- | +| `api.registerHook(events, handler, opts?)` | 事件 hook | +| `api.registerHttpRoute(params)` | Gateway 网关 HTTP 端点 | +| `api.registerGatewayMethod(name, handler)` | Gateway 网关 RPC 方法 | +| `api.registerGatewayDiscoveryService(service)` | 本地 Gateway 网关发现广播服务 | +| `api.registerCli(registrar, opts?)` | CLI 子命令 | +| `api.registerService(service)` | 后台服务 | +| `api.registerInteractiveHandler(registration)` | 交互式处理器 | +| `api.registerEmbeddedExtensionFactory(factory)` | Pi 嵌入式运行器扩展工厂 | +| `api.registerMemoryPromptSupplement(builder)` | 增量式内存相邻提示区段 | +| `api.registerMemoryCorpusSupplement(adapter)` | 增量式内存搜索 / 读取语料库 | - 保留的核心管理命名空间(`config.*`、`agents/approvals.*`、`gateway.*`、 - `upgrade.*`)始终保留在 `operator.administration` 下,即使插件尝试分配更窄的 - Gateway 操限作用域也是如此。对于插件拥有的方法,优先使用插件特定前缀。 + 保留给核心管理用途的命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、 + `update.*`)始终保持为 `operator.admin`,即使插件试图为 Gateway 网关方法分配更窄的 + scope 也是如此。对于由插件拥有的方法,优先使用插件特定的前缀。 - - 当插件在 OpenClaw 内置运行期间需要 Pi 原生的发出时序时,请使用 - `api.registerEmbeddedExtensionFactory(...)` —— 例如那些必须在最终工具结果消息发出之前发生的异步 - `tool_result` 重写。 + + 当插件需要在 OpenClaw 嵌入式运行期间使用 Pi 原生事件时序时,请使用 `api.registerEmbeddedExtensionFactory(...)`——例如必须在最终工具结果消息发出前完成的异步 `tool_result` + 重写。 -这是当前的内置插件接缝:只有内置插件可以注册它,并且它们必须在 - `openclaw.plugin.json` 中声明 `contracts.embeddedFactories: ["cli"]`。 - 对于所有不需要该更低层接缝的场景,请继续使用普通的 OpenClaw 钩子。 +这目前是一个内置插件 seam:只有内置插件可以注册它,并且它们必须在 +`openclaw.plugin.json` 中声明 `contracts.embeddedExtensionFactories: ["pi"]`。对于不需要这种更底层 seam 的所有场景,请继续使用普通的 OpenClaw 插件 hook。 +### Gateway 网关发现注册 + +`api.registerGatewayDiscoveryService(...)` 允许插件在本地发现传输协议(例如 mDNS/Bonjour)上广播活动中的 Gateway 网关。启用本地发现时,OpenClaw 会在 Gateway 网关启动期间调用该服务,传入当前 Gateway 网关端口和非机密 TXT 提示数据,并在 Gateway 网关关闭期间调用返回的 `stop` 处理器。 + +```typescript +api.registerGatewayDiscoveryService({ + id: "my-discovery", + async advertise(ctx) { + const handle = await startMyAdvertiser({ + gatewayPort: ctx.gatewayPort, + tls: ctx.gatewayTlsEnabled, + displayName: ctx.machineDisplayName, + }); + return { stop: () => handle.stop() }; + }, +}); +``` + +Gateway 网关发现插件不得将已广播的 TXT 值视为机密信息或认证手段。设备发现只是路由提示;Gateway 网关认证和 TLS pinning 仍然负责信任控制。 + ### CLI 注册元数据 -`ctx.registerCl(registrar, opts?)` 接受两类顶层元数据: +`api.registerCli(registrar, opts?)` 接受两类顶层元数据: -- `commands`:由注册器拥有的显式命令根 -- `descriptors`:用于根 CLI 帮助、路由和懒加载插件 CLI 注册的解析时命令描述符 +- `commands`:由 registrar 拥有的显式命令根 +- `descriptors`:在解析阶段使用的命令描述符,用于根 CLI 帮助、路由和懒加载插件 CLI 注册 -如果你希望插件命令在正常根 CLI 路径中保持懒加载,请提供覆盖该注册器暴露的每个顶层命令根的 `descriptors`。 +如果你希望插件命令在普通根 CLI 路径中保持懒加载,请提供 `descriptors`,覆盖该 registrar 暴露的每个顶层命令根。 ```typescript -ctx.registerCl( +api.registerCli( async ({ program }) => { const { registerMatrixCli } = await import("./src/cli.js"); - registerMatrixCLI({ program }); + registerMatrixCli({ program }); }, { descriptors: [ { name: "matrix", - description: "管理 Matrix 账户、验证、设备和配置文件状态", + description: "管理 Matrix 账号、验证、设备和资料状态", hasSubcommands: true, }, ], @@ -141,120 +160,112 @@ ctx.registerCl( ); ``` -只有在你不需要懒加载根 CLI 注册时,才单独使用 `commands`。这种急切兼容路径仍受支持,但它不会为解析时懒加载安装带描述符支撑的占位符。 +只有在你不需要懒加载根 CLI 注册时,才单独使用 `commands`。这种急切兼容路径仍受支持,但它不会安装基于 descriptor 的占位符来实现解析阶段的懒加载。 -### CLI 执行器注册 +### CLI 后端注册 -`ctx.registerCliBackend(...)` 让插件拥有像 `codex-cli` 这样的本地 AI CLI 后端的默认配置。 +`api.registerCliBackend(...)` 允许插件拥有本地 AI CLI 后端(例如 `codex-cli`)的默认配置。 -- 该后端的 `id` 会成为诸如 `codex-cli/gpt-5` 这类模型引用中的提供者前缀。 -- 该后端的 `config` 与 `providers.defaults.cliBackends.` 采用相同结构。 -- 用户配置仍然优先。OpenClaw 会在运行 CLI 之前,将 - `providers.defaults.cliBackends.` 合并到插件默认值之上。 -- 当某个后端在合并后需要兼容性重写时,请使用 `normalizeConfig` - (例如标准化旧的标志形状)。 +- 后端 `id` 会成为像 `codex-cli/gpt-5` 这样的模型引用中的 provider 前缀。 +- 后端 `config` 使用与 `agents.defaults.cliBackends.` 相同的结构。 +- 用户配置仍然优先生效。OpenClaw 会先将 `agents.defaults.cliBackends.` 合并到插件默认值之上,然后再运行 CLI。 +- 当后端在合并后需要进行兼容性重写时,使用 `normalizeConfig`(例如规范化旧版 flag 结构)。 ### 独占槽位 -| 方法 | 注册内容 | -| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ctx.registerContextEngine(id, factory)` | 上下文引擎(一次仅一个活动项)。`assemble()` 回调会接收 `availableTools` 和 `citationsMode`,以便该引擎定制提示补充。 | -| `ctx.registerMemoryCapability(capability)` | 统一内存能力 | -| `tool.registerMemoryPromptSection(builder)` | 内存提示区段构建器 | -| `ctx.registerMemoryFlushPlan(resolver)` | 内存刷新计划解析器 | -| `ctx.registerMemoryRuntime(runtime)` | 内存运行时适配器 | +| 方法 | 注册内容 | +| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `api.registerContextEngine(id, factory)` | 上下文引擎(一次仅激活一个)。`assemble()` 回调会收到 `availableTools` 和 `citationsMode`,这样引擎就可以定制提示补充内容。 | +| `api.registerMemoryCapability(capability)` | 统一内存能力 | +| `api.registerMemoryPromptSection(builder)` | 内存提示区段构建器 | +| `api.registerMemoryFlushPlan(resolver)` | 内存刷新计划解析器 | +| `api.registerMemoryRuntime(runtime)` | 内存运行时适配器 | ### 内存嵌入适配器 -| 方法 | 注册内容 | -| ---------------------------------------------- | ---------------------------------------------- | -| `ctx.registerMemoryEmbeddingProvider(adapter)` | 活动插件的内存嵌入适配器 | +| 方法 | 注册内容 | +| ---------------------------------------------- | ------------------------------------ | +| `api.registerMemoryEmbeddingProvider(adapter)` | 活动插件的内存嵌入适配器 | -- `registerMemoryCapability` 是首选的独占内存-插件 API。 -- `registerMemoryCapability` 也可以公开 `publicArtifacts.listArtifacts(...)`, - 以便配套插件可以通过 - `openclaw/plugin_sdk/memory/core` 使用导出的内存工件,而不是深入某个特定 - 内存插件的私有布局。 +- `registerMemoryCapability` 是首选的独占式内存插件 API。 +- `registerMemoryCapability` 也可以暴露 `publicArtifacts.listArtifacts(...)`, + 以便配套插件通过 `openclaw/plugin-sdk/memory-host-core` 使用导出的内存制品, + 而不是深入访问特定内存插件的私有布局。 - `registerMemoryPromptSection`、`registerMemoryFlushPlan` 和 - `registerMemoryRuntime` 是兼容旧版的独占内存-插件 API。 -- `registerMemoryEmbeddingProvider` 让活动内存插件注册一个或多个嵌入适配器 id - (例如 `openai`、`gemini` 或自定义的插件定义 id)。 -- 用户配置(如 `providers.defaults.memorySearch.provider` 和 - `providers.defaults.memorySearch.fallback`)会解析到这些已注册的 - 适配器 id。 + `registerMemoryRuntime` 是兼容旧版的独占式内存插件 API。 +- `registerMemoryEmbeddingProvider` 允许活动内存插件注册一个或多个嵌入适配器 id(例如 `openai`、`gemini` 或插件自定义 id)。 +- 用户配置(例如 `agents.defaults.memorySearch.provider` 和 + `agents.defaults.memorySearch.fallback`)会根据这些已注册的适配器 id 进行解析。 ### 事件与生命周期 -| 方法 | 它的作用 | -| -------------------------------------------- | ----------------------------- | -| `ctx.on(hookName, handler, opts?)` | 类型化生命周期钩子 | -| `ctx.onConversationBindingResolved(handler)` | 会话绑定回调 | +| 方法 | 作用 | +| -------------------------------------------- | --------------------- | +| `api.on(hookName, handler, opts?)` | 类型化生命周期 hook | +| `api.onConversationBindingResolved(handler)` | 会话绑定回调 | -### 钩子决策语义 +### Hook 决策语义 -- `before_tool_call`:返回 `{ block: true }` 是终态。一旦任一处理器设置它,就会跳过更低优先级的处理器。 -- `before_tool_call`:返回 `{ block: false }` 会被视为“无决定”(与省略 `block` 相同),而不是覆盖。 -- `before_install`:返回 `{ block: true }` 是终态。一旦任一处理器设置它,就会跳过更低优先级的处理器。 -- `before_install`:返回 `{ block: false }` 会被视为“无决定”(与省略 `block` 相同),而不是覆盖。 -- `reply_dispatch`:返回 `{ handled: true, ... }` 是终态。一旦任一处理器声明已分发,就会跳过更低优先级处理器和默认模型分发路径。 -- `message_sending`:返回 `{ cancel: true }` 是终态。一旦任一处理器设置它,就会跳过更低优先级处理器。 -- `message_sending`:返回 `{ cancel: false }` 会被视为“无决定”(与省略 `cancel` 相同),而不是覆盖。 -- `message_received`:当你需要传入线程 / 主题路由时,请使用类型化的 `threadId` 字段。将 `metadata` 保留给特定渠道的额外信息。 -- `message_sending`:在回退到特定渠道 `metadata` 之前,优先使用类型化的 `replyToId` / `threadId` 路由字段。 -- `gateway_start`:使用 `ctx.config`、`ctx.workspaceDir` 和 `ctx.getCron?.()` 来处理插件拥有的的启动状态,而不要依赖内部的 `section:startup` 钩子。 +- `before_tool_call`:返回 `{ block: true }` 是终止性的。一旦任一处理器设置了它,就会跳过优先级更低的处理器。 +- `before_tool_call`:返回 `{ block: false }` 会被视为未作决定(与省略 `block` 相同),而不是覆盖。 +- `before_install`:返回 `{ block: true }` 是终止性的。一旦任一处理器设置了它,就会跳过优先级更低的处理器。 +- `before_install`:返回 `{ block: false }` 会被视为未作决定(与省略 `block` 相同),而不是覆盖。 +- `reply_dispatch`:返回 `{ handled: true, ... }` 是终止性的。一旦任一处理器声明已分发,就会跳过优先级更低的处理器以及默认的模型分发路径。 +- `message_sending`:返回 `{ cancel: true }` 是终止性的。一旦任一处理器设置了它,就会跳过优先级更低的处理器。 +- `message_sending`:返回 `{ cancel: false }` 会被视为未作决定(与省略 `cancel` 相同),而不是覆盖。 +- `message_received`:当你需要入站线程 / 话题路由时,请使用类型化的 `threadId` 字段。将 `metadata` 保留给渠道特定的额外信息。 +- `message_sending`:优先使用类型化的 `replyToId` / `threadId` 路由字段,再回退到渠道特定的 `metadata`。 +- `gateway_start`:使用 `ctx.config`、`ctx.workspaceDir` 和 `ctx.getCron?.()` 表示由 Gateway 网关拥有的启动状态,而不要依赖内部 `gateway:startup` hook。 -| 字段 | 类型 | 说明 | -| ------------------------ | ------------------------- | -------------------------------------------------------------------------------------------- | -| `api.id` | `string` | 插件 id | -| `api.name` | `string` | 显示名称 | -| `api.version` | `string?` | 插件版本(可选) | -| `api.description` | `string?` | 插件描述(可选) | -| `api.source` | `string` | 插件源路径 | -| `api.rootDir` | `string?` | 插件根目录(可选) | -| `api.config` | `OpenClawConfig` | 当前配置快照(可用时为活动的内存中运行时快照) | -| `api.pluginConfig` | `Record` | 来自 `plugins.entries..config` 的插件特定配置 | -| `api.runtime` | `PluginRuntime` | [运行时辅助函数](/zh-CN/plugins/sdk-runtime) | -| `api.logger` | `PluginLogger` | 作用域日志记录器(`debug`、`info`、`warn`、`error`) | -| `api.setupMode` | `PluginSetupMode` | 当前加载模式;`"setup-runtime"` 是完整入口启动 / 设置之前的轻量级预启动 / 设置窗口 | -| `api.resolvePath(input)` | `(string) => string` | 解析相对于插件根目录的路径 | +### API 对象字段 + +| 字段 | 类型 | 说明 | +| ------------------------ | ------------------------- | ------------------------------------------------------------------------------------------- | +| `api.id` | `string` | 插件 id | +| `api.name` | `string` | 显示名称 | +| `api.version` | `string?` | 插件版本(可选) | +| `api.description` | `string?` | 插件描述(可选) | +| `api.source` | `string` | 插件源路径 | +| `api.rootDir` | `string?` | 插件根目录(可选) | +| `api.config` | `OpenClawConfig` | 当前配置快照(可用时为活动的内存运行时快照) | +| `api.pluginConfig` | `Record` | 来自 `plugins.entries..config` 的插件特定配置 | +| `api.runtime` | `PluginRuntime` | [运行时辅助函数](/zh-CN/plugins/sdk-runtime) | +| `api.logger` | `PluginLogger` | 作用域日志记录器(`debug`、`info`、`warn`、`error`) | +| `api.registrationMode` | `PluginRegistrationMode` | 当前加载模式;`"setup-runtime"` 是完整入口启动 / 设置前的轻量预启动 / 设置窗口 | +| `api.resolvePath(input)` | `(string) => string` | 解析相对于插件根目录的路径 | ## 内部模块约定 -在你的插件中,使用本地 barrel 文件进行内部导入: +在你的插件内部,请使用本地 barrel 文件进行内部导入: ``` my-plugin/ - api.ts # 面向外部使用者的公共导出 - runtime-api.ts # 仅限内部的运行时导出 + api.ts # 供外部使用方使用的公共导出 + runtime-api.ts # 仅供内部使用的运行时导出 index.ts # 插件入口点 - setup-entry.ts # 仅设置的轻量级入口(可选) + setup-entry.ts # 仅设置用的轻量入口点(可选) ``` - 永远不要在生产代码中通过 `openclaw/plugin_sdk/` + 永远不要在生产代码中通过 `openclaw/plugin-sdk/` 导入你自己的插件。内部导入应通过 `./api.ts` 或 - `./runtime-api.ts`。SDK 路径只是外部契约。 + `./runtime-api.ts`。SDK 路径仅是对外契约。 -由门面加载的内置插件公共表面(`api.ts`、`runtime-api.ts`、 -`index.ts`、`setup-entry.ts` 以及类似的公共入口文件)在 OpenClaw 已经运行时, -会优先使用活动运行时配置快照。如果运行时快照尚不存在, -它们会回退到磁盘上解析得到的配置文件。 +由 facade 加载的内置插件公共 surface(`api.ts`、`runtime-api.ts`、 +`index.ts`、`setup-entry.ts` 以及类似的公共入口文件)会在 OpenClaw 已经运行时优先使用活动运行时配置快照。如果尚不存在运行时快照,它们会回退到磁盘上的已解析配置文件。 -提供者插件可以公开一个狭义的插件本地契约 barrel,当某个辅助函数明确是提供者特定的、且暂时不属于通用 SDK 子路径时。内置示例: +当某个辅助函数明确是 provider 特定的、且尚不适合放入通用 SDK 子路径时,provider 插件可以暴露一个窄化的插件本地契约 barrel。内置示例: -- **Anthropic**:用于 Claude - beta header 和 `service_tier` 流辅助函数的公共 `api.ts` / `contract-api.ts` 接缝。 -- **`@openclaw/openai-provider`**:`api.ts` 导出提供者构建器、 - 默认模型辅助函数和实时提供者构建器。 -- **`@openclaw/openrouter-provider`**:`api.ts` 导出提供者构建器, - 以及新手引导 / 配置辅助函数。 +- **Anthropic**:用于 Claude beta-header 和 `service_tier` 流辅助函数的公共 `api.ts` / `contract-api.ts` seam。 +- **`@openclaw/openai-provider`**:`api.ts` 导出 provider 构建器、默认模型辅助函数和实时 provider 构建器。 +- **`@openclaw/openrouter-provider`**:`api.ts` 导出 provider 构建器以及新手引导 / 配置辅助函数。 - 插件生产代码也应避免从 `openclaw_plugin_sdk/` - 导入。如果某个辅助函数确实需要共享,应将其提升为中立的 SDK 子路径, - 例如 `openclaw/plugin_sdk/speech`、`.../provider-model-shared`,或其他 - 面向能力的表面,而不是把两个插件耦合在一起。 + 扩展生产代码也应避免导入 `openclaw/plugin-sdk/`。 + 如果某个辅助函数确实需要共享,应将其提升为中立的 SDK 子路径, + 例如 `openclaw/plugin-sdk/speech`、`.../provider-model-shared` 或其他 + 面向能力的 surface,而不是将两个插件耦合在一起。 ## 相关内容 @@ -267,16 +278,15 @@ my-plugin/ 完整的 `api.runtime` 命名空间参考。 - 打包、清单和配置模式。 + 打包、manifest 和配置 schema。 测试工具和 lint 规则。 - 从已弃用表面迁移。 + 从已弃用 surface 迁移。 - 深入了解架构和能力模型。 - + 深入架构和能力模型。