chore(i18n): refresh zh-CN translations
This commit is contained in:
parent
babef6ba1d
commit
35567979f4
@ -1,27 +1,27 @@
|
||||
---
|
||||
read_when:
|
||||
- 实现提供商运行时钩子、渠道生命周期或软件包包集
|
||||
- 实现提供商运行时钩子、渠道生命周期或包集合
|
||||
- 调试插件加载顺序或注册表状态
|
||||
- 添加新的插件能力或上下文引擎插件
|
||||
summary: 插件架构内部机制:加载管线、注册表、运行时钩子、HTTP 路由和参考表
|
||||
summary: 插件架构内部机制:加载流水线、注册表、运行时钩子、HTTP 路由和参考表
|
||||
title: 插件架构内部机制
|
||||
x-i18n:
|
||||
generated_at: "2026-04-29T01:24:56Z"
|
||||
generated_at: "2026-04-29T02:56:03Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: 2c1167edfe84782c735fa8f22e25e14728c64289b63774a6c9730fecace7cc1a
|
||||
source_hash: 8bf4d19b962e92580d39b45f6171d937d2d23f3491a32a304bfd62510197ab3e
|
||||
source_path: plugins/architecture-internals.md
|
||||
workflow: 16
|
||||
---
|
||||
|
||||
对于公共能力模型、插件形态以及所有权/执行契约,请参阅 [插件架构](/zh-CN/plugins/architecture)。本页是内部机制的参考:加载流水线、注册表、运行时钩子、Gateway 网关 HTTP 路由、导入路径和 schema 表。
|
||||
关于公开能力模型、插件形态以及所有权/执行契约,请参阅[插件架构](/zh-CN/plugins/architecture)。本页是内部机制的参考:加载管线、注册表、运行时钩子、Gateway 网关 HTTP 路由、导入路径和模式表。
|
||||
|
||||
## 加载流水线
|
||||
## 加载管线
|
||||
|
||||
启动时,OpenClaw 大致会执行以下操作:
|
||||
|
||||
1. 发现候选插件根目录
|
||||
2. 读取原生或兼容 bundle manifest 以及 package 元数据
|
||||
2. 读取原生或兼容 bundle 清单和包元数据
|
||||
3. 拒绝不安全的候选项
|
||||
4. 规范化插件配置(`plugins.enabled`、`allow`、`deny`、`entries`、
|
||||
`slots`、`load.paths`)
|
||||
@ -32,62 +32,75 @@ x-i18n:
|
||||
8. 将注册表暴露给命令/运行时界面
|
||||
|
||||
<Note>
|
||||
`activate` 是 `register` 的旧版别名 —— 加载器会解析存在的那个(`def.register ?? def.activate`),并在同一位置调用它。所有内置插件都使用 `register`;新插件优先使用 `register`。
|
||||
`activate` 是 `register` 的旧版别名 — 加载器会解析当前存在的那个(`def.register ?? def.activate`),并在同一时点调用它。所有内置插件都使用 `register`;新插件请优先使用 `register`。
|
||||
</Note>
|
||||
|
||||
安全门禁发生在运行时执行**之前**。当入口逃逸出插件根目录、路径为全局可写,或非内置插件的路径所有权看起来可疑时,候选项会被阻止。
|
||||
安全门禁发生在运行时执行**之前**。当入口逃逸出插件根目录、路径可被所有用户写入,或非内置插件的路径所有权看起来可疑时,候选项会被阻止。
|
||||
|
||||
### Manifest 优先行为
|
||||
### 清单优先行为
|
||||
|
||||
manifest 是控制平面的事实来源。OpenClaw 用它来:
|
||||
清单是控制平面的事实来源。OpenClaw 使用它来:
|
||||
|
||||
- 识别插件
|
||||
- 发现声明的渠道/skills/配置 schema 或 bundle 能力
|
||||
- 发现声明的渠道/Skills/配置模式或 bundle 能力
|
||||
- 验证 `plugins.entries.<id>.config`
|
||||
- 增强 Control UI 标签/占位符
|
||||
- 显示安装/catalog 元数据
|
||||
- 在不加载插件运行时的情况下,保留低成本的激活和设置描述符
|
||||
- 增强控制 UI 标签/占位符
|
||||
- 显示安装/目录元数据
|
||||
- 在不加载插件运行时的情况下保留低成本激活和设置描述符
|
||||
|
||||
对于原生插件,运行时模块是数据平面部分。它注册实际行为,例如钩子、工具、命令或提供商流程。
|
||||
对于原生插件,运行时模块是数据平面部分。它注册钩子、工具、命令或提供商流程等实际行为。
|
||||
|
||||
可选的 manifest `activation` 和 `setup` 块保留在控制平面上。它们是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`。首批实时激活消费者现在会使用 manifest 命令、渠道和提供商提示,在更广泛的注册表物化之前缩小插件加载范围:
|
||||
可选清单 `activation` 和 `setup` 块保留在控制平面上。它们是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`。第一批实时激活消费者现在会使用清单命令、渠道和提供商提示,在更广泛的注册表物化之前缩小插件加载范围:
|
||||
|
||||
- CLI 加载会缩小到拥有所请求主命令的插件
|
||||
- 渠道设置/插件解析会缩小到拥有所请求渠道 id 的插件
|
||||
- 显式提供商设置/运行时解析会缩小到拥有所请求提供商 id 的插件
|
||||
- Gateway 网关启动规划会使用 `activation.onStartup` 进行显式启动导入和启动选择退出;随着 OpenClaw 摆脱隐式启动导入,每个插件都应声明它,而没有静态能力元数据且没有 `activation.onStartup` 的插件,仍会使用已弃用的隐式启动 sidecar 回退来保持兼容性
|
||||
- 渠道设置/插件解析会缩小到拥有所请求
|
||||
渠道 ID 的插件
|
||||
- 显式提供商设置/运行时解析会缩小到拥有所请求
|
||||
提供商 ID 的插件
|
||||
- Gateway 网关启动规划使用 `activation.onStartup` 处理显式启动
|
||||
导入和启动退出;随着 OpenClaw 从隐式启动导入迁移出去,每个插件都应声明它,而没有静态
|
||||
能力元数据且没有 `activation.onStartup` 的插件仍会使用
|
||||
已弃用的隐式启动 sidecar 回退以保持兼容性
|
||||
|
||||
激活规划器同时为现有调用方暴露仅 ids 的 API,并为新诊断暴露计划 API。计划条目会报告插件被选中的原因,将显式 `activation.*` 规划器提示与 manifest 所有权回退区分开来,例如 `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子。这种原因拆分就是兼容性边界:现有插件元数据会继续工作,而新代码可以在不改变运行时加载语义的情况下检测宽泛提示或回退行为。
|
||||
激活规划器既为现有调用方暴露仅包含 ID 的 API,也为新诊断暴露规划 API。规划条目会报告插件被选中的原因,将显式 `activation.*` 规划器提示与清单所有权回退区分开来,例如 `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子。这种原因拆分就是兼容性边界:现有插件元数据会继续工作,而新代码可以在不改变运行时加载语义的情况下检测宽泛提示或回退行为。
|
||||
|
||||
设置发现现在优先使用描述符拥有的 id,例如 `setup.providers` 和 `setup.cliBackends`,在回退到仍需要设置时运行时钩子的插件的 `setup-api` 之前缩小候选插件范围。提供商设置列表会使用 manifest `providerAuthChoices`、从描述符派生的设置选项以及安装 catalog 元数据,而不加载提供商运行时。显式 `setup.requiresRuntime: false` 是仅描述符的截止点;省略 `requiresRuntime` 会保留旧版 setup-api 回退以保持兼容性。如果多个已发现插件声明同一个规范化后的设置提供商或 CLI 后端 id,设置查找会拒绝这个有歧义的所有者,而不是依赖发现顺序。当设置运行时确实执行时,注册表诊断会报告 `setup.providers` / `setup.cliBackends` 与 setup-api 注册的提供商或 CLI 后端之间的漂移,但不会阻止旧版插件。
|
||||
设置发现现在优先使用描述符拥有的 ID,例如 `setup.providers` 和 `setup.cliBackends`,以便在回退到仍需要设置时运行时钩子的插件的 `setup-api` 之前缩小候选插件范围。提供商设置列表会使用清单 `providerAuthChoices`、从描述符派生的设置选项以及安装目录元数据,而不加载提供商运行时。显式 `setup.requiresRuntime: false` 是仅描述符的截止点;省略 `requiresRuntime` 会保留旧版 setup-api 回退以保持兼容性。如果多个已发现插件声明同一个规范化后的设置提供商或 CLI 后端 ID,设置查找会拒绝这个含糊的所有者,而不是依赖发现顺序。当设置运行时确实执行时,注册表诊断会报告 `setup.providers` / `setup.cliBackends` 与 setup-api 注册的提供商或 CLI 后端之间的漂移,但不会阻止旧版插件。
|
||||
|
||||
### 加载器缓存的内容
|
||||
### 插件缓存边界
|
||||
|
||||
OpenClaw 会保留短期进程内缓存,用于:
|
||||
OpenClaw 不会在基于墙钟时间的窗口后面缓存插件发现结果或直接清单注册表数据。安装、清单编辑和加载路径变更必须在下一次显式元数据读取或快照重建时可见。
|
||||
|
||||
安全的元数据快速路径是显式对象所有权,而不是隐藏缓存。Gateway 网关启动热路径应通过调用链传递当前的 `PluginMetadataSnapshot`、派生的 `PluginLookUpTable` 或显式清单注册表。配置验证、启动自动启用、插件引导、设置查找和提供商选择可以复用这些对象,只要它们表示的是当前配置和插件清单。当该输入变化时,应重建并替换快照,而不是修改它或保留历史副本。
|
||||
对活动插件注册表的视图和内置渠道引导辅助工具应从当前注册表/根目录重新计算。短生命周期映射可以在一次调用内部用于去重工作或防止重入;它们不得变成进程元数据缓存。
|
||||
|
||||
对于插件加载,持久缓存层是运行时加载。当代码或已安装产物确实被加载时,它可以复用加载器状态,例如:
|
||||
|
||||
- `PluginLoaderCacheState` 和兼容的活动运行时注册表
|
||||
- 用于避免反复导入同一运行时界面的 jiti/模块缓存和公共界面加载器缓存
|
||||
- 已安装插件产物的运行时依赖镜像和文件系统缓存
|
||||
- 用于路径规范化或重复解析的短生命周期逐调用映射
|
||||
|
||||
这些缓存是数据平面实现细节。它们不得回答控制平面问题,例如“哪个插件拥有此提供商?”,除非调用方有意请求了运行时加载。
|
||||
|
||||
不要为以下内容添加持久缓存或基于墙钟时间的缓存:
|
||||
|
||||
- 发现结果
|
||||
- manifest 注册表数据
|
||||
- 已加载的插件注册表
|
||||
- 直接清单注册表
|
||||
- 从已安装插件索引重建的清单注册表
|
||||
- 提供商所有者查找、模型抑制、提供商策略或公共产物
|
||||
元数据
|
||||
- 任何其他从清单派生的答案,其中变更后的清单、已安装索引
|
||||
或加载路径应在下一次元数据读取时可见
|
||||
|
||||
这些缓存可以降低突发启动和重复命令开销。可以把它们视为短生命周期的性能缓存,而不是持久化存储。
|
||||
|
||||
Gateway 网关启动热路径应优先使用当前的 `PluginMetadataSnapshot`、派生的 `PluginLookUpTable`,或通过调用链传入的显式 manifest 注册表。配置验证、启动自动启用和插件引导会在可用时使用同一个快照。对于仍从持久化已安装插件索引重建 manifest 元数据的调用方,OpenClaw 还会保留一个小型有界回退缓存,其键由已安装索引、请求形态、配置策略、运行时根目录以及 manifest/package 文件签名组成。该缓存只是重复已安装索引重建的回退;它不是可变的运行时插件注册表。
|
||||
|
||||
性能说明:
|
||||
|
||||
- 设置 `OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1` 或
|
||||
`OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1` 可禁用这些缓存。
|
||||
- 设置 `OPENCLAW_DISABLE_INSTALLED_PLUGIN_MANIFEST_REGISTRY_CACHE=1` 可仅禁用已安装索引 manifest 注册表回退缓存。
|
||||
- 使用 `OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS` 和
|
||||
`OPENCLAW_PLUGIN_MANIFEST_CACHE_MS` 调整缓存窗口。
|
||||
从持久化已安装插件索引重建清单元数据的调用方会按需重建该注册表。已安装索引是持久的源平面状态;它不是隐藏的进程内元数据缓存。
|
||||
|
||||
## 注册表模型
|
||||
|
||||
已加载的插件不会直接修改随机的核心全局变量。它们会注册到中央插件注册表中。
|
||||
已加载的插件不会直接修改随机核心全局变量。它们会注册到一个中央插件注册表中。
|
||||
|
||||
注册表会跟踪:
|
||||
|
||||
- 插件记录(身份、来源、源头、状态、诊断)
|
||||
- 插件记录(身份、来源、源头、Status、诊断)
|
||||
- 工具
|
||||
- 旧版钩子和类型化钩子
|
||||
- 渠道
|
||||
@ -98,16 +111,16 @@ Gateway 网关启动热路径应优先使用当前的 `PluginMetadataSnapshot`
|
||||
- 后台服务
|
||||
- 插件拥有的命令
|
||||
|
||||
然后核心功能会从该注册表读取,而不是直接与插件模块交互。这使加载保持单向:
|
||||
随后,核心功能会从该注册表读取,而不是直接与插件模块通信。这使加载保持单向:
|
||||
|
||||
- 插件模块 -> 注册表注册
|
||||
- 核心运行时 -> 注册表消费
|
||||
|
||||
这种分离对可维护性很重要。它意味着大多数核心界面只需要一个集成点:“读取注册表”,而不是“为每个插件模块编写特殊情况”。
|
||||
这种分离对可维护性很重要。它意味着大多数核心界面只需要一个集成点:“读取注册表”,而不是“为每个插件模块做特殊处理”。
|
||||
|
||||
## 对话绑定回调
|
||||
|
||||
绑定对话的插件可以在审批被解析时作出响应。
|
||||
绑定对话的插件可以在审批完成时作出反应。
|
||||
|
||||
使用 `api.onConversationBindingResolved(...)` 在绑定请求被批准或拒绝后接收回调:
|
||||
|
||||
@ -129,89 +142,92 @@ export default {
|
||||
};
|
||||
```
|
||||
|
||||
回调 payload 字段:
|
||||
回调载荷字段:
|
||||
|
||||
- `status`:`"approved"` 或 `"denied"`
|
||||
- `decision`:`"allow-once"`、`"allow-always"` 或 `"deny"`
|
||||
- `binding`:已批准请求的已解析绑定
|
||||
- `request`:原始请求摘要、detach 提示、发送方 id 和对话元数据
|
||||
- `request`:原始请求摘要、分离提示、发送方 ID 和
|
||||
对话元数据
|
||||
|
||||
此回调仅用于通知。它不会更改谁可以绑定对话,并且会在核心审批处理完成后运行。
|
||||
此回调仅用于通知。它不会改变允许谁绑定对话,并且会在核心审批处理完成后运行。
|
||||
|
||||
## 提供商运行时钩子
|
||||
|
||||
提供商插件有三层:
|
||||
|
||||
- 用于低成本预运行时查找的 **manifest 元数据**:
|
||||
- 用于低成本运行时前查找的**清单元数据**:
|
||||
`setup.providers[].envVars`、已弃用的兼容性 `providerAuthEnvVars`、
|
||||
`providerAuthAliases`、`providerAuthChoices` 和 `channelEnvVars`。
|
||||
- **配置时钩子**:`catalog`(旧版 `discovery`)以及
|
||||
- **配置时钩子**:`catalog`(旧版 `discovery`)加上
|
||||
`applyConfigDefaults`。
|
||||
- **运行时钩子**:40 多个可选钩子,涵盖身份验证、模型解析、流包装、thinking 级别、重放策略和使用量端点。完整列表见 [钩子顺序和用法](#hook-order-and-usage)。
|
||||
- **运行时钩子**:40 多个可选钩子,覆盖认证、模型解析、
|
||||
流包装、思考等级、重放策略和用量端点。请参阅
|
||||
[钩子顺序和用法](#hook-order-and-usage)下的完整列表。
|
||||
|
||||
OpenClaw 仍然拥有通用 Agent loop、故障转移、transcript 处理和工具策略。这些钩子是提供商特定行为的扩展界面,无需完整的自定义推理传输。
|
||||
OpenClaw 仍拥有通用 Agent loop、故障转移、转录处理和工具策略。这些钩子是在不需要完整自定义推理传输的情况下支持提供商特定行为的扩展界面。
|
||||
|
||||
当提供商有基于环境的凭证,并且通用身份验证/Status/模型选择器路径应在不加载插件运行时的情况下看到它们时,请使用 manifest `setup.providers[].envVars`。已弃用的 `providerAuthEnvVars` 在弃用窗口期间仍会由兼容性适配器读取,使用它的非内置插件会收到 manifest 诊断。当一个提供商 id 应复用另一个提供商 id 的环境变量、auth profiles、配置支持的身份验证以及 API-key 新手引导选项时,请使用 manifest `providerAuthAliases`。当 onboarding/auth-choice CLI 界面应在不加载提供商运行时的情况下了解提供商的选项 id、分组标签以及简单的单标志身份验证接线时,请使用 manifest `providerAuthChoices`。将提供商运行时 `envVars` 保留给面向操作者的提示,例如新手引导标签或 OAuth client-id/client-secret 设置变量。
|
||||
当提供商具有基于环境的凭证,并且通用认证/Status/模型选择器路径应在不加载插件运行时的情况下看到这些凭证时,请使用清单 `setup.providers[].envVars`。已弃用的 `providerAuthEnvVars` 在弃用窗口期间仍会由兼容性适配器读取,使用它的非内置插件会收到清单诊断。当一个提供商 ID 应复用另一个提供商 ID 的环境变量、认证配置文件、配置支持的认证和 API 密钥新手引导选项时,请使用清单 `providerAuthAliases`。当新手引导/认证选择 CLI 界面应在不加载提供商运行时的情况下了解提供商的选择 ID、分组标签和简单的单标志认证接线时,请使用清单 `providerAuthChoices`。请将提供商运行时 `envVars` 保留用于面向操作员的提示,例如新手引导标签或 OAuth 客户端 ID/客户端密钥设置变量。
|
||||
|
||||
当渠道有环境驱动的身份验证或设置,并且通用 shell-env 回退、配置/Status 检查或设置提示应在不加载渠道运行时的情况下看到它们时,请使用 manifest `channelEnvVars`。
|
||||
当渠道具有由环境驱动的认证或设置,并且通用 shell 环境回退、配置/Status 检查或设置提示应在不加载渠道运行时的情况下看到它们时,请使用清单 `channelEnvVars`。
|
||||
|
||||
### 钩子顺序和用法
|
||||
|
||||
对于模型/提供商插件,OpenClaw 会按以下大致顺序调用钩子。
|
||||
“When to use” 列是快速决策指南。
|
||||
“When to use”列是快速决策指南。
|
||||
|
||||
| # | 钩子 | 作用 | 使用时机 |
|
||||
| # | 钩子 | 作用 | 使用场景 |
|
||||
| --- | --------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1 | `catalog` | 在生成 `models.json` 期间将提供商配置发布到 `models.providers` | 提供商拥有目录或基础 URL 默认值 |
|
||||
| 2 | `applyConfigDefaults` | 在配置物化期间应用由提供商拥有的全局配置默认值 | 默认值取决于凭证模式、环境或提供商模型系列语义 |
|
||||
| -- | _(内置模型查找)_ | OpenClaw 会先尝试正常的注册表/目录路径 | _(不是插件钩子)_ |
|
||||
| 3 | `normalizeModelId` | 在查找前规范化旧版或预览版模型 ID 别名 | 提供商在规范模型解析前负责别名清理 |
|
||||
| 4 | `normalizeTransport` | 在通用模型组装前规范化提供商系列的 `api` / `baseUrl` | 提供商负责同一传输系列中自定义提供商 ID 的传输清理 |
|
||||
| 5 | `normalizeConfig` | 在运行时/提供商解析前规范化 `models.providers.<id>` | 提供商需要与插件同处的配置清理;内置 Google 系列辅助逻辑也会兜底支持的 Google 配置条目 |
|
||||
| 1 | `catalog` | 在生成 `models.json` 期间,将提供商配置发布到 `models.providers` | 提供商拥有目录或基础 URL 默认值 |
|
||||
| 2 | `applyConfigDefaults` | 在配置物化期间应用提供商拥有的全局配置默认值 | 默认值取决于认证模式、环境或提供商模型系列语义 |
|
||||
| -- | _(内置模型查找)_ | OpenClaw 会先尝试普通注册表/目录路径 | _(不是插件钩子)_ |
|
||||
| 3 | `normalizeModelId` | 在查找前规范化旧版或预览版模型 ID 别名 | 提供商负责在规范模型解析前清理别名 |
|
||||
| 4 | `normalizeTransport` | 在通用模型组装前规范化提供商系列的 `api` / `baseUrl` | 提供商负责清理同一传输系列中自定义提供商 ID 的传输 |
|
||||
| 5 | `normalizeConfig` | 在运行时/提供商解析前规范化 `models.providers.<id>` | 提供商需要由插件负责的配置清理;内置 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 |
|
||||
| 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` | 在嵌入式运行器看到工具 schema 前对其进行规范化 | 提供商需要传输系列 schema 清理 |
|
||||
| 17 | `inspectToolSchemas` | 在规范化后暴露由提供商拥有的 schema 诊断信息 | 提供商需要关键字警告,而不把提供商特定规则教给核心 |
|
||||
| 14 | `contributeResolvedModelCompat` | 为位于另一个兼容传输后的供应商模型贡献兼容性标志 | 提供商可在代理传输上识别自己的模型,而无需接管该提供商 |
|
||||
| 15 | `capabilities` | 由共享核心逻辑使用的提供商自有 transcript/工具元数据 | 提供商需要 transcript/提供商系列特殊处理 |
|
||||
| 16 | `normalizeToolSchemas` | 在嵌入式运行器看到工具 schema 前规范化它们 | 提供商需要传输系列的 schema 清理 |
|
||||
| 17 | `inspectToolSchemas` | 在规范化后暴露提供商自有的 schema 诊断 | 提供商想要关键字警告,而不把提供商特定规则教给核心 |
|
||||
| 18 | `resolveReasoningOutputMode` | 选择原生或带标签的推理输出契约 | 提供商需要带标签的推理/最终输出,而不是原生字段 |
|
||||
| 19 | `prepareExtraParams` | 在通用流选项包装器前进行请求参数规范化 | 提供商需要默认请求参数或按提供商清理参数 |
|
||||
| 20 | `createStreamFn` | 用自定义传输完全替换正常流路径 | 提供商需要自定义线路协议,而不仅是包装器 |
|
||||
| 21 | `wrapStreamFn` | 应用通用包装器后的流包装器 | 提供商需要请求头/请求体/模型兼容包装器,而不是自定义传输 |
|
||||
| 22 | `resolveTransportTurnState` | 附加原生的每轮传输请求头或元数据 | 提供商希望通用传输发送提供商原生的轮次标识 |
|
||||
| 23 | `resolveWebSocketSessionPolicy` | 附加原生 WebSocket 请求头或会话冷却策略 | 提供商希望通用 WS 传输调整会话请求头或回退策略 |
|
||||
| 24 | `formatApiKey` | 凭证配置文件格式化器:已存储的配置文件会变成运行时 `apiKey` 字符串 | 提供商存储额外凭证元数据,并需要自定义运行时令牌形态 |
|
||||
| 25 | `refreshOAuth` | 用于自定义刷新端点或刷新失败策略的 OAuth 刷新覆盖 | 提供商不适配共享的 `pi-ai` 刷新器 |
|
||||
| 26 | `buildAuthDoctorHint` | OAuth 刷新失败时追加的修复提示 | 提供商需要在刷新失败后提供由提供商拥有的凭证修复指导 |
|
||||
| 27 | `matchesContextOverflowError` | 由提供商拥有的上下文窗口溢出匹配器 | 提供商存在通用启发式规则会漏掉的原始溢出错误 |
|
||||
| 28 | `classifyFailoverReason` | 由提供商拥有的故障转移原因分类 | 提供商可以将原始 API/传输错误映射为速率限制/过载等 |
|
||||
| 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` | 已弃用。运行时钩子不再调用;请使用清单 `modelCatalog.suppressions` | 用于隐藏陈旧上游行的历史钩子;将新的抑制数据保留在插件清单中 |
|
||||
| 32 | `augmentModelCatalog` | 在设备发现后追加的合成/最终目录行 | 提供商需要 `models list` 和选择器中的合成前向兼容行 |
|
||||
| 33 | `resolveThinkingProfile` | 特定模型的 `/think` 级别集、显示标签和默认值 | 提供商为选定模型暴露自定义思考层级或二元标签 |
|
||||
| 34 | `isBinaryThinking` | 开/关推理切换兼容性钩子 | 提供商只暴露二元思考开关 |
|
||||
| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性钩子 | 提供商只想在一部分模型上启用 `xhigh` |
|
||||
| 30 | `buildMissingAuthMessage` | 替换通用的缺失认证恢复消息 | 提供商需要提供商特定的缺失认证恢复提示 |
|
||||
| 31 | `suppressBuiltInModel` | 已弃用。运行时钩子不再被调用;请使用清单 `modelCatalog.suppressions` | 用于隐藏过期上游行的历史钩子;将新的抑制数据保留在插件清单中 |
|
||||
| 32 | `augmentModelCatalog` | 在设备发现后追加的合成/最终目录行 | 提供商需要在 `models list` 和选择器中提供合成的前向兼容行 |
|
||||
| 33 | `resolveThinkingProfile` | 模型特定的 `/think` 级别集合、显示标签和默认值 | 提供商为所选模型暴露自定义思考档位或二元标签 |
|
||||
| 34 | `isBinaryThinking` | 开/关推理切换兼容性钩子 | 提供商只暴露二元思考开/关 |
|
||||
| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性钩子 | 提供商只想在模型子集上启用 `xhigh` |
|
||||
| 36 | `resolveDefaultThinkingLevel` | 默认 `/think` 级别兼容性钩子 | 提供商拥有某个模型系列的默认 `/think` 策略 |
|
||||
| 37 | `isModernModelRef` | 用于实时配置文件过滤器和冒烟选择的现代模型匹配器 | 提供商负责实时/冒烟首选模型匹配 |
|
||||
| 38 | `prepareRuntimeAuth` | 在推理前,将已配置凭证交换为实际的运行时令牌/密钥 | 提供商需要令牌交换或短期请求凭证 |
|
||||
| 39 | `resolveUsageAuth` | 为 `/usage` 和相关 Status 界面解析用量/计费凭证 | 提供商需要自定义用量/配额令牌解析,或不同的用量凭证 |
|
||||
| 37 | `isModernModelRef` | 用于实时 profile 过滤器和冒烟选择的现代模型匹配器 | 提供商负责实时/冒烟首选模型匹配 |
|
||||
| 38 | `prepareRuntimeAuth` | 在推理前,将配置的凭据交换为实际的运行时令牌/密钥 | 提供商需要令牌交换或短期请求凭据 |
|
||||
| 39 | `resolveUsageAuth` | 为 `/usage` 和相关 Status 界面解析用量/计费凭据 | 提供商需要自定义用量/配额令牌解析,或不同的用量凭据 |
|
||||
| 40 | `fetchUsageSnapshot` | 在认证解析完成后,获取并规范化提供商特定的用量/配额快照 | 提供商需要提供商特定的用量端点或载荷解析器 |
|
||||
| 41 | `createEmbeddingProvider` | 构建提供商拥有的嵌入适配器,用于记忆/搜索 | 记忆嵌入行为归属提供商插件 |
|
||||
| 42 | `buildReplayPolicy` | 返回控制提供商会话记录处理的重放策略 | 提供商需要自定义会话记录策略(例如剥离 thinking 块) |
|
||||
| 43 | `sanitizeReplayHistory` | 在通用会话记录清理后重写重放历史 | 提供商需要超出共享压缩助手范围的提供商特定重放重写 |
|
||||
| 44 | `validateReplayTurns` | 在嵌入式运行器之前进行最终的重放轮次验证或重塑 | 提供商传输协议在通用清理后需要更严格的轮次验证 |
|
||||
| 45 | `onModelSelected` | 运行提供商拥有的选择后副作用 | 当某个模型变为活动状态时,提供商需要遥测或提供商拥有的状态 |
|
||||
| 41 | `createEmbeddingProvider` | 为记忆/搜索构建由提供商负责的嵌入适配器 | 记忆嵌入行为归属提供商插件 |
|
||||
| 42 | `buildReplayPolicy` | 返回用于控制该提供商转录处理的重放策略 | 提供商需要自定义转录策略(例如,剥离思考块) |
|
||||
| 43 | `sanitizeReplayHistory` | 在通用转录清理后重写重放历史 | 提供商需要超出共享压缩辅助函数范围的提供商特定重放重写 |
|
||||
| 44 | `validateReplayTurns` | 在嵌入式运行器之前进行最终重放回合验证或重塑 | 提供商传输协议在通用清理后需要更严格的回合验证 |
|
||||
| 45 | `onModelSelected` | 运行由提供商负责的选择后副作用 | 当模型变为活动状态时,提供商需要遥测或由提供商负责的状态 |
|
||||
|
||||
`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配的提供商插件,然后继续遍历其他支持钩子的提供商插件,直到某个插件实际更改模型 ID 或传输协议/配置。这样可以让别名/兼容提供商 shim 继续工作,而无需调用方知道哪个内置插件负责该重写。如果没有提供商钩子重写受支持的 Google 系列配置项,内置的 Google 配置规范化器仍会应用该兼容性清理。
|
||||
`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配的提供商插件,然后继续落到其他具备钩子能力的提供商插件,直到某个插件实际更改了模型 ID 或传输/配置。这样可以让别名/兼容性提供商垫片继续工作,而不要求调用方知道哪个内置插件拥有这次重写。如果没有提供商钩子重写受支持的 Google 系列配置项,内置的 Google 配置规范化器仍会应用该兼容性清理。
|
||||
|
||||
如果提供商需要完全自定义的线协议或自定义请求执行器,那属于另一类扩展。这些钩子适用于仍在 OpenClaw 正常推理循环上运行的提供商行为。
|
||||
如果提供商需要完全自定义的线协议或自定义请求执行器,那属于另一类插件。这些钩子用于仍然运行在 OpenClaw 常规推理循环上的提供商行为。
|
||||
|
||||
### 提供商示例
|
||||
|
||||
@ -269,35 +285,23 @@ api.registerProvider({
|
||||
|
||||
### 内置示例
|
||||
|
||||
内置提供商插件会组合上面的钩子,以适配各厂商的目录、认证、思考、重放和用量需求。权威钩子集合与每个插件一起位于 `extensions/` 下;本页展示的是形态,而不是镜像完整列表。
|
||||
内置提供商插件会组合上面的钩子,以适配每个厂商的目录、认证、思考、重放和用量需求。权威的钩子集合与每个插件一起位于 `extensions/` 下;本页展示的是形态,而不是镜像完整列表。
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="直通目录提供商">
|
||||
OpenRouter、Kilocode、Z.AI、xAI 会注册 `catalog` 加上
|
||||
`resolveDynamicModel` / `prepareDynamicModel`,这样它们就能在 OpenClaw 的静态目录之前暴露上游
|
||||
模型 ID。
|
||||
<Accordion title="Pass-through catalog providers">
|
||||
OpenRouter、Kilocode、Z.AI、xAI 注册 `catalog` 加上 `resolveDynamicModel` / `prepareDynamicModel`,这样它们可以在 OpenClaw 的静态目录之前暴露上游模型 ID。
|
||||
</Accordion>
|
||||
<Accordion title="OAuth 和用量端点提供商">
|
||||
GitHub Copilot、Gemini CLI、ChatGPT Codex、MiniMax、小米、z.ai 会将
|
||||
`prepareRuntimeAuth` 或 `formatApiKey` 与 `resolveUsageAuth` +
|
||||
`fetchUsageSnapshot` 配对,用于拥有令牌交换和 `/usage` 集成。
|
||||
<Accordion title="OAuth and usage endpoint providers">
|
||||
GitHub Copilot、Gemini CLI、ChatGPT Codex、MiniMax、Xiaomi、z.ai 将 `prepareRuntimeAuth` 或 `formatApiKey` 与 `resolveUsageAuth` + `fetchUsageSnapshot` 配对,用于拥有令牌交换和 `/usage` 集成。
|
||||
</Accordion>
|
||||
<Accordion title="重放和转录清理系列">
|
||||
共享的命名系列(`google-gemini`、`passthrough-gemini`、
|
||||
`anthropic-by-model`、`hybrid-anthropic-openai`)允许提供商通过
|
||||
`buildReplayPolicy` 选择加入转录策略,而不是让每个插件重新实现清理。
|
||||
<Accordion title="Replay and transcript cleanup families">
|
||||
共享的具名系列(`google-gemini`、`passthrough-gemini`、`anthropic-by-model`、`hybrid-anthropic-openai`)让提供商可以通过 `buildReplayPolicy` 选择加入转录策略,而不必让每个插件重新实现清理逻辑。
|
||||
</Accordion>
|
||||
<Accordion title="仅目录提供商">
|
||||
`byteplus`、`cloudflare-ai-gateway`、`huggingface`、`kimi-coding`、`nvidia`、
|
||||
`qianfan`、`synthetic`、`together`、`venice`、`vercel-ai-gateway` 和
|
||||
`volcengine` 只注册 `catalog`,并使用共享推理循环。
|
||||
<Accordion title="Catalog-only providers">
|
||||
`byteplus`、`cloudflare-ai-gateway`、`huggingface`、`kimi-coding`、`nvidia`、`qianfan`、`synthetic`、`together`、`venice`、`vercel-ai-gateway` 和 `volcengine` 只注册 `catalog`,并使用共享推理循环。
|
||||
</Accordion>
|
||||
<Accordion title="Anthropic 专用流式辅助函数">
|
||||
Beta 标头、`/fast` / `serviceTier` 和 `context1m` 位于
|
||||
Anthropic 插件的公共 `api.ts` / `contract-api.ts` 接缝中
|
||||
(`wrapAnthropicProviderStream`、`resolveAnthropicBetas`、
|
||||
`resolveAnthropicFastMode`、`resolveAnthropicServiceTier`),而不是通用
|
||||
SDK 中。
|
||||
<Accordion title="Anthropic-specific stream helpers">
|
||||
Beta 标头、`/fast` / `serviceTier` 和 `context1m` 位于 Anthropic 插件的公开 `api.ts` / `contract-api.ts` 接缝(`wrapAnthropicProviderStream`、`resolveAnthropicBetas`、`resolveAnthropicFastMode`、`resolveAnthropicServiceTier`)中,而不是位于通用 SDK 中。
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
@ -322,13 +326,13 @@ const voices = await api.runtime.tts.listVoices({
|
||||
});
|
||||
```
|
||||
|
||||
注意:
|
||||
说明:
|
||||
|
||||
- `textToSpeech` 会返回用于文件/语音备注界面的正常核心 TTS 输出载荷。
|
||||
- `textToSpeech` 为文件/语音备注表面返回常规核心 TTS 输出载荷。
|
||||
- 使用核心 `messages.tts` 配置和提供商选择。
|
||||
- 返回 PCM 音频缓冲区 + 采样率。插件必须为提供商重新采样/编码。
|
||||
- `listVoices` 对每个提供商都是可选的。将其用于厂商拥有的语音选择器或设置流程。
|
||||
- 语音列表可以包含更丰富的元数据,例如语言区域、性别和个性标签,以供感知提供商的选择器使用。
|
||||
- `listVoices` 对每个提供商都是可选的。将它用于厂商拥有的语音选择器或设置流程。
|
||||
- 语音列表可以包含更丰富的元数据,例如区域设置、性别和个性标签,用于感知提供商的选择器。
|
||||
- OpenAI 和 ElevenLabs 目前支持电话语音。Microsoft 不支持。
|
||||
|
||||
插件也可以通过 `api.registerSpeechProvider(...)` 注册语音提供商。
|
||||
@ -349,14 +353,14 @@ api.registerSpeechProvider({
|
||||
});
|
||||
```
|
||||
|
||||
注意:
|
||||
说明:
|
||||
|
||||
- 将 TTS 策略、回退和回复递送保留在核心中。
|
||||
- 使用语音提供商处理厂商拥有的合成行为。
|
||||
- 旧版 Microsoft `edge` 输入会规范化为 `microsoft` 提供商 ID。
|
||||
- 首选所有权模型是面向公司的:随着 OpenClaw 添加这些能力契约,一个厂商插件可以拥有文本、语音、图像和未来媒体提供商。
|
||||
- 首选的所有权模型面向公司:随着 OpenClaw 添加这些能力契约,一个厂商插件可以拥有文本、语音、图像以及未来的媒体提供商。
|
||||
|
||||
对于图像/音频/视频理解,插件注册一个带类型的媒体理解提供商,而不是通用键/值包:
|
||||
对于图像/音频/视频理解,插件会注册一个带类型的媒体理解提供商,而不是泛型键/值包:
|
||||
|
||||
```ts
|
||||
api.registerMediaUnderstandingProvider({
|
||||
@ -368,11 +372,11 @@ api.registerMediaUnderstandingProvider({
|
||||
});
|
||||
```
|
||||
|
||||
注意:
|
||||
说明:
|
||||
|
||||
- 将编排、回退、配置和渠道接线保留在核心中。
|
||||
- 将厂商行为保留在提供商插件中。
|
||||
- 增量扩展应保持有类型:新的可选方法、新的可选结果字段、新的可选能力。
|
||||
- 增量扩展应保持类型化:新的可选方法、新的可选结果字段、新的可选能力。
|
||||
- 视频生成已经遵循相同模式:
|
||||
- 核心拥有能力契约和运行时辅助函数
|
||||
- 厂商插件注册 `api.registerVideoGenerationProvider(...)`
|
||||
@ -393,7 +397,7 @@ const video = await api.runtime.mediaUnderstanding.describeVideoFile({
|
||||
});
|
||||
```
|
||||
|
||||
对于音频转录,插件可以使用媒体理解运行时或旧版 STT 别名:
|
||||
对于音频转录,插件可以使用媒体理解运行时或较旧的 STT 别名:
|
||||
|
||||
```ts
|
||||
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
|
||||
@ -404,11 +408,11 @@ const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
|
||||
});
|
||||
```
|
||||
|
||||
注意:
|
||||
说明:
|
||||
|
||||
- `api.runtime.mediaUnderstanding.*` 是图像/音频/视频理解的首选共享界面。
|
||||
- `api.runtime.mediaUnderstanding.*` 是图像/音频/视频理解的首选共享表面。
|
||||
- 使用核心媒体理解音频配置(`tools.media.audio`)和提供商回退顺序。
|
||||
- 当未生成转录输出时(例如跳过/不支持的输入),返回 `{ text: undefined }`。
|
||||
- 当没有生成转录输出时(例如跳过/不受支持的输入),返回 `{ text: undefined }`。
|
||||
- `api.runtime.stt.transcribeAudioFile(...)` 仍作为兼容性别名保留。
|
||||
|
||||
插件也可以通过 `api.runtime.subagent` 启动后台子智能体运行:
|
||||
@ -423,14 +427,14 @@ const result = await api.runtime.subagent.run({
|
||||
});
|
||||
```
|
||||
|
||||
注意:
|
||||
说明:
|
||||
|
||||
- `provider` 和 `model` 是每次运行的可选覆盖项,不是持久会话变更。
|
||||
- OpenClaw 只为受信任的调用方遵循这些覆盖字段。
|
||||
- 对于插件拥有的回退运行,操作员必须使用 `plugins.entries.<id>.subagent.allowModelOverride: true` 选择加入。
|
||||
- 使用 `plugins.entries.<id>.subagent.allowedModels` 将受信任插件限制到特定规范 `provider/model` 目标,或使用 `"*"` 显式允许任意目标。
|
||||
- `provider` 和 `model` 是每次运行的可选覆盖项,而不是持久会话更改。
|
||||
- OpenClaw 只会为受信任调用方遵守这些覆盖字段。
|
||||
- 对于插件拥有的回退运行,操作员必须通过 `plugins.entries.<id>.subagent.allowModelOverride: true` 选择加入。
|
||||
- 使用 `plugins.entries.<id>.subagent.allowedModels` 将受信任插件限制到特定的规范 `provider/model` 目标,或使用 `"*"` 明确允许任意目标。
|
||||
- 不受信任的插件子智能体运行仍可工作,但覆盖请求会被拒绝,而不是静默回退。
|
||||
- 插件创建的子智能体会话会标记创建它的插件 ID。回退 `api.runtime.subagent.deleteSession(...)` 只能删除这些归属会话;任意会话删除仍需要具备管理员作用域的 Gateway 网关请求。
|
||||
- 插件创建的子智能体会话会用创建它的插件 ID 打标签。回退 `api.runtime.subagent.deleteSession(...)` 只能删除这些归属会话;任意会话删除仍需要管理员作用域的 Gateway 网关请求。
|
||||
|
||||
对于 Web 搜索,插件可以使用共享运行时辅助函数,而不是进入智能体工具接线:
|
||||
|
||||
@ -448,14 +452,13 @@ const result = await api.runtime.webSearch.search({
|
||||
});
|
||||
```
|
||||
|
||||
插件也可以通过
|
||||
`api.registerWebSearchProvider(...)` 注册 Web 搜索提供商。
|
||||
插件也可以通过 `api.registerWebSearchProvider(...)` 注册 Web 搜索提供商。
|
||||
|
||||
注意:
|
||||
说明:
|
||||
|
||||
- 将提供商选择、凭据解析和共享请求语义保留在核心中。
|
||||
- 使用 Web 搜索提供商处理厂商专用搜索传输。
|
||||
- `api.runtime.webSearch.*` 是需要搜索行为但不依赖智能体工具包装器的功能/渠道插件的首选共享界面。
|
||||
- 将提供商选择、凭证解析和共享请求语义保留在核心中。
|
||||
- 使用 Web 搜索提供商处理厂商特定的搜索传输。
|
||||
- `api.runtime.webSearch.*` 是需要搜索行为但不依赖智能体工具包装器的功能/渠道插件的首选共享表面。
|
||||
|
||||
### `api.runtime.imageGeneration`
|
||||
|
||||
@ -470,12 +473,12 @@ const providers = api.runtime.imageGeneration.listProviders({
|
||||
});
|
||||
```
|
||||
|
||||
- `generate(...)`:使用已配置的图像生成提供商链生成图像。
|
||||
- `generate(...)`:使用配置的图像生成提供商链生成图像。
|
||||
- `listProviders(...)`:列出可用的图像生成提供商及其能力。
|
||||
|
||||
## Gateway 网关 HTTP 路由
|
||||
|
||||
插件可以使用 `api.registerHttpRoute(...)` 暴露 HTTP 端点。
|
||||
插件可以通过 `api.registerHttpRoute(...)` 暴露 HTTP 端点。
|
||||
|
||||
```ts
|
||||
api.registerHttpRoute({
|
||||
@ -493,119 +496,119 @@ 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`。
|
||||
- 精确的 `path + match` 冲突会被拒绝,除非设置 `replaceExisting: true`,并且一个插件不能替换另一个插件的路由。
|
||||
- 不同 `auth` 级别的重叠路由会被拒绝。请仅在同一认证级别上保留 `exact`/`prefix` 回退链。
|
||||
- `auth: "plugin"` 路由**不会**自动获得操作员运行时作用域。它们用于插件管理的 webhook/签名验证,而不是特权 Gateway 网关辅助调用。
|
||||
- `auth: "gateway"` 路由在 Gateway 网关请求运行时作用域内运行,但该作用域有意保持保守:
|
||||
- shared-secret bearer auth(`gateway.auth.mode = "token"` / `"password"`)会将插件路由运行时作用域固定为 `operator.write`,即使调用方发送了 `x-openclaw-scopes`
|
||||
- 可信且携带身份的 HTTP 模式(例如私有入口上的 `trusted-proxy` 或 `gateway.auth.mode = "none"`)仅在显式存在该请求头时才会遵循 `x-openclaw-scopes`
|
||||
- 除非设置 `replaceExisting: true`,否则会拒绝完全相同的 `path + match` 冲突,并且一个插件不能替换另一个插件的路由。
|
||||
- 会拒绝具有不同 `auth` 级别的重叠路由。只应在相同鉴权级别上保留 `exact`/`prefix` 回退链。
|
||||
- `auth: "plugin"` 路由**不会**自动获得 operator 运行时作用域。它们用于插件管理的 webhook/签名验证,而不是特权 Gateway 网关辅助调用。
|
||||
- `auth: "gateway"` 路由在 Gateway 网关请求运行时作用域内运行,但该作用域刻意保持保守:
|
||||
- shared-secret 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` 请求头约定。
|
||||
- 实用规则:不要假设 Gateway 网关鉴权的插件路由是隐式管理员入口。如果你的路由需要仅限管理员的行为,请要求携带身份的鉴权模式,并记录显式的 `x-openclaw-scopes` 标头契约。
|
||||
|
||||
## 插件 SDK 导入路径
|
||||
|
||||
编写新插件时,请使用较窄的 SDK 子路径,而不是整体式的 `openclaw/plugin-sdk` 根 barrel。核心子路径:
|
||||
编写新插件时,请使用较窄的 SDK 子路径,而不是单体的 `openclaw/plugin-sdk` 根汇总入口。核心子路径:
|
||||
|
||||
| 子路径 | 用途 |
|
||||
| 子路径 | 用途 |
|
||||
| ----------------------------------- | -------------------------------------------------- |
|
||||
| `openclaw/plugin-sdk/plugin-entry` | 插件注册原语 |
|
||||
| `openclaw/plugin-sdk/channel-core` | 渠道入口/构建辅助工具 |
|
||||
| `openclaw/plugin-sdk/core` | 通用共享辅助工具和总括合约 |
|
||||
| `openclaw/plugin-sdk/config-schema` | 根 `openclaw.json` Zod schema(`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`、`agent-runtime`、`lazy-runtime`、`directory-runtime`、`text-runtime`、`runtime-store`、`system-event-runtime`、`heartbeat-runtime`、`channel-activity-runtime` 等)。请优先使用 `config-types`、`plugin-config-runtime`、`runtime-config-snapshot` 和 `config-mutation`,而不是宽泛的 `config-runtime` 兼容 barrel。
|
||||
运行时和配置辅助工具位于对应的聚焦型 `*-runtime` 子路径下(`approval-runtime`、`agent-runtime`、`lazy-runtime`、`directory-runtime`、`text-runtime`、`runtime-store`、`system-event-runtime`、`heartbeat-runtime`、`channel-activity-runtime` 等)。请优先使用 `config-types`、`plugin-config-runtime`、`runtime-config-snapshot` 和 `config-mutation`,而不是宽泛的 `config-runtime` 兼容汇总入口。
|
||||
|
||||
<Info>
|
||||
`openclaw/plugin-sdk/channel-runtime`、`openclaw/plugin-sdk/config-runtime` 和 `openclaw/plugin-sdk/infra-runtime` 是面向旧插件的已弃用兼容垫片。新代码应改为导入更窄的通用原语。
|
||||
</Info>
|
||||
|
||||
仓库内部入口点(按内置插件包根目录):
|
||||
仓库内部入口点(按每个内置插件包根目录):
|
||||
|
||||
- `index.js` — 内置插件入口
|
||||
- `api.js` — 辅助工具/类型 barrel
|
||||
- `runtime-api.js` — 仅运行时 barrel
|
||||
- `api.js` — 辅助工具/类型汇总入口
|
||||
- `runtime-api.js` — 仅运行时汇总入口
|
||||
- `setup-entry.js` — 设置插件入口
|
||||
|
||||
外部插件应只导入 `openclaw/plugin-sdk/*` 子路径。绝不要从核心或另一个插件导入另一个插件包的 `src/*`。通过门面加载的入口点会优先使用有效的运行时配置快照(如果存在),然后回退到磁盘上已解析的配置文件。
|
||||
外部插件只应导入 `openclaw/plugin-sdk/*` 子路径。切勿从核心或另一个插件导入另一个插件包的 `src/*`。通过外观加载的入口点会在存在活动运行时配置快照时优先使用它,然后回退到磁盘上解析出的配置文件。
|
||||
|
||||
诸如 `image-generation`、`media-understanding` 和 `speech` 这类特定能力子路径存在,是因为内置插件目前正在使用它们。它们并不会自动成为长期冻结的外部合约;依赖它们时请查看相关 SDK 参考页。
|
||||
存在 `image-generation`、`media-understanding` 和 `speech` 等特定能力子路径,是因为内置插件目前会使用它们。它们不会自动成为长期冻结的外部契约;依赖它们时请检查相关 SDK 参考页面。
|
||||
|
||||
## 消息工具 schema
|
||||
## 消息工具模式
|
||||
|
||||
插件应拥有针对非消息原语(例如回应、已读和投票)的渠道特定 `describeMessageTool(...)` schema 贡献。共享发送呈现应使用通用 `MessagePresentation` 合约,而不是提供商原生的按钮、组件、块或卡片字段。有关合约、回退规则、提供商映射和插件作者清单,请参见[消息呈现](/zh-CN/plugins/message-presentation)。
|
||||
插件应拥有渠道特定的 `describeMessageTool(...)` 模式贡献,用于 reaction、已读和投票等非消息原语。共享发送呈现应使用通用 `MessagePresentation` 契约,而不是提供商原生的按钮、组件、区块或卡片字段。请参见[消息呈现](/zh-CN/plugins/message-presentation),了解契约、回退规则、提供商映射和插件作者检查清单。
|
||||
|
||||
具备发送能力的插件通过消息能力声明它们可以渲染的内容:
|
||||
|
||||
- `presentation` 用于语义呈现块(`text`、`context`、`divider`、`buttons`、`select`)
|
||||
- `delivery-pin` 用于置顶递送请求
|
||||
- `presentation` 用于语义呈现区块(`text`、`context`、`divider`、`buttons`、`select`)
|
||||
- `delivery-pin` 用于固定投递请求
|
||||
|
||||
核心决定是以原生方式渲染该呈现,还是将其降级为文本。不要从通用消息工具暴露提供商原生 UI 逃生口。面向旧版原生 schema 的已弃用 SDK 辅助工具仍会为现有第三方插件导出,但新插件不应使用它们。
|
||||
核心决定是原生渲染该呈现,还是降级为文本。不要从通用消息工具暴露提供商原生 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` 作为提供商特定的规范化回退,而不是用于宽泛的目录搜索。
|
||||
- 将聊天 ID、话题 ID、JID、句柄和房间 ID 等提供商原生 ID 保留在 `target` 值或提供商特定参数中,不要放入通用 SDK 字段。
|
||||
- 使用 `inferTargetChatType` 处理应在搜索 peer/group 之前发生的类别决策。
|
||||
- 使用 `looksLikeId` 检查“将此视为显式/原生目标 id”。
|
||||
- 使用 `resolveTarget` 作为提供商特定的规范化回退,而不是用于宽泛目录搜索。
|
||||
- 将 chat id、thread id、JID、handle 和 room id 等提供商原生 id 保留在 `target` 值或提供商特定参数中,而不是通用 SDK 字段中。
|
||||
|
||||
## 配置支持的目录
|
||||
|
||||
从配置派生目录条目的插件应将该逻辑保留在插件中,并复用 `openclaw/plugin-sdk/directory-runtime` 中的共享辅助工具。
|
||||
|
||||
当某个渠道需要配置支持的对等方/群组时,请使用这种方式,例如:
|
||||
当渠道需要配置支持的 peer/group 时使用它,例如:
|
||||
|
||||
- 由允许列表驱动的私信对等方
|
||||
- 已配置的渠道/群组映射
|
||||
- 由 allowlist 驱动的私信 peer
|
||||
- 已配置的渠道/group 映射
|
||||
- 账号作用域的静态目录回退
|
||||
|
||||
`directory-runtime` 中的共享辅助工具只处理通用操作:
|
||||
`directory-runtime` 中的共享辅助工具仅处理通用操作:
|
||||
|
||||
- 查询过滤
|
||||
- 限制应用
|
||||
- 去重/规范化辅助工具
|
||||
- 构建 `ChannelDirectoryEntry[]`
|
||||
|
||||
渠道特定的账号检查和 ID 规范化应保留在插件实现中。
|
||||
渠道特定的账号检查和 id 规范化应保留在插件实现中。
|
||||
|
||||
## 提供商目录
|
||||
|
||||
提供商插件可以使用 `registerProvider({ catalog: { run(...) { ... } } })` 定义用于推理的模型目录。
|
||||
提供商插件可以通过 `registerProvider({ catalog: { run(...) { ... } } })` 为推理定义模型目录。
|
||||
|
||||
`catalog.run(...)` 返回的形状与 OpenClaw 写入 `models.providers` 的形状相同:
|
||||
|
||||
- `{ provider }` 用于一个提供商条目
|
||||
- `{ providers }` 用于多个提供商条目
|
||||
- `{ provider }` 表示一个提供商条目
|
||||
- `{ providers }` 表示多个提供商条目
|
||||
|
||||
当插件拥有提供商特定的模型 ID、基础 URL 默认值或受认证保护的模型元数据时,请使用 `catalog`。
|
||||
当插件拥有提供商特定的模型 id、base URL 默认值或受鉴权保护的模型元数据时,请使用 `catalog`。
|
||||
|
||||
`catalog.order` 控制某个插件的目录相对于 OpenClaw 内置隐式提供商合并的时机:
|
||||
`catalog.order` 控制插件目录相对于 OpenClaw 内置隐式提供商的合并时机:
|
||||
|
||||
- `simple`:普通 API key 或环境变量驱动的提供商
|
||||
- `profile`:存在认证配置文件时出现的提供商
|
||||
- `profile`:存在鉴权配置文件时出现的提供商
|
||||
- `paired`:合成多个相关提供商条目的提供商
|
||||
- `late`:最后一轮,在其他隐式提供商之后
|
||||
|
||||
发生键冲突时,后面的提供商胜出,因此插件可以有意用相同的提供商 ID 覆盖内置提供商条目。
|
||||
发生键冲突时,后出现的提供商胜出,因此插件可以有意用相同提供商 id 覆盖内置提供商条目。
|
||||
|
||||
兼容性:
|
||||
|
||||
@ -614,30 +617,30 @@ api.registerHttpRoute({
|
||||
|
||||
## 只读渠道检查
|
||||
|
||||
如果你的插件注册了一个渠道,请优先在 `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(...)` 是运行时路径。它可以假设凭证已完全实体化,并在缺少所需 secret 时快速失败。
|
||||
- `openclaw status`、`openclaw status --all`、`openclaw channels status`、`openclaw channels resolve` 等只读命令路径,以及 Doctor/配置修复流程,不应只是为了描述配置就需要实体化运行时凭证。
|
||||
|
||||
推荐的 `inspectAccount(...)` 行为:
|
||||
建议的 `inspectAccount(...)` 行为:
|
||||
|
||||
- 仅返回描述性账号状态。
|
||||
- 只返回描述性的账号状态。
|
||||
- 保留 `enabled` 和 `configured`。
|
||||
- 在相关时包含凭据来源/状态字段,例如:
|
||||
- 相关时包含凭证来源/状态字段,例如:
|
||||
- `tokenSource`、`tokenStatus`
|
||||
- `botTokenSource`、`botTokenStatus`
|
||||
- `appTokenSource`、`appTokenStatus`
|
||||
- `signingSecretSource`、`signingSecretStatus`
|
||||
- 你不需要为了报告只读可用性而返回原始令牌值。返回 `tokenStatus: "available"`(以及匹配的来源字段)就足以支持状态类命令。
|
||||
- 当凭据通过 SecretRef 配置,但在当前命令路径中不可用时,使用 `configured_unavailable`。
|
||||
- 你不需要为了报告只读可用性而返回原始 token 值。返回 `tokenStatus: "available"`(以及匹配的来源字段)就足够用于 Status 风格的命令。
|
||||
- 当凭证通过 SecretRef 配置但在当前命令路径中不可用时,使用 `configured_unavailable`。
|
||||
|
||||
这样只读命令就可以报告“已配置,但在此命令路径中不可用”,而不是崩溃或误报账号未配置。
|
||||
这样,只读命令可以报告“已配置但在此命令路径中不可用”,而不是崩溃或错误报告账号未配置。
|
||||
|
||||
## 包集合
|
||||
|
||||
插件目录可以包含一个带有 `openclaw.extensions` 的 `package.json`:
|
||||
插件目录可以包含带有 `openclaw.extensions` 的 `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -649,37 +652,37 @@ api.registerHttpRoute({
|
||||
}
|
||||
```
|
||||
|
||||
每个条目都会成为一个插件。如果包列出了多个插件,插件 ID 会变为 `name/<fileBase>`。
|
||||
每个条目都会成为一个插件。如果该集合列出多个扩展,插件 id 会变为 `name/<fileBase>`。
|
||||
|
||||
如果你的插件导入 npm 依赖,请在该目录中安装它们,以便 `node_modules` 可用(`npm install` / `pnpm install`)。
|
||||
|
||||
安全护栏:每个 `openclaw.extensions` 条目在解析符号链接后都必须留在插件目录内。逃出包目录的条目会被拒绝。
|
||||
安全护栏:每个 `openclaw.extensions` 条目在 symlink 解析后都必须留在插件目录内。逃逸出包目录的条目会被拒绝。
|
||||
|
||||
安全说明:`openclaw plugins install` 使用项目本地的 `npm install --omit=dev --ignore-scripts` 安装插件依赖(无生命周期脚本,运行时无开发依赖),并忽略继承的全局 npm 安装设置。保持插件依赖树“纯 JS/TS”,并避免需要 `postinstall` 构建的包。
|
||||
安全说明:`openclaw plugins install` 使用项目本地的 `npm install --omit=dev --ignore-scripts` 安装插件依赖(没有生命周期脚本,运行时没有 dev 依赖),并忽略继承的全局 npm 安装设置。保持插件依赖树为“纯 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 网关方法、工具或服务
|
||||
|
||||
如果你的完整入口仍拥有任何必需的启动能力,请不要启用此标志。保持插件的默认行为,让 OpenClaw 在启动期间加载完整入口。
|
||||
如果你的完整入口仍拥有任何必需的启动能力,请不要启用此标志。保留插件的默认行为,让 OpenClaw 在启动期间加载完整入口。
|
||||
|
||||
内置渠道也可以发布仅设置的合约界面辅助工具,供核心在完整渠道运行时加载前查询。当前的设置提升界面为:
|
||||
内置渠道也可以发布仅设置的契约表面辅助工具,供核心在完整渠道运行时加载前查询。当前设置提升表面为:
|
||||
|
||||
- `singleAccountKeysToMove`
|
||||
- `namedAccountPromotionKeys`
|
||||
- `resolveSingleAccountPromotionTarget(...)`
|
||||
|
||||
当 core 需要在不加载完整插件入口的情况下,将旧版单账号渠道配置提升到 `channels.<id>.accounts.*` 时,会使用这个表面。Matrix 是当前内置示例:当命名账号已经存在时,它只会把身份验证/启动键移动到命名提升账号中,并且可以保留已配置的非规范默认账号键,而不是总是创建 `accounts.default`。
|
||||
核心在需要将旧版单账号渠道配置提升为 `channels.<id>.accounts.*`,但不加载完整插件入口时,会使用该接口。Matrix 是当前的内置示例:当已存在命名账号时,它只会把 auth/bootstrap 键移动到一个命名的提升账号中,并且它可以保留已配置的非规范默认账号键,而不是总是创建 `accounts.default`。
|
||||
|
||||
这些设置补丁适配器会让内置契约表面发现保持惰性。导入时间保持轻量;提升表面只会在首次使用时加载,而不是在模块导入时重新进入内置渠道启动流程。
|
||||
这些设置补丁适配器会让内置契约接口发现保持惰性。导入时间保持轻量;提升接口只会在首次使用时加载,而不是在模块导入时重新进入内置渠道启动流程。
|
||||
|
||||
当这些启动表面包含 Gateway 网关 RPC 方法时,请将它们放在插件专用前缀下。Core 管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)保持保留,并且始终解析为 `operator.admin`,即使某个插件请求了更窄的范围。
|
||||
当这些启动接口包含 Gateway 网关 RPC 方法时,请把它们放在插件专用前缀下。核心管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)保持保留,并且始终解析为 `operator.admin`,即使某个插件请求了更窄的作用域也是如此。
|
||||
|
||||
示例:
|
||||
|
||||
@ -698,7 +701,7 @@ api.registerHttpRoute({
|
||||
|
||||
### 渠道目录元数据
|
||||
|
||||
渠道插件可以通过 `openclaw.channel` 声明设置/设备发现元数据,并通过 `openclaw.install` 声明安装提示。这会让 core 目录不包含数据。
|
||||
渠道插件可以通过 `openclaw.channel` 公告设置/发现元数据,并通过 `openclaw.install` 公告安装提示。这样核心目录就不需要携带数据。
|
||||
|
||||
示例:
|
||||
|
||||
@ -726,38 +729,38 @@ api.registerHttpRoute({
|
||||
}
|
||||
```
|
||||
|
||||
除了最小示例之外,实用的 `openclaw.channel` 字段:
|
||||
除最小示例外,常用的 `openclaw.channel` 字段:
|
||||
|
||||
- `detailLabel`:用于更丰富的目录/Status 表面的次级标签
|
||||
- `detailLabel`:用于更丰富目录/Status 界面的次级标签
|
||||
- `docsLabel`:覆盖文档链接的链接文本
|
||||
- `preferOver`:此目录条目应优先于的较低优先级插件/渠道 ID
|
||||
- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面的文案控制
|
||||
- `markdownCapable`:将渠道标记为支持 Markdown,用于出站格式化决策
|
||||
- `exposure.configured`:设置为 `false` 时,从已配置渠道列表表面隐藏该渠道
|
||||
- `exposure.setup`:设置为 `false` 时,从交互式设置/配置选择器中隐藏该渠道
|
||||
- `exposure.docs`:将渠道标记为文档导航表面的内部/私有渠道
|
||||
- `preferOver`:此目录条目应排在其前面的低优先级插件/渠道 ID
|
||||
- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择界面文案控制项
|
||||
- `markdownCapable`:将该渠道标记为支持 Markdown,用于出站格式决策
|
||||
- `exposure.configured`:设置为 `false` 时,在已配置渠道列表界面中隐藏该渠道
|
||||
- `exposure.setup`:设置为 `false` 时,在交互式设置/配置选择器中隐藏该渠道
|
||||
- `exposure.docs`:将该渠道标记为内部/私有,用于文档导航界面
|
||||
- `showConfigured` / `showInSetup`:为兼容性仍接受的旧版别名;优先使用 `exposure`
|
||||
- `quickstartAllowFrom`:让渠道加入标准快速开始 `allowFrom` 流程
|
||||
- `quickstartAllowFrom`:让该渠道加入标准快速开始 `allowFrom` 流程
|
||||
- `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 是精确版本还是浮动选择器、预期完整性元数据是否存在,以及本地来源路径是否也可用。当目录/包身份已知时,如果解析出的 npm 包名与该身份发生偏移,规范化事实会发出警告。它们还会在 `defaultChoice` 无效或指向不可用来源时发出警告,并在存在 npm 完整性元数据但没有有效 npm 来源时发出警告。消费者应将 `installSource` 视为一个附加的可选字段,这样手写条目和目录垫片就无需合成它。这让新手引导和诊断可以解释来源平面状态,而无需导入插件运行时。
|
||||
生成的渠道目录条目和提供商安装目录条目会在原始 `openclaw.install` 块旁公开规范化的安装来源事实。规范化事实会标识 npm 规格是精确版本还是浮动选择器,是否存在预期完整性元数据,以及是否也有本地来源路径可用。当目录/包身份已知时,如果解析出的 npm 包名偏离该身份,规范化事实会发出警告。当 `defaultChoice` 无效或指向不可用来源,以及存在 npm 完整性元数据但没有有效 npm 来源时,它们也会发出警告。消费者应将 `installSource` 视为可选的增量字段,这样手写条目和目录垫片就不必合成它。这样,新手引导和诊断就能解释来源平面状态,而无需导入插件运行时。
|
||||
|
||||
官方外部 npm 条目应优先使用精确的 `npmSpec` 加 `expectedIntegrity`。裸包名和 dist-tag 仍然可用于兼容性,但它们会显示来源平面警告,以便目录可以逐步转向固定且经过完整性检查的安装,而不破坏现有插件。当新手引导从本地目录路径安装时,它会记录一个托管插件索引条目,其中包含 `source: "path"`,并在可能时包含相对于工作区的 `sourcePath`。绝对操作加载路径仍保留在 `plugins.load.paths` 中;安装记录避免将本地工作站路径重复写入长期配置。这让本地开发安装对来源平面诊断保持可见,同时不会增加第二个原始文件系统路径披露表面。持久化的 `plugins/installs.json` 插件索引是安装来源的事实来源,并且可以在不加载插件运行时模块的情况下刷新。即使插件清单缺失或无效,其 `installRecords` 映射也会持久保留;其 `plugins` 数组是可重建的清单/缓存视图。
|
||||
官方外部 npm 条目应优先使用精确的 `npmSpec` 加 `expectedIntegrity`。裸包名和 dist-tag 仍可用于兼容性,但它们会显示来源平面警告,使目录可以在不破坏现有插件的情况下向固定版本、完整性检查安装迁移。当新手引导从本地目录路径安装时,它会记录一个托管插件索引条目,其中包含 `source: "path"`,并在可能时包含工作区相对的 `sourcePath`。绝对操作加载路径仍保留在 `plugins.load.paths` 中;安装记录避免把本地工作站路径复制到长期配置中。这样,本地开发安装对来源平面诊断保持可见,同时不会增加第二个原始文件系统路径披露界面。持久化的 `plugins/installs.json` 插件索引是安装来源事实来源,并且可以在不加载插件运行时模块的情况下刷新。即使插件清单缺失或无效,它的 `installRecords` 映射也会持久保留;它的 `plugins` 数组是可重建的清单视图。
|
||||
|
||||
## 上下文引擎插件
|
||||
|
||||
上下文引擎插件负责会话上下文的摄取、组装和压缩编排。使用 `api.registerContextEngine(id, factory)` 从你的插件注册它们,然后用 `plugins.slots.contextEngine` 选择活动引擎。
|
||||
上下文引擎插件拥有会话上下文编排,用于摄取、组装和压缩。通过 `api.registerContextEngine(id, factory)` 从你的插件注册它们,然后使用 `plugins.slots.contextEngine` 选择活跃引擎。
|
||||
|
||||
当你的插件需要替换或扩展默认上下文管线,而不只是添加记忆搜索或钩子时,请使用此方式。
|
||||
当你的插件需要替换或扩展默认上下文流水线,而不只是添加记忆搜索或钩子时,请使用这个能力。
|
||||
|
||||
```ts
|
||||
import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
|
||||
@ -787,7 +790,7 @@ export default function (api) {
|
||||
|
||||
工厂 `ctx` 会公开可选的 `config`、`agentDir` 和 `workspaceDir` 值,用于构造时初始化。
|
||||
|
||||
如果你的引擎**不**拥有压缩算法,请保留 `compact()` 实现并显式委托它:
|
||||
如果你的引擎**不**拥有压缩算法,请保留 `compact()` 实现并显式委托:
|
||||
|
||||
```ts
|
||||
import {
|
||||
@ -824,37 +827,37 @@ export default function (api) {
|
||||
|
||||
## 添加新能力
|
||||
|
||||
当插件需要当前 API 无法容纳的行为时,不要通过私有深入访问绕过插件系统。请添加缺失的能力。
|
||||
当插件需要的行为不适合当前 API 时,不要用私有伸入方式绕过插件系统。请添加缺失的能力。
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. 定义 core 契约
|
||||
决定 core 应拥有哪些共享行为:策略、回退、配置合并、生命周期、面向渠道的语义,以及运行时辅助程序形状。
|
||||
2. 添加类型化插件注册/运行时表面
|
||||
使用最小可用的类型化能力表面扩展 `OpenClawPluginApi` 和/或 `api.runtime`。
|
||||
3. 连接 core + 渠道/功能消费者
|
||||
渠道和功能插件应通过 core 使用新能力,而不是直接导入某个厂商实现。
|
||||
4. 注册厂商实现
|
||||
然后由厂商插件针对该能力注册自己的后端。
|
||||
1. 定义核心契约
|
||||
决定核心应拥有哪些共享行为:策略、回退、配置合并、生命周期、面向渠道的语义,以及运行时辅助工具形态。
|
||||
2. 添加类型化插件注册/运行时接口
|
||||
使用最小有用的类型化能力接口扩展 `OpenClawPluginApi` 和/或 `api.runtime`。
|
||||
3. 接入核心 + 渠道/功能消费者
|
||||
渠道和功能插件应通过核心消费新能力,而不是直接导入供应商实现。
|
||||
4. 注册供应商实现
|
||||
然后供应商插件将其后端注册到该能力。
|
||||
5. 添加契约覆盖
|
||||
添加测试,确保所有权和注册形状随时间保持明确。
|
||||
添加测试,使所有权和注册形态随时间保持明确。
|
||||
|
||||
这就是 OpenClaw 保持有主见而不硬编码到某个提供商世界观中的方式。请参阅[能力扩展手册](/zh-CN/plugins/architecture),了解具体的文件检查清单和完整示例。
|
||||
这就是 OpenClaw 保持有主见,同时又不硬编码到某个提供商世界观中的方式。有关具体文件检查清单和完整示例,请参阅[能力扩展手册](/zh-CN/plugins/architecture)。
|
||||
|
||||
### 能力检查清单
|
||||
|
||||
添加新能力时,通常应让实现同时触及这些表面:
|
||||
添加新能力时,通常应一起触及这些界面:
|
||||
|
||||
- `src/<capability>/types.ts` 中的 core 契约类型
|
||||
- `src/<capability>/runtime.ts` 中的 core runner/运行时辅助程序
|
||||
- `src/plugins/types.ts` 中的插件 API 注册表面
|
||||
- `src/<capability>/types.ts` 中的核心契约类型
|
||||
- `src/<capability>/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/` 中的操作员/插件文档
|
||||
|
||||
如果其中某个表面缺失,通常表明该能力尚未完全集成。
|
||||
如果缺少其中某个界面,通常说明该能力尚未完全集成。
|
||||
|
||||
### 能力模板
|
||||
|
||||
@ -892,14 +895,14 @@ expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]);
|
||||
|
||||
这会让规则保持简单:
|
||||
|
||||
- core 拥有能力契约 + 编排
|
||||
- 厂商插件拥有厂商实现
|
||||
- 功能/渠道插件使用运行时辅助程序
|
||||
- 核心拥有能力契约 + 编排
|
||||
- 供应商插件拥有供应商实现
|
||||
- 功能/渠道插件消费运行时辅助工具
|
||||
- 契约测试让所有权保持明确
|
||||
|
||||
## 相关
|
||||
## 相关内容
|
||||
|
||||
- [插件架构](/zh-CN/plugins/architecture) — 公共能力模型和形状
|
||||
- [插件架构](/zh-CN/plugins/architecture) — 公共能力模型和形态
|
||||
- [插件 SDK 子路径](/zh-CN/plugins/sdk-subpaths)
|
||||
- [插件 SDK 设置](/zh-CN/plugins/sdk-setup)
|
||||
- [构建插件](/zh-CN/plugins/building-plugins)
|
||||
|
||||
@ -1,29 +1,29 @@
|
||||
---
|
||||
read_when:
|
||||
- 构建或调试原生 OpenClaw 插件
|
||||
- 了解插件能力模型或所有权边界
|
||||
- 处理插件加载管线或注册表
|
||||
- 理解插件能力模型或所有权边界
|
||||
- 处理插件加载流水线或注册表时
|
||||
- 实现提供商运行时钩子或渠道插件
|
||||
sidebarTitle: Internals
|
||||
summary: 插件内部机制:能力模型、所有权、契约、加载管线和运行时辅助工具
|
||||
summary: 插件内部机制:能力模型、所有权、契约、加载流水线和运行时辅助工具
|
||||
title: 插件内部机制
|
||||
x-i18n:
|
||||
generated_at: "2026-04-28T11:58:02Z"
|
||||
generated_at: "2026-04-29T02:56:07Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: 6afc634508c1d623fa1caceb6b463917f5a8adbaabf42b5381974bd86d117f5d
|
||||
source_hash: 1516e0784a005af87a6c081d8027a1e2dc10445e47b6824488e9d9987bb96975
|
||||
source_path: plugins/architecture.md
|
||||
workflow: 16
|
||||
---
|
||||
|
||||
这是 OpenClaw 插件系统的**深层架构参考**。如需实用指南,请从下面某个聚焦页面开始。
|
||||
这是 OpenClaw 插件系统的**深度架构参考**。如需实践指南,请从下面的专题页面开始。
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="安装和使用插件" icon="plug" href="/zh-CN/tools/plugin">
|
||||
面向最终用户的指南,用于添加、启用和故障排除插件。
|
||||
面向最终用户的指南,用于添加、启用插件并进行故障排除。
|
||||
</Card>
|
||||
<Card title="构建插件" icon="rocket" href="/zh-CN/plugins/building-plugins">
|
||||
使用最小可用清单的第一个插件教程。
|
||||
使用最小可用清单创建第一个插件的教程。
|
||||
</Card>
|
||||
<Card title="渠道插件" icon="comments" href="/zh-CN/plugins/sdk-channel-plugins">
|
||||
构建一个消息渠道插件。
|
||||
@ -38,7 +38,7 @@ x-i18n:
|
||||
|
||||
## 公共能力模型
|
||||
|
||||
能力是 OpenClaw 内部公开的**原生插件**模型。每个原生 OpenClaw 插件都会针对一个或多个能力类型注册:
|
||||
能力是 OpenClaw 内部公开的**原生插件**模型。每个原生 OpenClaw 插件都会注册到一种或多种能力类型:
|
||||
|
||||
| 能力 | 注册方法 | 示例插件 |
|
||||
| ---------------------- | ------------------------------------------------ | ------------------------------------ |
|
||||
@ -54,27 +54,27 @@ x-i18n:
|
||||
| Web 获取 | `api.registerWebFetchProvider(...)` | `firecrawl` |
|
||||
| Web 搜索 | `api.registerWebSearchProvider(...)` | `google` |
|
||||
| 渠道 / 消息 | `api.registerChannel(...)` | `msteams`, `matrix` |
|
||||
| Gateway 网关发现 | `api.registerGatewayDiscoveryService(...)` | `bonjour` |
|
||||
| Gateway 网关设备发现 | `api.registerGatewayDiscoveryService(...)` | `bonjour` |
|
||||
|
||||
<Note>
|
||||
注册零个能力但提供钩子、工具、发现服务或后台服务的插件是**旧版仅钩子**插件。该模式仍受到完全支持。
|
||||
注册零项能力但提供钩子、工具、设备发现服务或后台服务的插件是**仅旧版钩子**插件。这种模式仍然受到完整支持。
|
||||
</Note>
|
||||
|
||||
### 外部兼容性立场
|
||||
|
||||
能力模型已经落地到核心中,并且目前由内置/原生插件使用,但外部插件兼容性仍需要比“它已导出,因此已冻结”更严格的标准。
|
||||
能力模型已经落地到核心中,并且目前由内置/原生插件使用,但外部插件兼容性仍需要比“已导出,因此已冻结”更严格的标准。
|
||||
|
||||
| 插件情况 | 指引 |
|
||||
| 插件情况 | 指导建议 |
|
||||
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| 现有外部插件 | 保持基于钩子的集成可用;这是兼容性基线。 |
|
||||
| 新的内置/原生插件 | 优先使用显式能力注册,而不是特定供应商的内部访问或新的仅钩子设计。 |
|
||||
| 采用能力注册的外部插件 | 允许使用,但除非文档标记为稳定,否则应将特定能力的辅助接口视为仍在演进。 |
|
||||
| 新的内置/原生插件 | 优先使用显式能力注册,而不是供应商特定的直接访问或新的仅钩子设计。 |
|
||||
| 采用能力注册的外部插件 | 允许使用,但除非文档标明稳定,否则应将能力特定的辅助接口视为仍在演进。 |
|
||||
|
||||
能力注册是预期方向。在过渡期间,旧版钩子仍是外部插件最安全的无破坏路径。导出的辅助子路径并不完全等同——应优先使用狭窄且有文档说明的契约,而不是偶然导出的辅助接口。
|
||||
能力注册是预期方向。在过渡期间,旧版钩子仍然是外部插件最安全的无破坏路径。导出的辅助子路径并不完全等价——优先使用范围狭窄且已文档化的契约,而不是偶然导出的辅助接口。
|
||||
|
||||
### 插件形态
|
||||
|
||||
OpenClaw 会根据每个已加载插件的实际注册行为(而不只是静态元数据)将其分类为一种形态:
|
||||
OpenClaw 会根据每个已加载插件的实际注册行为(而不仅仅是静态元数据)将其归类为一种形态:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="plain-capability">
|
||||
@ -84,81 +84,81 @@ OpenClaw 会根据每个已加载插件的实际注册行为(而不只是静
|
||||
注册多种能力类型(例如 `openai` 拥有文本推理、语音、媒体理解和图像生成)。
|
||||
</Accordion>
|
||||
<Accordion title="hook-only">
|
||||
只注册钩子(类型化钩子或自定义钩子),不注册能力、工具、命令或服务。
|
||||
只注册钩子(类型化或自定义),没有能力、工具、命令或服务。
|
||||
</Accordion>
|
||||
<Accordion title="non-capability">
|
||||
注册工具、命令、服务或路由,但不注册能力。
|
||||
注册工具、命令、服务或路由,但没有能力。
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
使用 `openclaw plugins inspect <id>` 查看插件的形态和能力细分。详情见 [CLI 参考](/zh-CN/cli/plugins#inspect)。
|
||||
使用 `openclaw plugins inspect <id>` 查看插件的形态和能力拆解。详见 [CLI 参考](/zh-CN/cli/plugins#inspect)。
|
||||
|
||||
### 旧版钩子
|
||||
|
||||
`before_agent_start` 钩子仍作为仅钩子插件的兼容路径受到支持。旧版真实插件仍依赖它。
|
||||
`before_agent_start` 钩子仍作为仅钩子插件的兼容路径受到支持。真实世界中的旧版插件仍依赖它。
|
||||
|
||||
方向:
|
||||
|
||||
- 保持其可用
|
||||
- 将其记录为旧版
|
||||
- 对于模型/提供商覆盖工作,优先使用 `before_model_resolve`
|
||||
- 对于提示词变更工作,优先使用 `before_prompt_build`
|
||||
- 仅在真实使用量下降且夹具覆盖证明迁移安全后移除
|
||||
- 将其文档化为旧版机制
|
||||
- 对模型/提供商覆盖工作,优先使用 `before_model_resolve`
|
||||
- 对提示词变更工作,优先使用 `before_prompt_build`
|
||||
- 只有在真实使用量下降且 fixture 覆盖证明迁移安全后才移除
|
||||
|
||||
### 兼容性信号
|
||||
|
||||
运行 `openclaw doctor` 或 `openclaw plugins inspect <id>` 时,你可能会看到以下标签之一:
|
||||
|
||||
| 信号 | 含义 |
|
||||
| -------------------------- | ------------------------------------------------------------ |
|
||||
| **配置有效** | 配置解析正常,插件可解析 |
|
||||
| **兼容性建议** | 插件使用受支持但较旧的模式(例如 `hook-only`) |
|
||||
| **旧版警告** | 插件使用已弃用的 `before_agent_start` |
|
||||
| **硬错误** | 配置无效或插件加载失败 |
|
||||
| 信号 | 含义 |
|
||||
| -------------------------- | ---------------------------------------------------------- |
|
||||
| **配置有效** | 配置可以正常解析,插件也能解析 |
|
||||
| **兼容性建议** | 插件使用受支持但较旧的模式(例如 `hook-only`) |
|
||||
| **旧版警告** | 插件使用已弃用的 `before_agent_start` |
|
||||
| **硬错误** | 配置无效,或插件加载失败 |
|
||||
|
||||
`hook-only` 和 `before_agent_start` 现在都不会破坏你的插件:`hook-only` 是建议性提示,而 `before_agent_start` 只会触发警告。这些信号也会出现在 `openclaw status --all` 和 `openclaw plugins doctor` 中。
|
||||
`hook-only` 和 `before_agent_start` 目前都不会破坏你的插件:`hook-only` 只是建议,`before_agent_start` 只会触发警告。这些信号也会出现在 `openclaw status --all` 和 `openclaw plugins doctor` 中。
|
||||
|
||||
## 架构概览
|
||||
|
||||
OpenClaw 的插件系统有四层:
|
||||
|
||||
<Steps>
|
||||
<Step title="清单 + 发现">
|
||||
OpenClaw 会从已配置路径、工作区根目录、全局插件根目录和内置插件中查找候选插件。发现流程会优先读取原生 `openclaw.plugin.json` 清单以及受支持的包清单。
|
||||
<Step title="清单 + 设备发现">
|
||||
OpenClaw 会从已配置路径、工作区根目录、全局插件根目录和内置插件中查找候选插件。设备发现会先读取原生 `openclaw.plugin.json` 清单以及受支持的 bundle 清单。
|
||||
</Step>
|
||||
<Step title="启用 + 验证">
|
||||
核心会决定一个已发现插件是启用、禁用、阻止,还是被选入某个独占槽位,例如内存。
|
||||
核心会决定发现的插件是启用、禁用、阻止,还是被选中用于某个独占槽位,例如 memory。
|
||||
</Step>
|
||||
<Step title="运行时加载">
|
||||
原生 OpenClaw 插件通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容包会被规范化为注册表记录,而不会导入运行时代码。
|
||||
原生 OpenClaw 插件通过 jiti 在进程内加载,并将能力注册到中央注册表。兼容 bundle 会被规范化为注册表记录,而不会导入运行时代码。
|
||||
</Step>
|
||||
<Step title="接口消费">
|
||||
OpenClaw 的其余部分读取注册表,以暴露工具、渠道、提供商设置、钩子、HTTP 路由、CLI 命令和服务。
|
||||
OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、钩子、HTTP 路由、CLI 命令和服务。
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
特别对于插件 CLI,根命令发现分为两个阶段:
|
||||
对于插件 CLI,根命令设备发现特别分为两个阶段:
|
||||
|
||||
- 解析时元数据来自 `registerCli(..., { descriptors: [...] })`
|
||||
- 真正的插件 CLI 模块可以保持懒加载,并在首次调用时注册
|
||||
- 真实的插件 CLI 模块可以保持懒加载,并在首次调用时注册
|
||||
|
||||
这样可以将插件拥有的 CLI 代码留在插件内部,同时仍允许 OpenClaw 在解析前保留根命令名称。
|
||||
这样既能将插件拥有的 CLI 代码保留在插件内部,又能让 OpenClaw 在解析前保留根命令名称。
|
||||
|
||||
重要的设计边界:
|
||||
|
||||
- 清单/配置验证应可基于**清单/schema 元数据**完成,而不执行插件代码
|
||||
- 原生能力发现可以加载受信任的插件入口代码,以构建不激活的注册表快照
|
||||
- 清单/配置验证应当能够基于**清单/schema 元数据**完成,而不执行插件代码
|
||||
- 原生能力发现可以加载可信插件入口代码,以构建一个不会激活的注册表快照
|
||||
- 原生运行时行为来自插件模块的 `register(api)` 路径,并且 `api.registrationMode === "full"`
|
||||
|
||||
这种拆分让 OpenClaw 能够在完整运行时激活前验证配置、解释缺失/禁用的插件,并构建 UI/schema 提示。
|
||||
这种拆分让 OpenClaw 可以在完整运行时激活前验证配置、解释缺失/禁用的插件,并构建 UI/schema 提示。
|
||||
|
||||
### 插件元数据快照和查找表
|
||||
|
||||
Gateway 网关启动时会为当前配置快照构建一个 `PluginMetadataSnapshot`。该快照只包含元数据:它存储已安装插件索引、清单注册表、清单诊断、所有者映射、插件 ID 规范化器和清单记录。它不持有已加载的插件模块、提供商 SDK、包内容或运行时导出。
|
||||
Gateway 网关启动时会为当前配置快照构建一个 `PluginMetadataSnapshot`。该快照仅包含元数据:它存储已安装插件索引、清单注册表、清单诊断、所有者映射、插件 ID 规范化器和清单记录。它不持有已加载的插件模块、提供商 SDK、包内容或运行时导出。
|
||||
|
||||
感知插件的配置验证、启动自动启用和 Gateway 网关插件引导会消费该快照,而不是各自独立重建清单/索引元数据。`PluginLookUpTable` 派生自同一个快照,并为当前运行时配置添加启动插件计划。
|
||||
|
||||
启动后,Gateway 网关会将当前元数据快照保留为可替换的运行时产物。重复的运行时提供商发现可以借用该快照,而不是为每次提供商目录遍历重新构造已安装索引和清单注册表。Gateway 网关关闭、配置/插件清单变化以及已安装索引写入时,该快照会被清除或替换;如果不存在兼容的当前快照,调用方会回退到冷启动清单/索引路径。兼容性检查必须包括插件发现根目录,例如 `plugins.load.paths` 和默认 Agent 工作区,因为工作区插件属于元数据范围。
|
||||
启动后,Gateway 网关会将当前元数据快照保留为可替换的运行时产物。重复的运行时提供商设备发现可以借用该快照,而不必为每次提供商目录遍历重新构建已安装索引和清单注册表。Gateway 网关关闭、配置/插件清单变化以及已安装索引写入时,该快照会被清除或替换;如果不存在兼容的当前快照,调用方会回退到冷启动清单/索引路径。兼容性检查必须包含插件设备发现根目录,例如 `plugins.load.paths` 和默认 Agent 工作区,因为工作区插件属于元数据范围的一部分。
|
||||
|
||||
快照和查找表让重复的启动决策保持在快速路径上:
|
||||
|
||||
@ -170,41 +170,43 @@ Gateway 网关启动时会为当前配置快照构建一个 `PluginMetadataSnaps
|
||||
- 插件配置 schema 和渠道配置 schema 验证
|
||||
- 启动自动启用决策
|
||||
|
||||
安全边界是快照替换,而不是变更。配置、插件清单、安装记录或持久化索引策略发生变化时,应重建快照。不要将其视为宽泛的可变全局注册表,也不要保留无限数量的历史快照。运行时插件加载仍与元数据快照分离,这样过期运行时状态就不能隐藏在元数据缓存后面。
|
||||
安全边界是快照替换,而不是突变。配置、插件清单、安装记录或持久化索引策略变化时,应重建快照。不要把它当作广泛可变的全局注册表,也不要保留无界历史快照。运行时插件加载仍与元数据快照分离,因此过期的运行时状态不能隐藏在元数据缓存后面。
|
||||
|
||||
一些冷路径调用方仍直接从持久化的已安装插件索引重建清单注册表,而不是接收 Gateway 网关 `PluginLookUpTable`。该回退路径会保留一个小型有界内存缓存,其键由已安装索引、请求形态、配置策略、运行时根目录以及清单/包文件签名组成。它是重复索引重建的回退安全网,而不是首选的 Gateway 网关热路径。当调用方已经拥有当前查找表或显式清单注册表时,应优先通过运行时流程传递它。
|
||||
缓存规则记录在[插件架构内部机制](/zh-CN/plugins/architecture-internals#plugin-cache-boundary):除非调用方持有当前流程的显式快照、查找表或清单注册表,否则清单和设备发现元数据始终是新鲜的。隐藏元数据缓存和墙钟 TTL 并不是插件加载的一部分。只有运行时加载器、模块和依赖制品缓存可以在代码或已安装制品实际加载后持续存在。
|
||||
|
||||
一些冷路径调用方仍会直接从持久化的已安装插件索引重建清单注册表,而不是接收 Gateway 网关 `PluginLookUpTable`。该路径现在会按需重建注册表;如果调用方已经有当前查找表或显式清单注册表,运行时流程中应优先传递它们。
|
||||
|
||||
### 激活规划
|
||||
|
||||
激活规划是控制平面的一部分。调用方可以在加载更宽泛的运行时注册表之前,询问哪些插件与具体命令、提供商、渠道、路由、Agent harness 或能力相关。
|
||||
激活规划是控制平面的一部分。调用方可以在加载更广泛的运行时注册表之前,询问哪些插件与具体命令、提供商、渠道、路由、agent harness 或能力相关。
|
||||
|
||||
规划器保持当前清单行为兼容:
|
||||
|
||||
- `activation.*` 字段是显式规划器提示
|
||||
- `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子仍作为清单所有权回退
|
||||
- 仅 ID 的规划器 API 仍可供现有调用方使用
|
||||
- 计划 API 会报告原因标签,以便诊断可以区分显式提示和所有权回退
|
||||
- 计划 API 会报告原因标签,因此诊断可以区分显式提示和所有权回退
|
||||
|
||||
<Warning>
|
||||
不要将 `activation` 视为生命周期钩子或 `register(...)` 的替代品。它是用于缩小加载范围的元数据。当所有权字段已经描述关系时,应优先使用所有权字段;仅将 `activation` 用作额外的规划器提示。
|
||||
不要把 `activation` 当作生命周期钩子或 `register(...)` 的替代品。它是用于缩小加载范围的元数据。当所有权字段已经描述了关系时,优先使用所有权字段;仅将 `activation` 用作额外的规划器提示。
|
||||
</Warning>
|
||||
|
||||
### 渠道插件和共享消息工具
|
||||
|
||||
渠道插件不需要为常规聊天动作注册单独的发送/编辑/回应工具。OpenClaw 在核心中保留一个共享的 `message` 工具,渠道插件负责其背后的渠道特定发现与执行。
|
||||
渠道插件不需要为常规聊天操作注册单独的发送、编辑或反应工具。OpenClaw 在核心中保留一个共享的 `message` 工具,而渠道插件拥有其背后的渠道特定发现和执行逻辑。
|
||||
|
||||
当前边界是:
|
||||
|
||||
- 核心负责共享的 `message` 工具宿主、提示词接线、会话/线程簿记以及执行分发
|
||||
- 渠道插件负责有作用域的动作发现、能力发现以及任何渠道特定的 schema 片段
|
||||
- 渠道插件负责提供商特定的会话对话语法,例如对话 ID 如何编码线程 ID,或如何从父对话继承
|
||||
- 核心拥有共享的 `message` 工具宿主、提示词接线、会话/线程记账以及执行分发
|
||||
- 渠道插件拥有作用域内的动作发现、能力发现以及任何渠道特定的 schema 片段
|
||||
- 渠道插件拥有提供商特定的会话对话语法,例如会话 ID 如何编码线程 ID 或从父会话继承
|
||||
- 渠道插件通过其动作适配器执行最终动作
|
||||
|
||||
对于渠道插件,SDK 表面是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一发现调用让插件可以一起返回其可见动作、能力和 schema 贡献,避免这些部分相互偏离。
|
||||
对于渠道插件,SDK 表面是 `ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用允许插件一起返回其可见动作、能力和 schema 贡献,从而避免这些部分彼此漂移。
|
||||
|
||||
当渠道特定的消息工具参数携带媒体源(例如本地路径或远程媒体 URL)时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心使用这份显式列表来应用沙箱路径规范化和出站媒体访问提示,而不需要硬编码插件拥有的参数名称。此处优先使用按动作限定的映射,而不是一个渠道范围的扁平列表,这样仅用于资料的媒体参数就不会在 `send` 等无关动作上被规范化。
|
||||
当渠道特定的消息工具参数携带媒体源(例如本地路径或远程媒体 URL)时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心使用这个显式列表来应用沙箱路径规范化和出站媒体访问提示,而无需硬编码插件拥有的参数名称。这里优先使用按动作划分的映射,而不是一个渠道级的扁平列表,这样仅用于资料的媒体参数就不会在 `send` 等无关动作上被规范化。
|
||||
|
||||
核心会将运行时作用域传入该发现步骤。重要字段包括:
|
||||
核心会把运行时作用域传入该发现步骤。重要字段包括:
|
||||
|
||||
- `accountId`
|
||||
- `currentChannelId`
|
||||
@ -213,70 +215,70 @@ Gateway 网关启动时会为当前配置快照构建一个 `PluginMetadataSnaps
|
||||
- `sessionKey`
|
||||
- `sessionId`
|
||||
- `agentId`
|
||||
- 可信的入站 `requesterSenderId`
|
||||
- 受信任的入站 `requesterSenderId`
|
||||
|
||||
这对上下文敏感的插件很重要。渠道可以根据当前账号、当前房间/线程/消息,或可信请求者身份来隐藏或暴露消息动作,而无需在核心 `message` 工具中硬编码渠道特定分支。
|
||||
这对上下文敏感的插件很重要。渠道可以基于当前账号、当前房间/线程/消息或受信任的请求者身份来隐藏或公开消息动作,而无需在核心 `message` 工具中硬编码渠道特定分支。
|
||||
|
||||
这就是为什么嵌入式运行器路由变更仍然属于插件工作:运行器负责将当前聊天/会话身份转发到插件发现边界,以便共享的 `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 中狭窄的通用能力。
|
||||
|
||||
内置插件遵循同样的规则。内置插件的 `runtime-api.ts` 不应重新导出自己的品牌化 `openclaw/plugin-sdk/<plugin-id>` facade。这些品牌化 facade 仍然是面向外部插件和旧消费者的兼容垫片,但内置插件应使用本地导出,以及狭窄的通用 SDK 子路径,例如 `openclaw/plugin-sdk/channel-policy`、`openclaw/plugin-sdk/runtime-store` 或 `openclaw/plugin-sdk/webhook-ingress`。新代码不应添加插件 ID 特定的 SDK facade,除非现有外部生态系统的兼容边界需要它。
|
||||
内置插件遵循相同规则。内置插件的 `runtime-api.ts` 不应重新导出自己的品牌化 `openclaw/plugin-sdk/<plugin-id>` facade。这些品牌化 facade 仍然是面向外部插件和旧消费者的兼容性 shim,但内置插件应使用本地导出加上狭窄的通用 SDK 子路径,例如 `openclaw/plugin-sdk/channel-policy`、`openclaw/plugin-sdk/runtime-store` 或 `openclaw/plugin-sdk/webhook-ingress`。新代码不应添加插件 ID 特定的 SDK facade,除非现有外部生态的兼容性边界需要它。
|
||||
|
||||
具体到投票,有两条执行路径:
|
||||
对于投票,具体有两条执行路径:
|
||||
|
||||
- `outbound.sendPoll` 是适用于通用投票模型的渠道的共享基线
|
||||
- `outbound.sendPoll` 是适合通用投票模型的渠道的共享基线
|
||||
- `actions.handleAction("poll")` 是渠道特定投票语义或额外投票参数的首选路径
|
||||
|
||||
核心现在会等到插件投票分发拒绝该动作之后,才执行共享投票解析,因此插件拥有的投票处理器可以接受渠道特定的投票字段,而不会先被通用投票解析器阻挡。
|
||||
核心现在会将共享投票解析延后到插件投票分发拒绝该动作之后,因此插件拥有的投票处理器可以接受渠道特定的投票字段,而不会先被通用投票解析器阻挡。
|
||||
|
||||
完整启动序列见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。
|
||||
|
||||
## 能力所有权模型
|
||||
|
||||
OpenClaw 将原生插件视为一个**公司**或一项**功能**的所有权边界,而不是一组无关集成的大杂烩。
|
||||
OpenClaw 将原生插件视为一个**公司**或一个**功能**的所有权边界,而不是一堆无关集成的大杂烩。
|
||||
|
||||
这意味着:
|
||||
|
||||
- 公司插件通常应拥有该公司面向 OpenClaw 的所有表面
|
||||
- 功能插件通常应拥有它引入的完整功能表面
|
||||
- 渠道应使用共享核心能力,而不是临时重新实现提供商行为
|
||||
- 渠道应消费共享核心能力,而不是临时重新实现提供商行为
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="厂商多能力">
|
||||
`openai` 拥有文本推理、语音、实时语音、媒体理解和图像生成。`google` 拥有文本推理,以及媒体理解、图像生成和 Web 搜索。`qwen` 拥有文本推理,以及媒体理解和视频生成。
|
||||
`openai` 拥有文本推理、语音、实时语音、媒体理解和图像生成。`google` 拥有文本推理以及媒体理解、图像生成和 Web 搜索。`qwen` 拥有文本推理以及媒体理解和视频生成。
|
||||
</Accordion>
|
||||
<Accordion title="厂商单能力">
|
||||
`elevenlabs` 和 `microsoft` 拥有语音;`firecrawl` 拥有 Web 抓取;`minimax` / `mistral` / `moonshot` / `zai` 拥有媒体理解后端。
|
||||
`elevenlabs` 和 `microsoft` 拥有语音;`firecrawl` 拥有 Web 获取;`minimax` / `mistral` / `moonshot` / `zai` 拥有媒体理解后端。
|
||||
</Accordion>
|
||||
<Accordion title="功能插件">
|
||||
`voice-call` 拥有通话传输、工具、CLI、路由和 Twilio 媒体流桥接,但会使用共享语音、实时转录和实时语音能力,而不是直接导入厂商插件。
|
||||
`voice-call` 拥有呼叫传输、工具、CLI、路由和 Twilio 媒体流桥接,但消费共享的语音、实时转录和实时语音能力,而不是直接导入厂商插件。
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
预期的最终状态是:
|
||||
|
||||
- OpenAI 位于一个插件中,即使它横跨文本模型、语音、图像和未来的视频
|
||||
- 另一个厂商也可以对自己的表面区域执行同样做法
|
||||
- 渠道不关心哪个厂商插件拥有该提供商;它们使用核心暴露的共享能力契约
|
||||
- OpenAI 存在于一个插件中,即使它横跨文本模型、语音、图像和未来的视频
|
||||
- 另一个厂商可以对自己的表面区域执行相同做法
|
||||
- 渠道不关心哪个厂商插件拥有提供商;它们消费核心公开的共享能力契约
|
||||
|
||||
关键区别是:
|
||||
|
||||
- **插件** = 所有权边界
|
||||
- **能力** = 多个插件可以实现或使用的核心契约
|
||||
- **能力** = 多个插件可以实现或消费的核心契约
|
||||
|
||||
因此,如果 OpenClaw 添加视频等新领域,第一个问题不是“哪个提供商应该硬编码视频处理?”第一个问题是“核心视频能力契约是什么?”一旦该契约存在,厂商插件就可以针对它注册,渠道/功能插件也可以使用它。
|
||||
因此,如果 OpenClaw 添加了一个新领域(例如视频),第一个问题不是“哪个提供商应硬编码视频处理?”第一个问题是“核心视频能力契约是什么?”一旦该契约存在,厂商插件就可以针对它注册,渠道/功能插件也可以消费它。
|
||||
|
||||
如果该能力尚不存在,正确做法通常是:
|
||||
如果能力尚不存在,正确做法通常是:
|
||||
|
||||
<Steps>
|
||||
<Step title="定义能力">
|
||||
在核心中定义缺失的能力。
|
||||
</Step>
|
||||
<Step title="通过 SDK 暴露">
|
||||
通过插件 API/运行时以类型化方式暴露它。
|
||||
<Step title="通过 SDK 公开">
|
||||
以类型化方式通过插件 API/运行时公开它。
|
||||
</Step>
|
||||
<Step title="接线消费者">
|
||||
将渠道/功能接线到该能力。
|
||||
@ -286,11 +288,11 @@ OpenClaw 将原生插件视为一个**公司**或一项**功能**的所有权边
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
这可以保持所有权明确,同时避免核心行为依赖单个厂商或一次性的插件特定代码路径。
|
||||
这会保持所有权明确,同时避免核心行为依赖单个厂商或一次性的插件特定代码路径。
|
||||
|
||||
### 能力分层
|
||||
|
||||
决定代码归属时,使用这个心智模型:
|
||||
在决定代码归属位置时使用这个心智模型:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="核心能力层">
|
||||
@ -300,21 +302,21 @@ OpenClaw 将原生插件视为一个**公司**或一项**功能**的所有权边
|
||||
厂商特定 API、认证、模型目录、语音合成、图像生成、未来视频后端、用量端点。
|
||||
</Tab>
|
||||
<Tab title="渠道/功能插件层">
|
||||
Slack/Discord/voice-call 等集成,它们使用核心能力并将其呈现在某个表面上。
|
||||
Slack/Discord/voice-call/等集成,消费核心能力并在某个表面上呈现它们。
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
例如,TTS 遵循这个形状:
|
||||
例如,TTS 遵循这种形态:
|
||||
|
||||
- 核心负责回复时 TTS 策略、回退顺序、偏好设置和渠道交付
|
||||
- 核心拥有回复时 TTS 策略、回退顺序、偏好和渠道交付
|
||||
- `openai`、`elevenlabs` 和 `microsoft` 拥有合成实现
|
||||
- `voice-call` 使用电话 TTS 运行时辅助工具
|
||||
- `voice-call` 消费电话 TTS 运行时辅助工具
|
||||
|
||||
未来能力应优先采用同样的模式。
|
||||
同样的模式应优先用于未来能力。
|
||||
|
||||
### 多能力公司插件示例
|
||||
|
||||
公司插件从外部看应具有内聚性。如果 OpenClaw 为模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、Web 抓取和 Web 搜索提供共享契约,厂商就可以在一个地方拥有自己的所有表面:
|
||||
公司插件从外部看应当是内聚的。如果 OpenClaw 对模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、Web 获取和 Web 搜索都有共享契约,厂商就可以在一个地方拥有它的所有表面:
|
||||
|
||||
```ts
|
||||
import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry";
|
||||
@ -368,73 +370,73 @@ const plugin: OpenClawPluginDefinition = {
|
||||
export default plugin;
|
||||
```
|
||||
|
||||
重要的不是精确的辅助工具名称,而是整体形状:
|
||||
重要的不是确切的辅助工具名称,而是形态:
|
||||
|
||||
- 一个插件拥有厂商表面
|
||||
- 核心仍然拥有能力契约
|
||||
- 渠道和功能插件使用 `api.runtime.*` 辅助工具,而不是厂商代码
|
||||
- 契约测试可以断言插件注册了它声称拥有的能力
|
||||
- 渠道和功能插件消费 `api.runtime.*` 辅助工具,而不是厂商代码
|
||||
- 契约测试可以断言该插件注册了它声称拥有的能力
|
||||
|
||||
### 能力示例:视频理解
|
||||
|
||||
OpenClaw 已经将图像/音频/视频理解视为一项共享能力。同样的所有权模型也适用于此:
|
||||
OpenClaw 已经将图像/音频/视频理解视为一个共享能力。相同的所有权模型也适用于那里:
|
||||
|
||||
<Steps>
|
||||
<Step title="核心定义契约">
|
||||
核心定义媒体理解契约。
|
||||
</Step>
|
||||
<Step title="厂商插件注册">
|
||||
厂商插件按适用情况注册 `describeImage`、`transcribeAudio` 和 `describeVideo`。
|
||||
厂商插件按需注册 `describeImage`、`transcribeAudio` 和 `describeVideo`。
|
||||
</Step>
|
||||
<Step title="消费者使用共享行为">
|
||||
渠道和功能插件使用共享核心行为,而不是直接接线到厂商代码。
|
||||
渠道和功能插件消费共享的核心行为,而不是直接接线到厂商代码。
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
这可以避免将某个提供商的视频假设烘焙进核心。插件拥有厂商表面;核心拥有能力契约和回退行为。
|
||||
这避免把某个提供商的视频假设固化到核心中。插件拥有厂商表面;核心拥有能力契约和回退行为。
|
||||
|
||||
视频生成已经使用同样的序列:核心拥有类型化能力契约和运行时辅助工具,厂商插件则针对它注册 `api.registerVideoGenerationProvider(...)` 实现。
|
||||
视频生成已经使用相同序列:核心拥有类型化能力契约和运行时辅助工具,厂商插件针对它注册 `api.registerVideoGenerationProvider(...)` 实现。
|
||||
|
||||
需要具体的推出检查清单?见 [能力扩展手册](/zh-CN/plugins/architecture)。
|
||||
|
||||
## 契约和强制执行
|
||||
|
||||
插件 API 表面有意在 `OpenClawPluginApi` 中进行类型化和集中化。该契约定义受支持的注册点,以及插件可以依赖的运行时辅助工具。
|
||||
插件 API 表面有意在 `OpenClawPluginApi` 中保持类型化和集中化。该契约定义受支持的注册点以及插件可以依赖的运行时辅助工具。
|
||||
|
||||
这很重要的原因:
|
||||
这很重要,因为:
|
||||
|
||||
- 插件作者获得一个稳定的内部标准
|
||||
- 核心可以拒绝重复所有权,例如两个插件注册同一个提供商 ID
|
||||
- 启动过程可以为格式错误的注册显示可操作的诊断
|
||||
- 契约测试可以强制执行内置插件所有权,并防止静默偏移
|
||||
- 启动可以为格式错误的注册公开可操作的诊断信息
|
||||
- 契约测试可以强制执行内置插件所有权并防止静默漂移
|
||||
|
||||
强制执行有两层:
|
||||
有两层强制执行:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="运行时注册强制执行">
|
||||
插件注册表会在插件加载时验证注册。示例:重复的提供商 ID、重复的语音提供商 ID,以及格式错误的注册,会产生插件诊断,而不是未定义行为。
|
||||
<Accordion title="运行时注册强制检查">
|
||||
插件注册表会在插件加载时验证注册。示例:重复的提供商 ID、重复的语音提供商 ID,以及格式错误的注册会产生插件诊断,而不是未定义行为。
|
||||
</Accordion>
|
||||
<Accordion title="契约测试">
|
||||
内置插件会在测试运行期间被捕获到契约注册表中,以便 OpenClaw 可以显式断言所有权。如今这用于模型提供商、语音提供商、Web 搜索提供商和内置注册所有权。
|
||||
内置插件会在测试运行期间被捕获到契约注册表中,以便 OpenClaw 可以明确断言所有权。目前,这用于模型提供商、语音提供商、Web 搜索提供商,以及内置注册所有权。
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
实际效果是,OpenClaw 会预先知道哪个插件拥有哪个表面。这样,核心和渠道就可以无缝组合,因为所有权是声明式、有类型且可测试的,而不是隐式的。
|
||||
实际效果是,OpenClaw 会预先知道哪个插件拥有哪个表面。这让 core 和渠道能够无缝组合,因为所有权是声明式、类型化且可测试的,而不是隐式的。
|
||||
|
||||
### 契约中应包含什么
|
||||
|
||||
<Tabs>
|
||||
<Tab title="良好契约">
|
||||
- 有类型
|
||||
- 小而精
|
||||
- 特定于能力
|
||||
- 由核心拥有
|
||||
- 类型化
|
||||
- 小而聚焦
|
||||
- 面向特定能力
|
||||
- 由 core 拥有
|
||||
- 可被多个插件复用
|
||||
- 可由渠道/功能使用,而无需了解厂商
|
||||
- 可被渠道/功能使用,且不需要厂商知识
|
||||
|
||||
</Tab>
|
||||
<Tab title="不良契约">
|
||||
- 隐藏在核心中的厂商特定策略
|
||||
- 隐藏在 core 中的厂商特定策略
|
||||
- 绕过注册表的一次性插件逃生口
|
||||
- 渠道代码直接访问厂商实现
|
||||
- 不属于 `OpenClawPluginApi` 或 `api.runtime` 的临时运行时对象
|
||||
@ -442,44 +444,44 @@ OpenClaw 已经将图像/音频/视频理解视为一项共享能力。同样的
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
不确定时,提高抽象层级:先定义能力,再让插件接入它。
|
||||
拿不准时,提高抽象层级:先定义能力,再让插件接入它。
|
||||
|
||||
## 执行模型
|
||||
|
||||
原生 OpenClaw 插件与 Gateway 网关**在同一进程内**运行。它们不是沙箱隔离的。已加载的原生插件与核心代码具有相同的进程级信任边界。
|
||||
原生 OpenClaw 插件会与 Gateway 网关**在同一进程内**运行。它们没有经过沙箱隔离。已加载的原生插件与 core 代码具有相同的进程级信任边界。
|
||||
|
||||
<Warning>
|
||||
原生插件的影响:插件可以注册工具、网络处理程序、钩子和服务;插件错误可能导致 Gateway 网关崩溃或不稳定;恶意原生插件等同于在 OpenClaw 进程内执行任意代码。
|
||||
原生插件的影响:插件可以注册工具、网络处理程序、钩子和服务;插件 bug 可能导致 Gateway 网关崩溃或不稳定;恶意原生插件等同于在 OpenClaw 进程内执行任意代码。
|
||||
</Warning>
|
||||
|
||||
兼容包默认更安全,因为 OpenClaw 目前将它们视为元数据/内容包。在当前版本中,这主要意味着内置 Skills。
|
||||
兼容包默认更安全,因为 OpenClaw 目前会将它们视为元数据/内容包。在当前版本中,这主要意味着内置 Skills。
|
||||
|
||||
对非内置插件使用允许列表和显式安装/加载路径。将工作区插件视为开发时代码,而不是生产默认项。
|
||||
对于非内置插件,请使用允许列表和显式安装/加载路径。将工作区插件视为开发时代码,而不是生产默认项。
|
||||
|
||||
对于内置工作区包名称,默认将插件 ID 锚定在 npm 名称中:`@openclaw/<id>`,或者在包有意公开更窄的插件角色时,使用已批准的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`。
|
||||
对于内置工作区包名称,默认让插件 ID 锚定在 npm 名称中:`@openclaw/<id>`,或者在包有意暴露更窄插件角色时使用经批准的类型化后缀,例如 `-provider`、`-plugin`、`-speech`、`-sandbox` 或 `-media-understanding`。
|
||||
|
||||
<Note>
|
||||
**信任注意事项:**`plugins.allow` 信任的是**插件 ID**,不是来源证明。与内置插件具有相同 ID 的工作区插件,在该工作区插件启用/加入允许列表时,会有意遮蔽内置副本。这是正常的,并且对本地开发、补丁测试和热修复很有用。内置插件信任基于源快照来解析,即加载时磁盘上的清单和代码,而不是安装元数据。损坏或被替换的安装记录不能在实际源声明之外,静默扩大内置插件的信任表面。
|
||||
**信任说明:**`plugins.allow` 信任的是**插件 ID**,而不是来源。与内置插件具有相同 ID 的工作区插件,在该工作区插件被启用/加入允许列表时,会有意遮蔽内置副本。这是正常行为,并且对本地开发、补丁测试和热修复很有用。内置插件信任来自源快照,也就是加载时磁盘上的清单和代码,而不是安装元数据。损坏或被替换的安装记录不能静默扩大内置插件的信任表面,使其超出实际源代码声明的范围。
|
||||
</Note>
|
||||
|
||||
## 导出边界
|
||||
|
||||
OpenClaw 导出能力,而不是实现便利项。
|
||||
|
||||
保持能力注册公开。精简非契约辅助导出:
|
||||
保持能力注册为公开接口。裁剪非契约辅助导出:
|
||||
|
||||
- 内置插件特定的辅助子路径
|
||||
- 不打算作为公共 API 的运行时管道子路径
|
||||
- 厂商特定的便利辅助工具
|
||||
- 属于实现细节的设置/新手引导辅助工具
|
||||
- 厂商特定的便利辅助函数
|
||||
- 属于实现细节的设置/新手引导辅助函数
|
||||
|
||||
保留的内置插件辅助子路径已从生成的 SDK 导出映射中退役。将所有者特定的辅助工具保留在所属插件包内;仅将可复用的宿主行为提升为通用 SDK 契约,例如 `plugin-sdk/gateway-runtime`、`plugin-sdk/security-runtime` 和 `plugin-sdk/plugin-config-runtime`。
|
||||
保留的内置插件辅助子路径已从生成的 SDK 导出映射中移除。将所有者特定的辅助函数保留在所属插件包内;只将可复用的宿主行为提升为通用 SDK 契约,例如 `plugin-sdk/gateway-runtime`、`plugin-sdk/security-runtime` 和 `plugin-sdk/plugin-config-runtime`。
|
||||
|
||||
## 内部机制与参考
|
||||
|
||||
有关加载管道、注册表模型、提供商运行时钩子、Gateway 网关 HTTP 路由、消息工具 schema、渠道目标解析、提供商目录、上下文引擎插件,以及添加新能力的指南,请参阅[插件架构内部机制](/zh-CN/plugins/architecture-internals)。
|
||||
有关加载流水线、注册表模型、提供商运行时钩子、Gateway 网关 HTTP 路由、消息工具 schema、渠道目标解析、提供商目录、上下文引擎插件,以及添加新能力的指南,请参阅[插件架构内部机制](/zh-CN/plugins/architecture-internals)。
|
||||
|
||||
## 相关内容
|
||||
## 相关
|
||||
|
||||
- [构建插件](/zh-CN/plugins/building-plugins)
|
||||
- [插件清单](/zh-CN/plugins/manifest)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user