chore(i18n): refresh zh-CN translations

This commit is contained in:
openclaw-docs-i18n[bot] 2026-04-27 16:10:35 +00:00
parent 92d4795a2a
commit 80aebad84c
2 changed files with 426 additions and 448 deletions

View File

@ -1,110 +1,110 @@
---
read_when:
- 实现 provider 运行时钩子、渠道生命周期或包打包
- 实现提供商运行时钩子、渠道生命周期或软件包打包
- 调试插件加载顺序或注册表状态
- 添加新的插件能力或上下文引擎插件
summary: 插件架构内部机制加载流水线、注册表、运行时钩子、HTTP 路由和参考表格
title: 插件架构内部机制
x-i18n:
generated_at: "2026-04-27T12:53:28Z"
generated_at: "2026-04-27T16:07:16Z"
model: gpt-5.4
provider: openai
source_hash: 2c491e72f14cd0cb5673343dd8374e7377f245ac6f0ca94eee954540fd0d7de6
source_hash: 72aac4073018a61d3731a8de54782c63c9ab6e3d21b3af95198adadf8be582f1
source_path: plugins/architecture-internals.md
workflow: 15
---
关于公开的能力模型、插件形状以及归属 / 执行契约,请参见 [Plugin architecture](/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`
5. 决定每个候选项是否启用
6. 加载已启用的原生模块:已构建的内置模块使用原生加载器;未构建的原生插件使用 jiti
4. 规范化插件配置(`plugins.enabled`、`allow`、`deny`、`entries`、`slots`、`load.paths`
5. 为每个候选项决定是否启用
6. 加载已启用的原生模块:已构建的内置模块使用原生加载器;未构建的原生插件使用 `jiti`
7. 调用原生 `register(api)` 钩子,并将注册内容收集到插件注册表中
8. 将注册表暴露给命令 / 运行时表面
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 标签 / 占位符
- 显示安装 / 目录元数据
- 在不加载插件运行时的情况下保留轻量级激活和设置描述符
- 增强 Control UI 标签/占位符
- 显示安装/目录元数据
- 在不加载插件运行时的情况下,保留轻量的激活和设置描述符
对于原生插件,运行时模块是数据平面部分。它会注册实际行为,例如钩子、工具、命令或 provider 流程。
对于原生插件,运行时模块是数据平面部分。它会注册实际行为,例如钩子、工具、命令或提供商流程。
可选的 manifest `activation``setup` 块仍停留在控制平面。它们只是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`首批真实激活使用方现在会利用 manifest 中的命令、渠道和 provider 提示,在更广泛的注册表物化之前缩小插件加载范围:
可选的清单 `activation``setup` 块仍然留在控制平面。它们只是用于激活规划和设置发现的纯元数据描述符;它们不会替代运行时注册、`register(...)` 或 `setupEntry`当前第一批实时激活消费者现在会使用清单中的命令、渠道和提供商提示,在更广泛的注册表实体化之前收窄插件加载范围:
- CLI 加载会缩小到拥有所请求主命令的插件
- 渠道设置 / 插件解析会缩小到拥有所请求渠道 id 的插件
- 显式的 provider 设置 / 运行时解析会缩小到拥有所请求 provider id 的插件
- CLI 加载会收窄到拥有所请求主命令的插件
- 渠道设置/插件解析会收窄到拥有所请求渠道 id 的插件
- 显式的提供商设置/运行时解析会收窄到拥有所请求提供商 id 的插件
激活规划器既暴露一个供现有调用方使用的仅 id API也暴露一个供新诊断使用的计划 API。计划条目会报告插件为何被选中并将显式 `activation.*` 规划器提示与 manifest 所有权回退区分开来,例如 `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` 仅用于仍需要设置阶段运行时钩子的插件。provider 设置列表会使用 manifest `providerAuthChoices`、从描述符导出的设置选项,以及安装目录元数据,而无需加载 provider 运行时。显式 `setup.requiresRuntime: false` 是一个仅描述符层面的截止点;省略 `requiresRuntime` 则会为兼容性保留旧版 `setup-api` 回退。如果发现多个插件声明了相同的标准化设置 provider 或 CLI 后端 id设置查找会拒绝这个有歧义的归属者,而不是依赖发现顺序。当设置运行时确实执行时,注册表诊断会报告 `setup.providers` / `setup.cliBackends` 与通过 setup-api 注册的 provider 或 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 会保留一些短生命周期的进程内缓存,用于:
- 发现结果
- manifest 注册表数据
- 清单注册表数据
- 已加载的插件注册表
这些缓存可减少突发启动开销和重复命令开销。可以将它们视为短期的性能缓存,而不是持久化存储。
这些缓存可减少突发启动开销和重复命令开销。可以将它们理解为短期性能缓存,而不是持久化存储。
Gateway 网关热路径应优先使用当前 `PluginLookUpTable`,或通过调用链显式传递的 manifest 注册表。对于那些仍会从持久化的已安装插件索引重建 manifest 元数据的调用方OpenClaw 还会保留一个小型有界回退缓存,其键包括已安装索引、请求形状、配置策略、运行时根目录以及 manifest / package 文件签名。该缓存只是重复进行已安装索引重建时的回退手段;它不是一个可变的运行时插件注册表。
Gateway 网关启动热路径应优先使用当前的 `PluginMetadataSnapshot`、派生的 `PluginLookUpTable`或通过调用链传递的显式清单注册表。配置验证、启动时自动启用和插件引导在可用时都会使用同一个快照。对于那些仍然会从持久化的已安装插件索引重新构建清单元数据的调用方OpenClaw 还会保留一个小型有界回退缓存,键由已安装索引、请求形态、配置策略、运行时根目录以及清单/软件包文件签名组成。该缓存仅用于重复的已安装索引重建回退;它不是可变的运行时插件注册表。
性能说明:
- 设置 `OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1``OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1` 可禁用这些缓存。
- 设置 `OPENCLAW_DISABLE_INSTALLED_PLUGIN_MANIFEST_REGISTRY_CACHE=1` 可仅禁用已安装索引 manifest 注册表回退缓存。
- 设置 `OPENCLAW_DISABLE_INSTALLED_PLUGIN_MANIFEST_REGISTRY_CACHE=1` 可仅禁用已安装索引的清单注册表回退缓存。
- 使用 `OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS``OPENCLAW_PLUGIN_MANIFEST_CACHE_MS` 调整缓存窗口。
## 注册表模型
已加载的插件不会直接修改各种随机的 core 全局状态。它们会注册到一个中央插件注册表中。
已加载的插件不会直接修改随意的核心全局状态。它们会注册到一个中心化的插件注册表中。
注册表会跟踪:
- 插件记录(身份、来源、起源、状态、诊断)
- 插件记录(标识、来源、源头、状态、诊断)
- 工具
- 旧版钩子和类型化钩子
- 渠道
- provider
- 提供商
- Gateway 网关 RPC 处理器
- HTTP 路由
- CLI 注册器
- 后台服务
- 插件拥有的命令
然后 core 功能会从该注册表读取,而不是直接与插件模块交互。这样可以保持单向加载
随后,核心功能会从该注册表读取,而不是直接与插件模块通信。这样可以保持加载方向单向
- 插件模块 -> 注册表注册
- core 运行时 -> 注册表消费
- 核心运行时 -> 注册表消费
这种分离对于可维护性很重要。这意味着大多数 core 表面只需要一个集成点:“读取注册表”,而不是“为每个插件模块做特殊处理”。
这种分离对于可维护性很重要。这意味着大多数核心表面只需要一个集成点:“读取注册表”,而不是“为每个插件模块做特殊处理”。
## 会话绑定回调
绑定会话的插件可以在审批结果确定后作出响应。
使用 `api.onConversationBindingResolved(...)` 可在绑定请求被批准或拒绝后接收回调:
使用 `api.onConversationBindingResolved(...)`可在绑定请求被批准或拒绝后接收回调:
```ts
export default {
@ -112,105 +112,101 @@ 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);
});
},
};
```
回调载字段:
回调载字段:
- `status``"approved"` 或 `"denied"`
- `decision``"allow-once"`、`"allow-always"` 或 `"deny"`
- `binding`:已批准请求的已解析绑定
- `request`:原始请求摘要、detach 提示、发送方 id 和会话元数据
- `binding`:已批准请求对应的已解析绑定
- `request`:原始请求摘要、分离提示、发送者 id 和会话元数据
该回调仅用于通知。它不会改变谁被允许绑定会话,并且会在 core 审批处理完成后运行。
该回调仅用于通知。它不会改变谁被允许绑定会话,并且会在核心审批处理完成后运行。
## provider 运行时钩子
## 提供商运行时钩子
provider 插件有三层:
提供商插件有三层:
- **manifest 元数据**,用于低成本的运行前查找:
`setup.providers[].envVars`、已弃用的兼容字段 `providerAuthEnvVars`
`providerAuthAliases`、`providerAuthChoices` 和 `channelEnvVars`
- **配置时钩子**`catalog`(旧称 `discovery`)以及
`applyConfigDefaults`
- **运行时钩子**40 多个可选钩子,涵盖鉴权、模型解析、
流包装、思考等级、重放策略和 usage 端点。完整列表见
[Hook order and usage](#hook-order-and-usage)。
- **清单元数据**,用于轻量的运行时前查找:
`setup.providers[].envVars`、已弃用的兼容字段 `providerAuthEnvVars`、`providerAuthAliases`、`providerAuthChoices` 和 `channelEnvVars`
- **配置时钩子**`catalog`(旧称 `discovery`)以及 `applyConfigDefaults`
- **运行时钩子**40 多个可选钩子,涵盖认证、模型解析、流包装、思考级别、重放策略和用量端点。完整列表请参见下方的 [钩子顺序和用法](#hook-order-and-usage)。
OpenClaw 仍然负责通用的 Agent loop、故障切换、转录处理和工具策略。这些钩子是在无需实现整套自定义推理传输层的情况下扩展 provider 特定行为的表面
OpenClaw 仍然负责通用的智能体循环、故障切换、转录处理和工具策略。这些钩子是提供商特定行为的扩展表面,无需为此实现一整套自定义推理传输。
provider 具有基于环境变量的凭证,并且需要让通用鉴权 / Status / 模型选择器路径在不加载 provider 运行时的情况下也能看到这些信息时,请使用 manifest `setup.providers[].envVars`。在弃用窗口内,已弃用的 `providerAuthEnvVars` 仍会被兼容适配器读取,而使用它的非内置插件会收到 manifest 诊断。当某个 provider id 需要复用另一个 provider id 的环境变量、auth profile、基于配置的鉴权以及 API key 新手引导选项时,请使用 manifest `providerAuthAliases`。当新手引导 / 鉴权选项 CLI 表面需要在不加载 provider 运行时的情况下知道该 provider 的选项 id、分组标签和简单的单标志鉴权接线时请使用 manifest `providerAuthChoices`。请将 provider 运行时 `envVars` 保留给面向操作者的提示,例如新手引导标签或 OAuth client-id / client-secret 设置变量。
当某个提供商具有基于环境变量的凭证,并且你希望通用的认证/Status/模型选择器路径在不加载提供商运行时的情况下也能看到这些凭证时,请使用清单 `setup.providers[].envVars`。在弃用窗口期间,兼容性适配器仍会读取已弃用的 `providerAuthEnvVars`,而使用它的非内置插件会收到一条清单诊断。当某个提供商 id 应复用另一个提供商 id 的环境变量、认证配置文件、基于配置的认证以及 API key 新手引导选项时,请使用清单 `providerAuthAliases`。当新手引导/认证选择 CLI 表面需要在不加载提供商运行时的情况下了解该提供商的选项 id、分组标签和简单的单标志认证接线时请使用清单 `providerAuthChoices`。请将提供商运行时的 `envVars` 保留给面向操作者的提示,例如新手引导标签或 OAuth client id/client secret 设置变量。
当某个渠道具有由环境变量驱动的鉴权或设置,并且需要让通用 shell 环境变量回退、配置 / 状态检查或设置提示在不加载渠道运行时的情况下也能看到这些信息时,请使用 manifest `channelEnvVars`
当某个渠道具有由环境变量驱动的认证或设置,并且你希望通用 shell 环境变量回退、配置/Status 检查或设置提示在不加载渠道运行时的情况下也能看到这些内容时,请使用清单 `channelEnvVars`
### 钩子顺序与使用方式
### 钩子顺序和用法
对于模型 / provider 插件OpenClaw 大致按以下顺序调用钩子。
“何时使用”这一列是快速决策指南。
对于模型/提供商插件OpenClaw 大致会按以下顺序调用钩子。
“何时使用”列是快速决策指南。
| # | 钩子 | 作用 | 何时使用 |
| # | 钩子 | 作用 | 何时使用 |
| --- | --------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `catalog` | 在生成 `models.json` 时将 provider 配置发布到 `models.providers` 中 | provider 拥有目录或 `baseUrl` 默认值 |
| 2 | `applyConfigDefaults` | 在配置物化期间应用 provider 拥有的全局配置默认值 | 默认值依赖于鉴权模式、环境变量或 provider 模型族语义 |
| -- | _(内置模型查找)_ | OpenClaw 会先尝试常规注册表 / 目录路径 | _(不是插件钩子)_ |
| 3 | `normalizeModelId` | 在查找前标准化旧版或预览版模型 id 别名 | provider 在规范模型解析前拥有别名清理逻辑 |
| 4 | `normalizeTransport` | 在通用模型组装前标准化 provider 族的 `api` / `baseUrl` | provider 在同一传输族内为自定义 provider id 提供传输清理逻辑 |
| 5 | `normalizeConfig` | 在运行时 / provider 解析前标准化 `models.providers.<id>` | provider 需要将配置清理逻辑放在插件内;内置的 Google 族辅助逻辑也会为受支持的 Google 配置条目提供兜底 |
| 6 | `applyNativeStreamingUsageCompat` | 对配置 provider 应用原生流式 usage 兼容性重写 | provider 需要基于端点的原生流式 usage 元数据修复 |
| 7 | `resolveConfigApiKey` | 在运行时鉴权加载前,为配置 provider 解析环境标记鉴权 | provider 具有由 provider 自身拥有的环境标记 API key 解析逻辑;`amazon-bedrock` 在这里也有一个内置 AWS 环境标记解析器 |
| 8 | `resolveSyntheticAuth` | 在不持久化明文的情况下暴露本地 / 自托管或基于配置的鉴权 | provider 可以使用合成 / 本地凭证标记运行 |
| 9 | `resolveExternalAuthProfiles` | 覆盖 provider 拥有的外部 auth profile对于 CLI / 应用拥有的凭证,默认 `persistence``runtime-only` | provider 复用外部鉴权凭证,而不持久化复制的刷新令牌;请在 manifest 中声明 `contracts.externalAuthProviders` |
| 10 | `shouldDeferSyntheticProfileAuth` | 将已存储的合成 profile 占位符优先级降到环境变量 / 配置支持的鉴权之后 | provider 存储的合成占位 profile 不应获得更高优先级 |
| 11 | `resolveDynamicModel` | 对本地注册表中尚不存在的 provider 拥有模型 id 执行同步回退解析 | provider 接受任意上游模型 id |
| 12 | `prepareDynamicModel` | 先执行异步预热,然后再次运行 `resolveDynamicModel` | provider 在解析未知 id 前需要网络元数据 |
| 13 | `normalizeResolvedModel` | 在嵌入式 runner 使用已解析模型前做最终重写 | provider 需要传输重写,但仍使用 core 传输 |
| 14 | `contributeResolvedModelCompat` | 为位于另一种兼容传输之后的厂商模型提供兼容标记 | provider 能在不接管 provider 本身的情况下识别代理传输中的自家模型 |
| 15 | `capabilities` | 由共享 core 逻辑使用的 provider 自有转录 / 工具元数据 | provider 需要处理转录 / provider 族怪癖 |
| 16 | `normalizeToolSchemas` | 在嵌入式 runner 看到工具 schema 之前对其进行标准化 | provider 需要传输族 schema 清理 |
| 17 | `inspectToolSchemas` | 在标准化之后暴露 provider 自有的 schema 诊断 | provider 想提供关键字警告,而不需要让 core 学习 provider 特定规则 |
| 18 | `resolveReasoningOutputMode` | 选择原生还是带标签的推理输出契约 | provider 需要使用带标签的推理 / 最终输出,而不是原生字段 |
| 19 | `prepareExtraParams` | 在通用流选项包装器之前做请求参数标准化 | provider 需要默认请求参数或每 provider 参数清理 |
| 20 | `createStreamFn` | 使用自定义传输完全替换常规流路径 | provider 需要自定义线协议,而不仅仅是包装器 |
| 21 | `wrapStreamFn` | 在应用通用包装器后再包装流函数 | provider 需要请求头 / 请求体 / 模型兼容包装器,但不需要自定义传输 |
| 22 | `resolveTransportTurnState` | 附加原生的每轮传输请求头或元数据 | provider 希望通用传输发送 provider 原生的轮次身份信息 |
| 23 | `resolveWebSocketSessionPolicy` | 附加原生 WebSocket 请求头或会话冷却策略 | provider 希望通用 WS 传输调整会话请求头或回退策略 |
| 24 | `formatApiKey` | auth profile 格式化器:已存储 profile 会变成运行时 `apiKey` 字符串 | provider 存储额外的鉴权元数据,并需要自定义的运行时令牌形状 |
| 25 | `refreshOAuth` | 针对自定义刷新端点或刷新失败策略的 OAuth 刷新覆盖 | provider 不适配共享的 `pi-ai` 刷新器 |
| 26 | `buildAuthDoctorHint` | 当 OAuth 刷新失败时追加的修复提示 | provider 需要在刷新失败后提供 provider 自有的鉴权修复指引 |
| 27 | `matchesContextOverflowError` | provider 自有的上下文窗口溢出错误匹配器 | provider 存在通用启发式无法捕获的原始溢出错误 |
| 28 | `classifyFailoverReason` | provider 自有的故障切换原因分类 | provider 可以将原始 API / 传输错误映射为限流 / 过载等 |
| 29 | `isCacheTtlEligible` | 面向代理 / 回传 provider 的提示缓存策略 | provider 需要代理特定的缓存 TTL 门控 |
| 30 | `buildMissingAuthMessage` | 替代通用的缺失鉴权恢复消息 | provider 需要 provider 特定的缺失鉴权恢复提示 |
| 31 | `suppressBuiltInModel` | 过时上游模型抑制,并可选提供面向用户的错误提示 | provider 需要隐藏过时的上游条目,或用厂商提示替换它们 |
| 32 | `augmentModelCatalog` | 在发现之后附加合成 / 最终目录条目 | provider 需要在 `models list` 和选择器中提供合成的前向兼容条目 |
| 33 | `resolveThinkingProfile` | 特定模型的 `/think` 级别集合、显示标签和默认值 | provider 为选定模型暴露自定义思考阶梯或二元标签 |
| 34 | `isBinaryThinking` | 开 / 关推理切换兼容性钩子 | provider 只暴露二元的思考开 / 关 |
| 35 | `supportsXHighThinking` | `xhigh` 推理支持兼容性钩子 | provider 希望仅在部分模型上提供 `xhigh` |
| 36 | `resolveDefaultThinkingLevel` | 默认 `/think` 级别兼容性钩子 | provider 为某个模型族拥有默认 `/think` 策略 |
| 37 | `isModernModelRef` | 用于实时 profile 过滤和 smoke 选择的现代模型匹配器 | provider 拥有实时 / smoke 首选模型匹配逻辑 |
| 38 | `prepareRuntimeAuth` | 在推理前将已配置凭证交换为实际运行时令牌 / key | provider 需要令牌交换或短生命周期请求凭证 |
| 39 | `resolveUsageAuth` | 为 `/usage` 及相关 Status 表面解析 usage / 计费凭证 | provider 需要自定义 usage / 配额令牌解析,或使用不同的 usage 凭证 |
| 40 | `fetchUsageSnapshot` | 在鉴权解析后抓取并标准化 provider 特定的 usage / 配额快照 | provider 需要 provider 特定的 usage 端点或载荷解析器 |
| 41 | `createEmbeddingProvider` | 为内存 / 搜索构建 provider 拥有的 embedding 适配器 | Memory embedding 行为应归属于 provider 插件 |
| 42 | `buildReplayPolicy` | 返回一个重放策略,用于控制该 provider 的转录处理 | provider 需要自定义转录策略(例如移除 thinking 块) |
| 43 | `sanitizeReplayHistory` | 在通用转录清理之后重写重放历史 | provider 需要超出共享压缩辅助之外的 provider 特定重放重写 |
| 44 | `validateReplayTurns` | 在嵌入式 runner 之前对重放轮次做最终校验或重塑 | provider 传输在通用清理之后需要更严格的轮次校验 |
| 45 | `onModelSelected` | 在模型被选中后运行 provider 拥有的副作用 | provider 在模型变为活动状态时需要遥测或 provider 拥有的状态 |
| 1 | `catalog` | 在生成 `models.json` 时,将提供商配置发布到 `models.providers` 中 | 提供商拥有目录或基础 `base URL` 默认值 |
| 2 | `applyConfigDefaults` | 在配置实体化期间应用提供商拥有的全局配置默认值 | 默认值依赖于认证模式、环境变量或提供商模型族语义 |
| -- | _(内置模型查找)_ | OpenClaw 会先尝试常规注册表/目录路径 | _(不是插件钩子)_ |
| 3 | `normalizeModelId` | 在查找前规范化旧版或预览版模型 id 别名 | 提供商拥有在规范模型解析前进行别名清理的逻辑 |
| 4 | `normalizeTransport` | 在通用模型组装前规范化提供商族的 `api` / `baseUrl` | 提供商拥有对同一传输族中自定义提供商 id 的传输清理逻辑 |
| 5 | `normalizeConfig` | 在运行时/提供商解析前规范化 `models.providers.<id>` | 提供商需要将配置清理逻辑保留在插件中;内置的 Google 族辅助逻辑也会为受支持的 Google 配置项提供兜底支持 |
| 6 | `applyNativeStreamingUsageCompat` | 对配置提供商应用原生流式用量兼容性重写 | 提供商需要基于端点的原生流式用量元数据修复 |
| 7 | `resolveConfigApiKey` | 在加载运行时认证前,为配置提供商解析 env-marker 认证 | 提供商拥有其自有的 env-marker API key 解析逻辑;`amazon-bedrock` 在这里也有一个内置的 AWS env-marker 解析器 |
| 8 | `resolveSyntheticAuth` | 在不持久化明文的情况下暴露 local/self-hosted 或基于配置的认证 | 提供商可以通过合成/local 凭证标记运行 |
| 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` | 用于实时配置文件过滤和冒烟测试选择的 modern-model 匹配器 | 提供商拥有实时/冒烟首选模型匹配逻辑 |
| 38 | `prepareRuntimeAuth` | 在推理前将已配置的凭证交换为实际运行时令牌/API key | 提供商需要令牌交换或短生命周期的请求凭证 |
| 39 | `resolveUsageAuth` | 为 `/usage` 和相关 Status 表面解析用量/计费凭证 | 提供商需要自定义用量/配额令牌解析,或需要不同的用量凭证 |
| 40 | `fetchUsageSnapshot` | 在认证解析后获取并规范化提供商特定的用量/配额快照 | 提供商需要提供商特定的用量端点或负载解析器 |
| 41 | `createEmbeddingProvider` | 为 memory/search 构建提供商拥有的嵌入适配器 | Memory 嵌入行为应归属于提供商插件 |
| 42 | `buildReplayPolicy` | 返回一个重放策略,用于控制该提供商的转录处理 | 提供商需要自定义转录策略(例如剥离 thinking 块) |
| 43 | `sanitizeReplayHistory` | 在通用转录清理后重写重放历史 | 提供商在共享压缩辅助逻辑之外还需要提供商特定的重放重写 |
| 44 | `validateReplayTurns` | 在嵌入式运行器之前,对重放轮次做最终校验或重塑 | 提供商传输在通用清理后需要更严格的轮次校验 |
| 45 | `onModelSelected` | 在模型被选中后运行提供商拥有的副作用 | 当某个模型变为活动状态时,提供商需要遥测或提供商拥有的状态 |
`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查匹配到的 provider 插件,然后继续回退到其他具备对应钩子能力的 provider 插件,直到某个插件实际更改了模型 id 或传输 / 配置。这样可以让别名 / 兼容 provider shim 正常工作,而不要求调用方知道哪个内置插件拥有该重写逻辑。如果没有任何 provider 钩子重写某个受支持的 Google 族配置条目,内置的 Google 配置标准化器仍会执行该兼容性清理。
`normalizeModelId`、`normalizeTransport` 和 `normalizeConfig` 会先检查已匹配的提供商插件,然后再回退到其他具备钩子能力的提供商插件,直到某个插件实际更改了模型 id 或传输/配置为止。这样可以让别名/兼容性提供商 shim 继续工作,而不要求调用方知道是哪个内置插件拥有该重写逻辑。如果没有任何提供商钩子重写受支持的 Google 族配置项,内置的 Google 配置规范化器仍会应用该兼容性清理。
如果 provider 需要完全自定义的线协议或自定义请求执行器,那属于另一类扩展。这些钩子适用于仍运行在 OpenClaw 常规推理循环上的 provider 行为。
如果提供商需要完全自定义的线协议或自定义请求执行器,那就是另一类扩展。这些钩子适用于仍运行在 OpenClaw 常规推理循环上的提供商行为。
### provider 示例
### 提供商示例
```ts
api.registerProvider({
@ -266,41 +262,29 @@ api.registerProvider({
### 内置示例
内置 provider 插件会组合使用上述钩子,以适配各厂商在目录、鉴权、思考、重放和 usage 方面的需求。权威钩子集合位于 `extensions/` 下各插件自身;本页只说明其形状,而不是镜像那份列表。
内置的提供商插件会组合上述钩子,以适配各个厂商的目录、认证、思考、重放和用量需求。权威的钩子集合位于每个 `extensions/` 下的插件中;本页用于说明这些形态,而不是镜像完整列表。
<AccordionGroup>
<Accordion title="透传目录 provider">
OpenRouter、Kilocode、Z.AI、xAI 会注册 `catalog`,以及
`resolveDynamicModel` / `prepareDynamicModel`,这样它们就可以在
OpenClaw 静态目录之前暴露上游模型 id。
<Accordion title="直通目录提供商">
OpenRouter、Kilocode、Z.AI、xAI 会注册 `catalog`,以及 `resolveDynamicModel` / `prepareDynamicModel`,以便在 OpenClaw 的静态目录之前暴露上游模型 id。
</Accordion>
<Accordion title="OAuth 和 usage 端点 provider">
GitHub Copilot、Gemini CLI、ChatGPT Codex、MiniMax、Xiaomi、z.ai 将
`prepareRuntimeAuth``formatApiKey``resolveUsageAuth` +
`fetchUsageSnapshot` 配对使用,以自行处理令牌交换和 `/usage` 集成。
<Accordion title="OAuth 和用量端点提供商">
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`)允许 provider 通过
`buildReplayPolicy` 选择加入转录策略,而不必让每个插件都重新实现清理逻辑。
<Accordion title="重放与转录清理族">
共享的命名族(`google-gemini`、`passthrough-gemini`、`anthropic-by-model`、`hybrid-anthropic-openai`)允许提供商通过 `buildReplayPolicy` 选择转录策略,而不是让每个插件都重新实现清理逻辑。
</Accordion>
<Accordion title="仅目录 provider">
`byteplus`、`cloudflare-ai-gateway`、`huggingface`、`kimi-coding`、`nvidia`、
`qianfan`、`synthetic`、`together`、`venice`、`vercel-ai-gateway` 和
`volcengine` 只注册 `catalog`,并复用共享推理循环。
<Accordion title="仅目录提供商">
`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 专用流辅助工具">
Beta 请求头、`/fast` / `serviceTier` 以及 `context1m` 位于 Anthropic 插件公开的 `api.ts` / `contract-api.ts` 接缝中(`wrapAnthropicProviderStream`、`resolveAnthropicBetas`、`resolveAnthropicFastMode`、`resolveAnthropicServiceTier`),而不是放在通用 SDK 中。
</Accordion>
</AccordionGroup>
## 运行时辅助
## 运行时辅助工具
插件可以通过 `api.runtime` 访问部分选定的 core 辅助。对于 TTS
插件可以通过 `api.runtime` 访问选定的核心辅助工具。对于 TTS
```ts
const clip = await api.runtime.tts.textToSpeech({
@ -321,14 +305,14 @@ const voices = await api.runtime.tts.listVoices({
说明:
- `textToSpeech` 返回适用于文件 / 语音消息表面的常规 core TTS 输出载荷
- 使用 core `messages.tts` 配置和 provider 选择逻辑
- 返回 PCM 音频缓冲区和采样率。插件必须为 provider 自行重采样 / 编码。
- `listVoices` 对每个 provider 来说是可选的。将其用于厂商自有语音选择器或设置流程。
- 语音列表可包含更丰富的元数据,例如区域设置、性别和个性标签,供 provider 感知的选择器使用
- 目前支持电话语音的是 OpenAI 和 ElevenLabs。Microsoft 不支持。
- `textToSpeech` 返回用于文件/语音便笺表面的常规核心 TTS 输出负载
- 使用核心 `messages.tts` 配置和提供商选择
- 返回 PCM 音频缓冲区 + 采样率。插件必须为提供商自行重采样/编码。
- `listVoices` 对每个提供商来说都是可选的。可将其用于厂商拥有的语音选择器或设置流程。
- 语音列表可以包含更丰富的元数据,例如语言区域、性别和个性标签,以支持具备提供商感知能力的选择器
- 目前 OpenAI 和 ElevenLabs 支持电话语音。Microsoft 不支持。
插件也可以通过 `api.registerSpeechProvider(...)` 注册语音 provider
插件也可以通过 `api.registerSpeechProvider(...)` 注册语音提供商
```ts
api.registerSpeechProvider({
@ -348,12 +332,12 @@ api.registerSpeechProvider({
说明:
- 将 TTS 策略、回退和回复投递保留在 core 中。
- 语音 provider 用于厂商自有的语音合成行为。
- 旧版 Microsoft `edge` 输入会被标准化为 `microsoft` provider id。
- 推荐的归属模型是面向公司的:随着 OpenClaw 增加这些能力契约,一个厂商插件可以同时拥有文本、语音、图像以及未来的媒体 provider
- 将 TTS 策略、回退和回复投递保留在核心中。
- 语音提供商用于厂商拥有的语音合成行为。
- 旧版 Microsoft `edge` 输入会规范化为 `microsoft` 提供商 id。
- 更推荐的所有权模型是面向公司:随着 OpenClaw 增加这些能力契约,一个厂商插件可以同时拥有文本、语音、图像以及未来的媒体提供商
对于图像 / 音频 / 视频理解,插件会注册一个类型化的媒体理解 provider而不是通用的键 / 值包:
对于图像/音频/视频理解,插件会注册一个类型化的媒体理解提供商,而不是通用的键值包:
```ts
api.registerMediaUnderstandingProvider({
@ -367,15 +351,15 @@ api.registerMediaUnderstandingProvider({
说明:
- 将编排、回退、配置和渠道接线保留在 core 中。
- 将厂商行为保留在 provider 插件中。
- 将编排、回退、配置和渠道接线保留在核心中。
- 将厂商行为保留在提供商插件中。
- 增量扩展应保持类型化:新的可选方法、新的可选结果字段、新的可选能力。
- 视频生成已经遵循同样的模式:
- core 拥有能力契约和运行时辅助
- 视频生成已经遵循同模式:
- 核心拥有能力契约和运行时辅助工具
- 厂商插件注册 `api.registerVideoGenerationProvider(...)`
- 功能 / 渠道插件消费 `api.runtime.videoGeneration.*`
- 功能/渠道插件消费 `api.runtime.videoGeneration.*`
对于媒体理解运行时辅助,插件可以调用:
对于媒体理解运行时辅助工具,插件可以调用:
```ts
const image = await api.runtime.mediaUnderstanding.describeImageFile({
@ -390,22 +374,22 @@ const video = await api.runtime.mediaUnderstanding.describeVideoFile({
});
```
对于音频转录,插件可以使用媒体理解运行时,或使用较旧的 STT 别名:
对于音频转录,插件既可以使用媒体理解运行时,也可以使用较旧的 STT 别名:
```ts
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
filePath: "/tmp/inbound-audio.ogg",
cfg: api.config,
// 当 MIME 无法可靠推断时可选:
// Optional when MIME cannot be inferred reliably:
mime: "audio/ogg",
});
```
说明:
- `api.runtime.mediaUnderstanding.*` 是图像 / 音频 / 视频理解的首选共享表面。
- 使用 core 媒体理解音频配置(`tools.media.audio`)和 provider 回退顺序。
- 当没有产生转录输出时返回 `{ text: undefined }`(例如输入被跳过 / 不受支持)。
- `api.runtime.mediaUnderstanding.*` 是图像/音频/视频理解的首选共享表面。
- 使用核心媒体理解音频配置(`tools.media.audio`)和提供商回退顺序。
- 当没有产生转录输出时返回 `{ text: undefined }`(例如输入被跳过/不受支持)。
- `api.runtime.stt.transcribeAudioFile(...)` 仍保留为兼容性别名。
插件还可以通过 `api.runtime.subagent` 启动后台子智能体运行:
@ -422,14 +406,14 @@ const result = await api.runtime.subagent.run({
说明:
- `provider``model` 是每次运行可选覆盖项,不是持久的会话变更。
- OpenClaw 只会为可信调用方接受这些覆盖字段。
- 对于插件拥有的回退运行,操作者必须通过 `plugins.entries.<id>.subagent.allowModelOverride: true` 显式启用。
- 使用 `plugins.entries.<id>.subagent.allowedModels` 可将可信插件限制为特定的规范 `provider/model` 目标,或设置为 `"*"` 明确允许任意目标。
- 不可信插件的子智能体运行仍可工作,但覆盖请求会被拒绝,而不是静默回退。
- 由插件创建的子智能体会话会带上创建插件 id 的标记。回退 `api.runtime.subagent.deleteSession(...)` 只能删除这些归属会话;任意会话删除仍需要管理员作用域的 Gateway 网关请求。
- `provider``model` 是每次运行可选覆盖项,不是持久的会话变更。
- OpenClaw 仅对受信任调用方接受这些覆盖字段。
- 对于插件拥有的回退运行,操作者必须通过 `plugins.entries.<id>.subagent.allowModelOverride: true` 明确启用。
- 使用 `plugins.entries.<id>.subagent.allowedModels` 将受信任插件限制到特定的规范 `provider/model` 目标,或使用 `"*"` 显式允许任意目标。
- 不受信任插件的子智能体运行仍可工作,但覆盖请求会被拒绝,而不是静默回退。
- 由插件创建的子智能体会话会带上创建插件 id 的标签。回退 `api.runtime.subagent.deleteSession(...)` 只能删除这些自有会话;删除任意会话仍需要管理员范围的 Gateway 网关请求。
对于 web 搜索,插件可以消费共享运行时辅助,而不是深入到智能体工具接线内部
对于 web 搜索,插件可以消费共享运行时辅助工具,而不是深入到智能体工具接线中
```ts
const providers = api.runtime.webSearch.listProviders({
@ -445,14 +429,13 @@ const result = await api.runtime.webSearch.search({
});
```
插件也可以通过
`api.registerWebSearchProvider(...)` 注册 web 搜索 provider。
插件也可以通过 `api.registerWebSearchProvider(...)` 注册 web 搜索提供商。
说明:
- 将 provider 选择、凭证解析和共享请求语义保留在 core 中。
- web 搜索 provider 用于厂商特定的搜索传输。
- `api.runtime.webSearch.*` 是功能 / 渠道插件的首选共享表面,适用于那些需要搜索行为但又不想依赖智能体工具包装器的场景
- 将提供商选择、凭证解析和共享请求语义保留在核心中。
- web 搜索提供商用于厂商特定的搜索传输。
- `api.runtime.webSearch.*` 是功能/渠道插件需要搜索能力但又不依赖智能体工具包装器时的首选共享表面
### `api.runtime.imageGeneration`
@ -467,8 +450,8 @@ const providers = api.runtime.imageGeneration.listProviders({
});
```
- `generate(...)`:使用已配置的图像生成 provider 链生成图像。
- `listProviders(...)`:列出可用的图像生成 provider 及其能力。
- `generate(...)`:使用已配置的图像生成提供商链生成图像。
- `listProviders(...)`:列出可用的图像生成提供商及其能力。
## Gateway 网关 HTTP 路由
@ -490,157 +473,151 @@ api.registerHttpRoute({
路由字段:
- `path`Gateway 网关 HTTP 服务器下的路由路径。
- `auth`:必填。使用 `"gateway"` 表示要求普通 Gateway 网关鉴权,或使用 `"plugin"` 表示由插件管理鉴权 / webhook 校验。
- `auth`:必填。使用 `"gateway"` 以要求常规 Gateway 网关认证,或使用 `"plugin"` 以启用插件管理的认证/webhook 校验。
- `match`:可选。`"exact"`(默认)或 `"prefix"`
- `replaceExisting`:可选。允许同一插件替换它自己已存在的路由注册。
- `handler`:当路由处理了请求时返回 `true`
- `replaceExisting`:可选。允许同一插件替换它自己现有的路由注册。
- `handler`:当路由处理了请求时返回 `true`
说明:
- `api.registerHttpHandler(...)` 已被移除,并会导致插件加载错误。请改用 `api.registerHttpRoute(...)`
- 插件路由必须显式声明 `auth`
- 精确的 `path + match` 冲突会被拒绝,除非设置了 `replaceExisting: true`,并且一个插件不能替换另一个插件的路由。
- 不同 `auth` 级别的重叠路由会被拒绝。仅在相同鉴权级别下保留 `exact` / `prefix` 的贯穿链。
- `auth: "plugin"` 路由**不会**自动获得操作者运行时作用域。它们用于插件管理的 webhook / 签名校验,而不是特权 Gateway 网关辅助调用。
- 不同 `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` 请求头契约。
- 共享密钥 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。core 子路径如下
在编写新插件时,请使用精细化的 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 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` 契约上,而不是分散在不相关的插件字段之间。参见 [Channel Plugins](/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` 等)。
<Info>
`openclaw/plugin-sdk/channel-runtime` 已弃用——它只是对旧插件的兼容 shim。新代码应改为导入更细粒度的通用原语。
`openclaw/plugin-sdk/channel-runtime` 已弃用——它只是面向旧插件的兼容性 shim。新代码应改为导入更精细的通用原语。
</Info>
仓库内部入口点(每个内置插件包根目录划分
仓库内部入口点(每个内置插件软件包根目录):
- `index.js` —— 内置插件入口
- `api.js` —— 辅助 / 类型 barrel
- `api.js` —— 辅助工具/类型 barrel
- `runtime-api.js` —— 仅运行时 barrel
- `setup-entry.js` —— 设置插件入口
外部插件只能导入 `openclaw/plugin-sdk/*` 子路径。绝不要从 core 或另一个插件中导入其他插件包的 `src/*`。通过 facade 加载的入口点会优先使用当前活动的运行时配置快照;如果不存在,则回退到磁盘上已解析的配置文件。
外部插件只能导入 `openclaw/plugin-sdk/*` 子路径。绝不要从核心或其他插件中导入另一个插件软件包的 `src/*`。通过 facade 加载的入口点在存在活动运行时配置快照时会优先使用它,否则回退到磁盘上已解析的配置文件。
`image-generation`、`media-understanding` 和 `speech` 这样的能力专用子路径之所以存在,是因为内置插件当前正在使用它们。它们并不自动构成长期冻结的外部契约——依赖它们时,请查看相应的 SDK 参考页面。
诸如 `image-generation`、`media-understanding` 和 `speech` 这样的能力专用子路径之所以存在,是因为当前内置插件正在使用它们。它们并不自动构成长期冻结的外部契约——在依赖它们之前,请查看相关 SDK 参考页面。
## 消息工具 schema
## 消息工具模式
对于反应、已读、投票这类非消息原语,插件应拥有渠道特定的 `describeMessageTool(...)` schema 扩展。共享的发送呈现应使用通用 `MessagePresentation` 契约,而不是 provider 原生的 button、component、block 或 card 字段。有关该契约、回退规则、provider 映射以及插件作者检查清单,请参见 [Message Presentation](/zh-CN/plugins/message-presentation)。
对于反应、已读和投票等非消息原语,插件应拥有渠道特定的 `describeMessageTool(...)` 模式扩展。共享发送展示应使用通用 `MessagePresentation` 契约,而不是提供商原生的按钮、组件、区块或卡片字段。关于该契约、回退规则、提供商映射以及插件作者检查清单,请参见 [消息展示](/zh-CN/plugins/message-presentation)。
具备发送能力的插件通过消息能力声明它们能渲染什么:
- `presentation`:用于语义化呈现块(`text`、`context`、`divider`、`buttons`、`select`
- `presentation`:用于语义化展示区块(`text`、`context`、`divider`、`buttons`、`select`
- `delivery-pin`:用于固定投递请求
由 core 决定是原生渲染该呈现,还是降级为文本。不要从通用消息工具中暴露 provider 原生 UI 逃逸口。用于旧版原生 schema 的已弃用 SDK 辅助仍会为现有第三方插件导出,但新插件不应使用它们。
核心决定是原生渲染该展示,还是将其降级为文本。不要从通用消息工具中暴露提供商原生 UI 的逃逸口。针对旧版原生模式的已弃用 SDK 辅助工具仍会为现有第三方插件导出,但新插件不应使用它们。
## 渠道目标解析
渠道插件应拥有渠道特定的目标语义。请保持共享出站宿主的通用性,并使用消息适配器表面来承载 provider 规则:
渠道插件应拥有渠道特定的目标语义。保持共享出站主机通用,并使用消息适配器表面处理提供商规则:
- `messaging.inferTargetChatType({ to })` 决定标准化目标在目录查找前应被视为 `direct`、`group` 还是 `channel`
- `messaging.targetResolver.looksLikeId(raw, normalized)` 告诉 core 某个输入是否应跳过目录搜索,直接进入类似 id 的解析
- `messaging.targetResolver.resolveTarget(...)`当 core 在标准化后或目录未命中后需要最终由 provider 拥有的解析时,插件侧的回退入口
- `messaging.resolveOutboundSessionRoute(...)` 在目标解析完成后负责构建 provider 特定的会话路由。
- `messaging.inferTargetChatType({ to })` 决定规范化后的目标在目录查找前应被视为 `direct`、`group` 还是 `channel`
- `messaging.targetResolver.looksLikeId(raw, normalized)` 告诉核心某个输入是否应直接跳到类 id 解析,而不是进行目录搜索
- `messaging.targetResolver.resolveTarget(...)`插件的回退路径,用于在规范化后或目录未命中后执行最终的提供商拥有解析
- `messaging.resolveOutboundSessionRoute(...)` 在目标解析完成后负责构建提供商特定的会话路由。
推荐拆分方式:
- 使用 `inferTargetChatType` 处理那些应在搜索联系人 / 群组之前进行的类别判断
- 使用 `looksLikeId` 处理“将此视为显式 / 原生目标 id”的判断
- 使用 `resolveTarget` 作为 provider 特定的标准化回退,而不是用于广泛的目录搜索。
- 将 chat id、thread id、JID、handle 和 room id 这类 provider 原生 id 保留在 `target` 值或 provider 特定参数中,而不是放进通用 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 的私信联系人
- 已配置的渠道 / 群组映射
- 按账号作用域划分的静态目录回退
- 已配置的渠道/群组映射
- 基于账号范围的静态目录回退
`directory-runtime` 中的共享辅助只处理通用操作:
`directory-runtime` 中的共享辅助工具只处理通用操作:
- 查询过滤
- 限制数量应用
- 去重 / 标准化辅助
- 去重/规范化辅助工具
- 构建 `ChannelDirectoryEntry[]`
渠道特定的账号检查和 id 标准化应保留在插件实现中。
渠道特定的账号检查和 id 规范化应保留在插件实现中。
## provider 目录
## 提供商目录
provider 插件可以通过
`registerProvider({ catalog: { run(...) { ... } } })`
为推理定义模型目录。
提供商插件可以通过 `registerProvider({ catalog: { run(...) { ... } } })` 定义用于推理的模型目录。
`catalog.run(...)` 返回与 OpenClaw 写入 `models.providers` 中相同的形状
`catalog.run(...)` 返回的形态与 OpenClaw 写入 `models.providers` 的形态相同:
- `{ provider }`一个 provider 条目
- `{ providers }`:多个 provider 条目
- `{ provider }`单个提供商条目
- `{ providers }`:多个提供商条目
当插件拥有 provider 特定的模型 id、`baseUrl` 默认值或受鉴权门控的模型元数据时,请使用 `catalog`
当插件拥有提供商特定的模型 id、基础 URL 默认值或受认证控制的模型元数据时,请使用 `catalog`
`catalog.order` 控制插件目录相对于 OpenClaw 内置隐式 provider 的合并时机:
`catalog.order` 控制插件目录相对于 OpenClaw 内置隐式提供商的合并时机:
- `simple`:普通 API key 或环境变量驱动的 provider
- `profile`当存在 auth profile 时出现的 provider
- `paired`合成多个相关 provider 条目的 provider
- `late`:最后阶段,在其他隐式 provider 之后
- `simple`:普通 API key 或基于环境变量的提供商
- `profile`存在认证配置文件时出现的提供商
- `paired`会合成多个相关提供商条目的提供商
- `late`:最后阶段,在其他隐式提供商之后
在键冲突时,后出现的 provider 会胜出,因此插件可以有意覆盖具有相同 provider id 的内置 provider 条目。
发生键冲突时,较晚的提供商会获胜,因此插件可以有意使用相同提供商 id 覆盖内置提供商条目。
兼容性:
- `discovery`可作为旧别名使
- `discovery`作为旧别名可
- 如果同时注册了 `catalog``discovery`OpenClaw 会使用 `catalog`
## 只读渠道检查
如果你的插件注册了一个渠道,请优先实现
`plugin.config.inspectAccount(cfg, accountId)`,并与 `resolveAccount(...)` 配套。
如果你的插件注册了一个渠道,请优先实现 `plugin.config.inspectAccount(cfg, accountId)`,并与 `resolveAccount(...)` 一起提供。
原因:
- `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`
- `botTokenSource`、`botTokenStatus`
- `appTokenSource`、`appTokenStatus`
- `signingSecretSource`、`signingSecretStatus`
- 你不需要为了报告只读可用性而返回原始令牌值。返回 `tokenStatus: "available"`(以及匹配的来源字段)对于状态类命令就足够了。
- 当凭证通过 SecretRef 配置但在当前命令路径中不可用时,请使用 `configured_unavailable`
- 你不需要为了报告只读可用性而返回原始令牌值。对于类似 Status 的命令,只返回 `tokenStatus: "available"`(以及对应的来源字段)就足够了。
- 当凭证通过 SecretRef 配置但在当前命令路径中不可用时,请使用 `configured_unavailable`
这样只读命令就能报告“已配置,但在当前命令路径中不可用”,而不是崩溃或错误地该账号报告为未配置。
这样一来,只读命令就能报告“已配置,但在当前命令路径中不可用”,而不是崩溃或错误地该账号报告为未配置。
## 包打包集合
## 软件包打包
插件目录可以包含一个带 `openclaw.extensions``package.json`
插件目录可以包含一个带 `openclaw.extensions``package.json`
```json
{
@ -652,38 +629,37 @@ provider 插件可以通过
}
```
每个条目都会变成一个插件。如果该包列出了多个扩展,则插件 id 会变成 `name/<fileBase>`
每个条目都会成为一个插件。如果该 pack 列出了多个扩展,插件 id 将变为 `name/<fileBase>`
如果你的插件导入了 npm 依赖,请在该目录中安装它们,以便 `node_modules` 可用(`npm install` / `pnpm install`)。
安全护栏:每个 `openclaw.extensions` 条目在解析符号链接之后都必须仍位于插件目录内部。逃出包目录的条目会被拒绝。
安全护栏:在解析符号链接后,每个 `openclaw.extensions` 条目都必须保留在插件目录内部。逃逸出软件包目录的条目会被拒绝。
安全说明:`openclaw plugins install` 会使用项目本地的 `npm install --omit=dev --ignore-scripts` 安装插件依赖(无生命周期脚本、运行时无开发依赖),并忽略继承的全局 npm 安装设置。请保持插件依赖树为“纯 JS / TS”并避免需要 `postinstall` 构建的包。
安全说明:`openclaw plugins install` 会使用项目本地的 `npm install --omit=dev --ignore-scripts` 安装插件依赖(无生命周期脚本、运行时无开发依赖),并忽略继承的全局 npm 安装设置。请保持插件依赖树为“纯 JS/TS”并避免使用需要 `postinstall` 构建的包。
可选项:`openclaw.setupEntry` 可以指向一个轻量的仅设置模块。当 OpenClaw 需要为一个已禁用的渠道插件提供设置表面,或者某个渠道插件已启用但尚未配置时,它会加载 `setupEntry` 而不是完整插件入口。这样当你的主插件入口还会接线工具、钩子或其他仅运行时代码时,就可以让启动和设置更轻量。
可选项:`openclaw.setupEntry` 可以指向一个轻量的用于设置模块。当 OpenClaw 需要为一个已禁用的渠道插件提供设置表面,或者某个渠道插件已启用但尚未配置时,它会加载 `setupEntry`,而不是完整的插件入口。这样当你的主插件入口还接入了工具、钩子或其他仅运行时代码时,就能让启动和设置更轻量。
可选项:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen`
可以让某个渠道插件在 Gateway 网关的 pre-listen 启动阶段也走同样的 `setupEntry` 路径,即使该渠道已经配置完成。
可选项:`openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` 可让某个渠道插件在 Gateway 网关监听前的启动阶段也选择同样的 `setupEntry` 路径,即使该渠道已经完成配置。
仅当 `setupEntry` 能完整覆盖 Gateway 网关开始监听前必须存在的启动表面时,才使用这个选项。实际上,这意味着 setup entry 必须注册启动所依赖的所有渠道拥有能力,例如:
只有当 `setupEntry` 完整覆盖了 Gateway 网关开始监听前必须存在的启动表面时,才应使用此选项。实际上,这意味着设置入口必须注册启动所依赖的每一项渠道自有能力,例如:
- 渠道注册本身
- 任何必须在 Gateway 网关开始监听前就可用的 HTTP 路由
- 任何在同一窗口内必须存在的 gateway 方法、工具或服务
- 在 Gateway 网关开始监听前必须可用的任何 HTTP 路由
- 在同一时间窗口内必须存在的任何 gateway 方法、工具或服务
如果你的完整入口仍拥有任何必需的启动能力,请不要启用这个标志。保持插件默认行为,让 OpenClaw 在启动期间加载完整入口。
如果你的完整入口仍拥有任何必需的启动能力,请不要启用该标志。请保留插件的默认行为,并让 OpenClaw 在启动期间加载完整入口。
内置渠道也可以发布仅设置阶段的契约表面辅助,供 core 在完整渠道运行时加载前查询。当前的设置提升表面包括:
内置渠道还可以发布仅用于设置的契约表面辅助工具,以便核心在完整渠道运行时加载前进行查询。当前的设置提升表面包括:
- `singleAccountKeysToMove`
- `namedAccountPromotionKeys`
- `resolveSingleAccountPromotionTarget(...)`
Core 会在需要将旧版单账号渠道配置提升到 `channels.<id>.accounts.*` 时使用该表面而无需加载完整插件入口。Matrix 是当前的内置示例:当已存在命名账号时,它只会把鉴权 / 引导键移动到一个被提升的命名账号中,并且能够保留一个已配置但非规范的默认账号键,而不是总是创建 `accounts.default`
核心会在需要将旧版单账号渠道配置提升为 `channels.<id>.accounts.*`且又不加载完整插件入口时使用该表面。Matrix 是当前的内置示例:当命名账号已存在时,它只会将认证/引导键移动到一个命名提升账号中,并且它可以保留一个已配置的非规范默认账号键,而不是总是创建 `accounts.default`
这些设置补丁适配器内置契约表面发现保持惰性。导入时保持轻量;提升表面只在首次使用时加载,而不会在模块导入期间重新进入内置渠道启动流程。
这些设置补丁适配器使内置契约表面发现保持惰性。导入时保持轻量;提升表面只在首次使用时加载,而不会在模块导入重新进入内置渠道启动流程。
当这些启动表面包含 Gateway 网关 RPC 方法时请将它们保留在插件专用前缀下。Core 管理员命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)始终保留,并且总是解析为 `operator.admin`,即使某个插件请求了更窄的作用域也是如此。
当这些启动表面包含 gateway RPC 方法时,请将它们放在插件专用前缀下。核心管理命名空间(`config.*`、`exec.approvals.*`、`wizard.*`、`update.*`)仍然保留,并且始终解析为 `operator.admin`,即使插件请求了更窄的作用域也是如此。
示例:
@ -702,7 +678,7 @@ Core 会在需要将旧版单账号渠道配置提升到 `channels.<id>.accounts
### 渠道目录元数据
渠道插件可以通过 `openclaw.channel`告设置 / 发现元数据,并通过 `openclaw.install` 宣告安装提示。这使得 core 目录保持无数据状态
渠道插件可以通过 `openclaw.channel`传设置/发现元数据,并通过 `openclaw.install` 提供安装提示。这样可以让核心目录不携带数据
示例:
@ -714,10 +690,10 @@ Core 会在需要将旧版单账号渠道配置提升到 `channels.<id>.accounts
"channel": {
"id": "nextcloud-talk",
"label": "Nextcloud Talk",
"selectionLabel": "Nextcloud Talk自托管",
"selectionLabel": "Nextcloud Talkself-hosted",
"docsPath": "/channels/nextcloud-talk",
"docsLabel": "nextcloud-talk",
"blurb": "通过 Nextcloud Talk webhook 机器人实现的自托管聊天。",
"blurb": "通过 Nextcloud Talk webhook bots 提供 self-hosted 聊天。",
"order": 65,
"aliases": ["nc-talk", "nc"]
},
@ -730,40 +706,39 @@ Core 会在需要将旧版单账号渠道配置提升到 `channels.<id>.accounts
}
```
除最小示例外,有用的 `openclaw.channel` 字段包括:
除最小示例外,其他有用的 `openclaw.channel` 字段包括:
- `detailLabel`:用于更丰富目录 / Status 表面的次级标签
- `detailLabel`:用于更丰富目录/Status 表面的次级标签
- `docsLabel`:覆盖文档链接的链接文本
- `preferOver`:该目录条目应优先于的低优先级插件 / 渠道 id
- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面的文案控制
- `markdownCapable`:将该渠道标记为支持 Markdown便进行出站格式决策
- `preferOver`:该目录条目应优先于的低优先级插件/渠道 id
- `selectionDocsPrefix`、`selectionDocsOmitLabel`、`selectionExtras`:选择表面的文案控制
- `markdownCapable`:将该渠道标记为支持 Markdown供出站格式决策使用
- `exposure.configured`:设为 `false` 时,在已配置渠道列表表面中隐藏该渠道
- `exposure.setup`:设为 `false` 时,在交互式设置 / 配置选择器中隐藏该渠道
- `exposure.docs`在文档导航表面中将该渠道标记为内部 / 私有
- `showConfigured` / `showInSetup`为兼容性仍接受的旧别名;优先使用 `exposure`
- `exposure.setup`:设为 `false` 时,在交互式设置/配置选择器中隐藏该渠道
- `exposure.docs`:将该渠道标记为内部/私有,以供文档导航表面使用
- `showConfigured` / `showInSetup`旧别名,出于兼容性仍被接受;请优先使用 `exposure`
- `quickstartAllowFrom`:让该渠道加入标准快速开始 `allowFrom` 流程
- `forceAccountBinding`:即使存在一个账号,也要求显式账号绑定
- `preferSessionLookupForAnnounceTarget`解析 announce 目标时优先使用会话查找
- `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"` 键的旧别名。
生成的渠道目录条目和 provider 安装目录条目会在原始 `openclaw.install` 块旁边暴露标准化后的安装来源事实。标准化事实会标识 npm spec 是精确版本还是浮动选择器、是否存在预期的完整性元数据,以及是否还可用本地源码路径。当目录 / 包身份已知时,如果解析出的 npm 包名与该身份发生漂移,标准化事实会发出警告。它们还会在 `defaultChoice` 无效、指向不可用来源,或存在 npm 完整性元数据但没有有效 npm 来源时发出警告。使用方应将 `installSource` 视为增量可选字段,这样手工构建的条目和目录 shim 就无需合成它。这样,新手引导和诊断就可以在不导入插件运行时的情况下解释来源平面状态。
生成的渠道目录条目和提供商安装目录条目,会在原始 `openclaw.install` 块旁暴露规范化的安装源事实。规范化事实会标识 npm 说明符是精确版本还是浮动选择器、是否存在预期完整性元数据,以及是否也可用本地源路径。当目录/软件包标识已知时,若解析出的 npm 包名偏离该标识,规范化事实会发出警告。它们还会在 `defaultChoice` 无效、指向不可用源,或存在 npm 完整性元数据却没有有效 npm 源时发出警告。消费者应将 `installSource` 视为附加的可选字段,这样手工构建的条目和目录 shim 就不必合成它。
这使新手引导和诊断能够在不导入插件运行时的情况下解释源平面状态。
官方外部 npm 条目应优先使用精确的 `npmSpec``expectedIntegrity`。仅包名和 dist-tag 为兼容性仍然可用,但它们会暴露来源平面警告,以便目录在不破坏现有插件的前提下逐步转向固定版本、带完整性校验的安装。当新手引导从本地目录路径安装时,它会记录一个受管插件索引条目,包含 `source: "path"`,并尽可能记录相对于工作区的 `sourcePath`。绝对运行时加载路径仍保存在 `plugins.load.paths` 中;安装记录会避免将本地工作站路径重复写入长期配置。这让本地开发安装对来源平面诊断保持可见,同时不会增加第二个原始文件系统路径泄露表面。持久化的 `plugins/installs.json` 插件索引是安装源的事实来源,并且可在不加载插件运行时模块的情况下刷新。它的 `installRecords` 映射即使在插件 manifest 缺失或无效时也是持久的;它的 `plugins` 数组则是一个可重建的 manifest / 缓存视图。
官方外部 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` 选择活动引擎。
当你的插件需要替换或扩展默认上下文流水线,而不只是添加内存搜索或钩子时,请使用这个能力
当你的插件需要替换或扩展默认上下文流水线,而不是仅添加 memory 搜索或钩子时,请使用这种方式。
```ts
import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
@ -791,7 +766,7 @@ export default function (api) {
}
```
如果你的引擎**不**拥有压缩算法,请保持 `compact()` 已实现,并显式委托它:
如果你的引擎**不**拥有压缩算法,请保持实现 `compact()`,并显式委托它:
```ts
import {
@ -828,52 +803,51 @@ export default function (api) {
## 添加新能力
当插件需要当前 API 无法适配的行为时,不要通过私有深入访问来绕过插件系统。应添加缺失的能力。
当插件需要当前 API 无法适配的行为时,不要通过私有穿透来绕过插件系统。请添加缺失的能力。
推荐顺序:
1. 定义 core 契约
决定哪些共享行为应由 core 拥有:策略、回退、配置合并、
生命周期、面向渠道的语义,以及运行时辅助形状。
2. 添加类型化的插件注册 / 运行时表面
用最小但有用的类型化能力表面扩展 `OpenClawPluginApi` 和 / 或 `api.runtime`
3. 接线 core + 渠道 / 功能使用方
渠道和功能插件应通过 core 消费该新能力,而不是直接导入某个厂商实现。
1. 定义核心契约
决定哪些共享行为应由核心负责:策略、回退、配置合并、生命周期、面向渠道的语义以及运行时辅助工具形态。
2. 添加类型化插件注册/运行时表面
用最小且有用的类型化能力表面扩展 `OpenClawPluginApi` 和/或 `api.runtime`
3. 接入核心 + 渠道/功能消费者
渠道和功能插件应通过核心消费这项新能力,而不是直接导入某个厂商实现。
4. 注册厂商实现
然后由厂商插件针对该能力注册它们的后端
然后由厂商插件针对该能力注册其后端实现
5. 添加契约覆盖
添加测试,以便随着时间推移,归属和注册形状仍保持明确。
添加测试,以便随着时间推移,所有权和注册形态仍保持明确。
这就是 OpenClaw 如何在保持明确立场的同时,不被某个 provider 的世界观硬编码。有关具体文件清单和完整示例,请参见 [Capability Cookbook](/zh-CN/plugins/architecture)。
这就是 OpenClaw 保持有主见、又不被某一家提供商世界观硬编码绑死的方式。有关具体文件检查清单和完整示例,请参见 [能力扩展手册](/zh-CN/plugins/architecture)。
### 能力检查清单
当你添加新能力时,实现通常应同时涉及以下表面:
当你添加一项新能力时,实现通常应一起触及以下表面:
- `src/<capability>/types.ts` 中的 core 契约类型
- `src/<capability>/runtime.ts` 中的 core runner / 运行时辅助
- `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` 中的 capture / 测试辅助
- `src/plugins/contracts/registry.ts` 中的归属 / 契约断言
- `docs/`的操作者 / 插件文档
- `src/plugins/runtime/*` 中的插件运行时暴露(当功能/渠道插件需要消费它时)
- `src/test-utils/plugin-registration.ts` 中的捕获/测试辅助工具
- `src/plugins/contracts/registry.ts` 中的所有权/契约断言
- `docs/`面向操作者/插件的文档
如果这些表面中缺少某一项,通常说明该能力尚未完全集成。
如果其中某个表面缺失,通常说明该能力尚未完全集成。
### 能力模板
最小模式:
```ts
// core 契约
// core contract
export type VideoGenerationProviderPlugin = {
id: string;
label: string;
generateVideo: (req: VideoGenerationRequest) => Promise<VideoGenerationResult>;
};
// 插件 API
// plugin API
api.registerVideoGenerationProvider({
id: "openai",
label: "OpenAI",
@ -882,7 +856,7 @@ api.registerVideoGenerationProvider({
},
});
// 面向功能 / 渠道插件的共享运行时辅助
// shared runtime helper for feature/channel plugins
const clip = await api.runtime.videoGeneration.generate({
prompt: "Show the robot walking through the lab.",
cfg,
@ -895,16 +869,16 @@ const clip = await api.runtime.videoGeneration.generate({
expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]);
```
这样规则就保持简单:
这样规则就简单:
- core 拥有能力契约 + 编排
- 核心拥有能力契约 + 编排
- 厂商插件拥有厂商实现
- 功能 / 渠道插件消费运行时辅助
- 契约测试让归属保持明确
- 功能/渠道插件消费运行时辅助工具
- 契约测试让所有权保持明确
## 相关内容
- [Plugin architecture](/zh-CN/plugins/architecture) — 公开能力模型和形状
- [Plugin SDK subpaths](/zh-CN/plugins/sdk-subpaths)
- [Plugin Setup](/zh-CN/plugins/sdk-setup)
- [Building plugins](/zh-CN/plugins/building-plugins)
- [插件架构](/zh-CN/plugins/architecture) —— 公开的能力模型和形态
- [插件 SDK 子路径](/zh-CN/plugins/sdk-subpaths)
- [插件 SDK 设置](/zh-CN/plugins/sdk-setup)
- [构建插件](/zh-CN/plugins/building-plugins)

View File

@ -3,27 +3,27 @@ read_when:
- 构建或调试原生 OpenClaw 插件
- 理解插件能力模型或所有权边界
- 处理插件加载流水线或注册表
- 实现 provider 运行时 hook 或渠道插件
- 实现提供商运行时钩子或渠道插件
sidebarTitle: Internals
summary: 插件内部机制:能力模型、所有权、契约、加载流水线和运行时辅助工具
title: 插件内部机制
x-i18n:
generated_at: "2026-04-27T12:54:04Z"
generated_at: "2026-04-27T16:07:01Z"
model: gpt-5.4
provider: openai
source_hash: bf11e7e9098283f5a489e9843c338ef235748663580dfeaef62f6f6766b55621
source_hash: 846b3ec4ddd38b87c7b4f5e039556373075d058013ed568175e8fd1b6de2aa4d
source_path: plugins/architecture.md
workflow: 15
---
这是 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">
构建一个消息渠道插件。
@ -31,16 +31,16 @@ x-i18n:
<Card title="提供商插件" icon="microchip" href="/zh-CN/plugins/sdk-provider-plugins">
构建一个模型提供商插件。
</Card>
<Card title="插件 SDK 概览" icon="book" href="/zh-CN/plugins/sdk-overview">
<Card title="SDK 概览" icon="book" href="/zh-CN/plugins/sdk-overview">
导入映射和注册 API 参考。
</Card>
</CardGroup>
## 公共能力模型
能力是 OpenClaw 内部公的**原生插件**模型。每个原生 OpenClaw 插件都会针对一种或多种能力类型进行注册:
能力是 OpenClaw 内部公的**原生插件**模型。每个原生 OpenClaw 插件都会针对一种或多种能力类型进行注册:
| Capability | Registration method | Example plugins |
| 能力 | 注册方法 | 示例插件 |
| ---------------------- | ------------------------------------------------ | ------------------------------------ |
| 文本推理 | `api.registerProvider(...)` | `openai`, `anthropic` |
| CLI 推理后端 | `api.registerCliBackend(...)` | `openai`, `anthropic` |
@ -53,150 +53,154 @@ x-i18n:
| 视频生成 | `api.registerVideoGenerationProvider(...)` | `qwen` |
| Web 抓取 | `api.registerWebFetchProvider(...)` | `firecrawl` |
| Web 搜索 | `api.registerWebSearchProvider(...)` | `google` |
| 渠道 / 消息 | `api.registerChannel(...)` | `msteams`, `matrix` |
| 渠道 / 消息传递 | `api.registerChannel(...)` | `msteams`, `matrix` |
| Gateway 网关发现 | `api.registerGatewayDiscoveryService(...)` | `bonjour` |
<Note>
一个注册了零个能力、但提供 hook、工具、发现服务或后台服务的插件是一种**旧版仅 hook** 插件。这种模式仍然受到完整支持。
注册零个能力、但提供钩子、工具、发现服务或后台服务的插件,属于**传统仅钩子**插件。该模式目前仍然受到完整支持。
</Note>
### 外部兼容性立场
能力模型已经在核心中落地,并且如今已被内置/原生插件使用,但外部插件兼容性仍然需要比“它已导出,因此已冻结”更严格的标准。
能力模型已经落地到核心中,并且当前已被内置 / 原生插件使用,但外部插件兼容性仍需要比“已导出,因此已冻结”更严格的标准。
| Plugin situation | Guidance |
| 插件情况 | 指导建议 |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| 现有外部插件 | 保持基于 hook 的集成可继续工作;这是兼容性基线。 |
| 新的内置/原生插件 | 优先使用显式能力注册,而不是供应商特定的深度耦合,或新的仅 hook 设计。 |
| 采用能力注册的外部插件 | 允许,但除非文档将能力特定的辅助表面标记为稳定,否则应视其为仍在演进中。 |
| 现有外部插件 | 保持基于钩子的集成继续可用;这是兼容性的基线。 |
| 新的内置 / 原生插件 | 优先选择显式能力注册,而不是特定厂商的内部接入或新的仅钩子设计。 |
| 采用能力注册的外部插件 | 允许,但除非文档将其标记为稳定,否则应将能力专用的辅助接口视为仍在演进中。 |
能力注册是预期方向。在过渡期间,对于外部插件来说,旧版 hook 仍然是最不易破坏兼容性的路径。已导出的辅助子路径并不完全等价——应优先使用范围窄且有文档说明的契约,而不是偶然导出的辅助内容
能力注册是既定方向。在过渡期间,传统钩子仍是对外部插件最安全、最不易破坏兼容性的路径。并非所有已导出的辅助子路径都同等稳定——应优先使用范围狭窄且有文档说明的契约,而不是偶然暴露出来的辅助导出
### 插件形态
OpenClaw 会根据每个已加载插件的实际注册行为对其进行形态分类(而不只是静态元数据):
OpenClaw 会根据每个已加载插件的实际注册行为(而不只是静态元数据)将其归类为某种形态
<AccordionGroup>
<Accordion title="plain-capability">
恰好注册一种能力类型(例如像 `mistral` 这样仅提供商的插件)。
只注册一种能力类型(例如仅提供商插件 `mistral`)。
</Accordion>
<Accordion title="hybrid-capability">
注册多种能力类型(例如 `openai` 同时拥有文本推理、语音、媒体理解和图像生成)。
</Accordion>
<Accordion title="hook-only">
仅注册 hook类型化或自定义没有能力、工具、命令或服务。
只注册钩子(类型化或自定义),不注册能力、工具、命令或服务。
</Accordion>
<Accordion title="non-capability">
注册工具、命令、服务或路由,但不注册能力。
</Accordion>
</AccordionGroup>
使用 `openclaw plugins inspect <id>`查看插件的形态和能力细分。详情请参见 [CLI reference](/zh-CN/cli/plugins#inspect)。
使用 `openclaw plugins inspect <id>`以查看插件的形态和能力明细。详见 [CLI 参考](/zh-CN/cli/plugins#inspect)。
### 旧版 hook
### 传统钩子
`before_agent_start` hook 仍然作为仅 hook 插件的兼容路径受到支持。旧版真实插件仍然依赖它。
`before_agent_start` 钩子仍作为兼容路径受到支持,适用于仅钩子插件。现实中的传统插件仍依赖它。
方向:
方向如下
- 保持其可用
- 将其记录为旧版
- 对于模型/提供商覆盖工作,优先使用 `before_model_resolve`
- 在文档中将其标记为传统方式
- 对于模型 / 提供商覆盖工作,优先使用 `before_model_resolve`
- 对于提示词变更工作,优先使用 `before_prompt_build`
- 只有在真实使用下降并且 fixture 覆盖证明迁移安全后才移除
- 只有在真实使用量下降且夹具覆盖证明迁移安全后才移除
### 兼容性信号
当你运行 `openclaw doctor``openclaw plugins inspect <id>` 时,你可能会看到以下标签之一:
运行 `openclaw doctor``openclaw plugins inspect <id>` 时,你可能会看到以下标签之一:
| Signal | Meaning |
| 信号 | 含义 |
| -------------------------- | ------------------------------------------------------------ |
| **配置有效** | 配置可正常解析,插件也能正常解析 |
| **兼容性建议** | 插件使用受支持但较旧的模式(例如 `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 的插件系统四层:
OpenClaw 的插件系统包含四层:
<Steps>
<Step title="清单 + 发现">
OpenClaw 会从已配置路径、工作区根目录、全局插件根目录和内置插件中查找候选插件。发现流程会优先读取原生 `openclaw.plugin.json` 清单以及支持的捆绑包清单。
OpenClaw 会从已配置路径、工作区根目录、全局插件根目录以及内置插件中查找候选插件。设备发现会优先读取原生 `openclaw.plugin.json` 清单以及受支持的 bundle 清单。
</Step>
<Step title="启用状态 + 校验">
核心决定某个已发现插件是已启用、已禁用、被阻止,还是被选入某个独占插槽,例如 memory。
<Step title="启用 + 校验">
核心决定某个已发现插件是启用、禁用、阻止,还是被选中用于某个独占槽位,例如 memory。
</Step>
<Step title="运行时加载">
原生 OpenClaw 插件通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容捆绑包则会在不导入运行时代码的情况下,被规范化为注册表记录。
原生 OpenClaw 插件通过 jiti 在进程内加载,并将能力注册到中央注册表中。兼容的 bundle 会在不导入运行时代码的情况下被标准化为注册表记录。
</Step>
<Step title="表面消费">
OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、hook、HTTP 路由、CLI 命令和服务。
OpenClaw 的其余部分会读取注册表,以暴露工具、渠道、提供商设置、钩子、HTTP 路由、CLI 命令和服务。
</Step>
</Steps>
具体到插件 CLI根命令发现被拆分为两个阶段
对于插件 CLI根命令发现被拆分为两个阶段
- 解析时元数据来自 `registerCli(..., { descriptors: [...] })`
- 真正的插件 CLI 模块可以保持惰性,并在首次调用时再注册
- 真正的插件 CLI 模块可以保持懒加载,并在首次调用时注册
这样可以让插件拥有的 CLI 代码保留在插件内部,同时仍让 OpenClaw 在解析前预留根命令名称。
这样既能将插件自有的 CLI 代码保留在插件内部,又能让 OpenClaw 在解析前预留根命令名称。
重要的设计边界
重要的设计边界如下
- 清单/配置校验应基于**清单/schema 元数据**完成,而不执行插件代码
- 清单 / 配置校验应基于**清单 / 模式元数据**完成,而不执行插件代码
- 原生能力发现可以加载受信任的插件入口代码,以构建一个不会激活的注册表快照
- 原生运行时行为来自插件模块的 `register(api)` 路径,并 `api.registrationMode === "full"`
- 原生运行时行为来自插件模块的 `register(api)` 路径,并带有 `api.registrationMode === "full"`
这种拆分让 OpenClaw 可以在完整运行时激活之前,就完成配置校验、解释缺失/禁用插件,并构建 UI/schema 提示。
这种拆分使 OpenClaw 能够在完整运行时激活之前,先校验配置、解释缺失 / 已禁用的插件,并构建 UI / 模式提示。
### 插件查找表
### 插件元数据快照和查找表
Gateway 网关启动时,会根据当前配置快照中的已安装插件索引和清单注册表构建一个 `PluginLookUpTable`。该表仅包含元数据:它存储插件 id、清单记录、诊断信息、所有者映射、插件 id 规范化器以及启动插件计划。它不持有已加载的插件模块、提供商 SDK、包内容或运行时导出。
Gateway 网关启动时会为当前配置快照构建一个 `PluginMetadataSnapshot`。该快照仅包含元数据:它存储已安装插件索引、清单注册表、清单诊断信息、所有者映射、插件 id 标准化器以及清单记录。它不持有已加载的插件模块、提供商 SDK、包内容或运行时导出。
查找表让重复的启动决策保持在快速路径上:
具备插件感知能力的配置校验、启动自动启用和 Gateway 网关插件引导都使用这个快照,而不是各自独立重建清单 / 索引元数据。`PluginLookUpTable` 由同一个快照派生而来,并为当前运行时配置增加了启动插件计划。
快照和查找表能让重复的启动决策保持在快速路径上:
- 渠道所有权
- 延迟渠道启动
- 启动插件 id
- 提供商和 CLI 后端所有权
- 设置提供商、命令别名、模型目录提供商以及清单契约所有权
- 插件配置模式和渠道配置模式校验
- 启动自动启用决策
安全边界在于快照替换,而不是变更。应在配置、插件清单、安装记录或持久化索引策略变化时重建该表。不要把它当作一个可广泛变更的全局注册表,也不要无限制地保留历史表。运行时插件加载仍与查找表元数据分离,因此过期的运行时状态不会被元数据缓存掩盖。
安全边界在于快照替换,而不是突变修改。当配置、插件清单、安装记录或持久化索引策略发生变化时,应重建快照。不要将它视为一个广泛可变的全局注册表,也不要保留无限增长的历史快照。运行时插件加载仍与元数据快照分离,因此过时的运行时状态不会被元数据缓存掩盖。
某些冷路径调用方仍会直接从持久化的已安装插件索引重建清单注册表,而不是接收 Gateway 网关的 `PluginLookUpTable`这条回退路径会保留一个小型、有界的内存缓存,其键由已安装索引、请求形态、配置策略、运行时根目录以及清单/package 文件签名组成。它是针对重复索引重建的回退安全网,而不是首选的 Gateway 网关热路径。当调用方已经持有当前查找表或显式清单注册表时,在运行时流程中应优先传递它们
一些冷路径调用方仍会直接根据持久化的已安装插件索引重建清单注册表,而不是接收 Gateway 网关的 `PluginLookUpTable`该回退路径保留了一个小型、有界的内存缓存,其键由已安装索引、请求形态、配置策略、运行时根目录以及清单 / 包文件签名组成。它是为重复索引重建提供的回退安全网,而不是首选的 Gateway 网关热路径。当调用方已经拥有当前查找表时,应优先在运行时流程中传递该查找表或显式的清单注册表
### 激活规划
激活规划是控制平面的一部分。调用方可以在加载更广泛的运行时注册表之前,先询哪些插件与具体命令、提供商、渠道、路由、Agent harness 或能力相关。
激活规划是控制平面的一部分。调用方可以在加载更广泛的运行时注册表之前,先询哪些插件与某个具体命令、提供商、渠道、路由、Agent harness 或能力相关。
规划器保持与当前清单行为兼容:
规划器保持与当前清单行为兼容:
- `activation.*` 字段是显式的规划器提示
- `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和 hook 仍然是清单所有权回退
- 仅 id 的规划器 API 对现有调用方仍然可用
- plan API 会报告原因标签,以便诊断区分显式提示和所有权回退
- `providers`、`channels`、`commandAliases`、`setup.providers`、`contracts.tools` 和钩子仍然是清单所有权回退
- 仅返回 id 的规划器 API 对现有调用方可用
- 计划 API 会报告原因标签,以便诊断信息区分显式提示和所有权回退
<Warning>
不要将 `activation` 视为生命周期 hook 或 `register(...)` 的替代品。它是用于缩小加载范围的元数据。当现有所有权字段已经能描述这种关系时,应优先使用所有权字段;只有在需要额外规划器提示时,才使用 `activation`
不要将 `activation` 视为生命周期钩子,也不要把它当作 `register(...)` 的替代品。它是用于缩小加载范围的元数据。若所有权字段已经能够描述关系,应优先使用所有权字段;仅在需要额外规划器提示时才使用 `activation`
</Warning>
### 渠道插件和共享 message 工具
### 渠道插件和共享消息工具
对于常规聊天操作,渠道插件不需要单独注册发送/编辑/反应工具。OpenClaw 在核心中保留了一个共享的 `message` 工具,而渠道插件拥有其背后的渠道特定发现和执行逻辑
渠道插件在执行常规聊天操作时,不需要单独注册发送 / 编辑 / 响应工具。OpenClaw 在核心中保留了一个共享的 `message` 工具,而渠道插件负责其背后的渠道专属发现与执行
当前边界
当前边界如下
- 核心拥有共享 `message` 工具宿主、提示词接线、会话/线程簿记和执行分发
- 渠道插件拥有作用域动作发现、能力发现以及所有渠道特定 schema 片段
- 渠道插件拥有提供商特定的会话会话语法,例如会话 id 如何编码线程 id或如何继承父会话
- 渠道插件通过它们的动作适配器执行最终动作
- 核心拥有共享 `message` 工具宿主、提示词接线、会话 / 线程簿记以及执行分发
- 渠道插件拥有作用域动作发现、能力发现,以及任何渠道专属的模式片段
- 渠道插件拥有提供商专属的会话对话语法,例如对话 id 如何编码线程 id 或如何从父对话继承
- 渠道插件通过动作适配器执行最终动作
对于渠道插件SDK 表面`ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用允许插件将其可见动作、能力和 schema 贡献一起返回,从而避免这些部分彼此漂移。
对于渠道插件SDK 接口`ChannelMessageActionAdapter.describeMessageTool(...)`。这个统一的发现调用允许插件将其可见动作、能力和模式贡献一起返回,从而避免这些部分彼此漂移。
当某个渠道专用 message 工具参数携带媒体来源,例如本地路径或远程媒体 URL 时,插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心会使用这份显式列表来应用沙箱路径规范化和出站媒体访问提示,而不需要硬编码插件拥有的参数名。这里应优先使用按动作划分的映射,而不是一个覆盖整个渠道的扁平列表,这样某个仅限 profile 的媒体参数就不会在 `send` 之类无关动作上被规范化。
当某个渠道专属的消息工具参数携带媒体来源时,例如本地路径或远程媒体 URL插件还应从 `describeMessageTool(...)` 返回 `mediaSourceParams`。核心使用这个显式列表来应用沙箱路径标准化和出站媒体访问提示,而无需硬编码由插件拥有的参数名。这里应优先使用按动作划分的映射,而不是整个渠道范围内的单一扁平列表,这样仅用于资料的媒体参数就不会在 `send` 之类无关动作上被标准化。
核心会将运行时作用域传入该发现步骤。重要字段包括:
@ -207,36 +211,36 @@ Gateway 网关启动时,会根据当前配置快照中的已安装插件索引
- `sessionKey`
- `sessionId`
- `agentId`
- 受信任入站 `requesterSenderId`
- 受信任入站 `requesterSenderId`
这对上下文敏感型插件很重要。一个渠道可以根据活动账户、当前房间/线程/消息,或受信任请求者身份来隐藏或暴露 message 动作,而无需在核心 `message` 工具中硬编码渠道特定分支。
这对上下文敏感型插件很重要。渠道可以根据当前账户、当前房间 / 线程 / 消息或受信任的请求方身份来隐藏或暴露消息动作,而无需在核心 `message` 工具中硬编码渠道专属分支。
这也是为什么嵌入式运行器路由变更仍然属于插件工作:运行器负责将当前聊天/会话身份转发到插件发现边界,这样共享 `message` 工具就能为当前 turn 暴露正确的、由渠道拥有的表面。
这也是为什么嵌入式运行器路由变更仍然属于插件工作:运行器负责将当前聊天 / 会话身份转发到插件发现边界,使共享的 `message` 工具能为当前轮次暴露正确的、由渠道拥有的表面。
对于由渠道拥有的执行辅助工具,内置插件应将执行运行时保留在它们自己的扩展模块中。核心不再拥有 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp message-action 运行时。我们不会发布单独的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从它们自己拥有的扩展模块中导入本地运行时代码。
对于由渠道拥有的执行辅助工具,内置插件应将执行运行时保留在自己的扩展模块内部。核心不再拥有 `src/agents/tools` 下的 Discord、Slack、Telegram 或 WhatsApp 消息动作运行时。我们不会发布独立的 `plugin-sdk/*-action-runtime` 子路径,内置插件应直接从其扩展自有模块导入本地运行时代码。
同样的边界也适用于一般性的 provider 命名 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 仍然作为外部插件和旧消费者的兼容性 shim 而保留,但内置插件应使用本地导出以及狭义的通用 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>` 门面。这些带品牌标识的门面仍然是面向外部插件和旧调用方的兼容性垫片,但内置插件应使用本地导出以及狭义的通用 SDK 子路径,例如 `openclaw/plugin-sdk/channel-policy`、`openclaw/plugin-sdk/runtime-store` 或 `openclaw/plugin-sdk/webhook-ingress`。除非现有外部生态的兼容性边界确实需要,否则新代码不应再添加按插件 id 划分的 SDK 门面
对于投票,当前有两条执行路径:
对于投票功能,当前有两条执行路径:
- `outbound.sendPoll` 是适用于符合通用投票模型渠道的共享基线
- `actions.handleAction("poll")` 是适用于渠道特定投票语义或额外投票参数的首选路径
- `actions.handleAction("poll")` 是适用于渠道专属投票语义或额外投票参数的首选路径
核心现在会在插件投票分发拒绝该动作之后,才延迟执行共享投票解析,因此插件拥有的投票处理器可以接受渠道特定投票字段,而不会先被通用投票解析器拦住
现在,核心会在插件投票分发拒绝该动作之后,才推迟执行共享投票解析,因此由插件拥有的投票处理器可以接受渠道专属投票字段,而不会先被通用投票解析器阻挡
完整启动顺序请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。
完整启动顺序见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。
## 能力所有权模型
OpenClaw 将原生插件视为**公司**或**功能**的所有权边界,而不是一堆无关集成的集合。
OpenClaw 将原生插件视为某个**公司**或某项**功能**的所有权边界,而不是无关集成的杂物集合。
这意味着:
- 一个公司插件通常应拥有该公司的所有 OpenClaw 对外表面
- 一个功能插件通常应拥有其引入的完整功能表面
- 渠道应消费共享核心能力,而不是临时重新实现 provider 行为
- 公司插件通常应拥有该公司的所有面向 OpenClaw 的表面
- 功能插件通常应拥有它引入的完整功能表面
- 渠道应消费共享的核心能力,而不是临时重实现提供商行为
<AccordionGroup>
<Accordion title="供应商多能力">
@ -246,22 +250,22 @@ OpenClaw 将原生插件视为**公司**或**功能**的所有权边界,而不
`elevenlabs``microsoft` 拥有语音;`firecrawl` 拥有 Web 抓取;`minimax` / `mistral` / `moonshot` / `zai` 拥有媒体理解后端。
</Accordion>
<Accordion title="功能插件">
`voice-call` 拥有通话传输、工具、CLI、路由和 Twilio 媒体流桥接,但它消费共享的语音、实时转录和实时语音能力,而不是直接导入供应商插件。
`voice-call` 拥有呼叫传输、工具、CLI、路由和 Twilio 媒体流桥接,但它消费共享的语音、实时转录和实时语音能力,而不是直接导入供应商插件。
</Accordion>
</AccordionGroup>
预期的最终状态是:
- OpenAI 即使同时覆盖文本模型、语音、图像和未来的视频,也应存在于一个插件中
- 另一个供应商也可以为其自身表面采用相同方式
- 渠道不关心哪个供应商插件拥有该 provider它们消费的是核心暴露出的共享能力契约
- OpenAI 保持在一个插件中,即使它跨越文本模型、语音、图像和未来的视频
- 其他供应商也可以对自己的表面范围采用相同方式
- 渠道不关心哪个供应商插件拥有该提供商;它们消费的是由核心暴露出的共享能力契约
是关键区别:
这是关键区别:
- **plugin** = 所有权边界
- **capability** = 多个插件实现或消费的核心契约
- **capability** = 可由多个插件实现或消费的核心契约
因此,如果 OpenClaw 新增一个领域,比如视频,第一问题不应是“哪个 provider 应该硬编码视频处理?”第一问题应是“核心的视频能力契约是什么?”一旦该契约存在,供应商插件就可以针对它注册,渠道/功能插件也可以消费它。
因此,如果 OpenClaw 增加一个新领域,例如视频,首要问题不是“哪个提供商应硬编码视频处理?”首要问题是“核心视频能力契约是什么?”一旦该契约存在,供应商插件就可以针对它进行注册,渠道 / 功能插件也可以消费它。
如果该能力尚不存在,通常正确的做法是:
@ -270,31 +274,31 @@ OpenClaw 将原生插件视为**公司**或**功能**的所有权边界,而不
在核心中定义缺失的能力。
</Step>
<Step title="通过 SDK 暴露">
以类型化方式通过插件 API/运行时暴露它。
通过插件 API / 运行时以类型化方式暴露它。
</Step>
<Step title="接入消费者">
将渠道/功能接入到该能力
让渠道 / 功能针对该能力进行接线
</Step>
<Step title="供应商实现">
让供应商插件注册实现。
</Step>
</Steps>
这样能在保持所有权明确的同时,避免核心行为依赖单一供应商或某条一次性的插件专用代码路径。
这样可以保持所有权清晰,同时避免核心行为依赖单一供应商或某条一次性的插件专属代码路径。
### 能力分层
在决定代码应放在哪里时,可使用下面的心智模型:
在决定代码应归属何处时,请使用以下思维模型:
<Tabs>
<Tab title="核心能力层">
共享编排、策略、回退、配置合并规则、交付语义和类型化契约。
</Tab>
<Tab title="供应商插件层">
供应商特定 API、认证、模型目录、语音合成、图像生成、未来的视频后端、用量端点。
供应商专属 API、凭证、模型目录、语音合成、图像生成、未来的视频后端、用量端点。
</Tab>
<Tab title="渠道/功能插件层">
Slack/Discord/voice-call 等集成,它们消费核心能力并将其呈现在某个表面上。
<Tab title="渠道 / 功能插件层">
Slack / Discord / voice-call 等集成,它们消费核心能力并将其呈现在某个表面上。
</Tab>
</Tabs>
@ -304,11 +308,11 @@ OpenClaw 将原生插件视为**公司**或**功能**的所有权边界,而不
- `openai`、`elevenlabs` 和 `microsoft` 拥有合成实现
- `voice-call` 消费电话 TTS 运行时辅助工具
未来的能力也应优先遵循同样的模式。
对于未来的能力,也应优先采用同样的模式。
### 多能力公司插件示例
从外部看,一个公司插件应当是内聚的。如果 OpenClaw 对模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、Web 抓取和 Web 搜索都有共享契约,那么一个供应商可以在一个地方拥有它的全部表面:
从外部看,公司插件应当具有一致性。如果 OpenClaw 对模型、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、Web 抓取和 Web 搜索都有共享契约,那么某个供应商就可以在一个地方拥有它的所有表面:
```ts
import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry";
@ -362,16 +366,16 @@ const plugin: OpenClawPluginDefinition = {
export default plugin;
```
重要的不在于辅助函数的精确名称,而在于形态:
重要的不是辅助函数的确切名称,而是这种形态:
- 一个插件拥有供应商表面
- 一个插件拥有供应商表面
- 核心仍然拥有能力契约
- 渠道和功能插件消费 `api.runtime.*` 辅助工具,而不是供应商代码
- 契约测试可以断言该插件已注册它所声称拥有的能力
- 契约测试可以断言该插件确实注册了它声称拥有的能力
### 能力示例:视频理解
OpenClaw 已经将图像/音频/视频理解视为一个共享能力。同样的所有权模型也适用于这里
OpenClaw 已经将图像 / 音频 / 视频理解视为一种共享能力。这里同样适用相同的所有权模型
<Steps>
<Step title="核心定义契约">
@ -381,107 +385,107 @@ OpenClaw 已经将图像/音频/视频理解视为一个共享能力。同样的
供应商插件按适用情况注册 `describeImage`、`transcribeAudio` 和 `describeVideo`
</Step>
<Step title="消费者使用共享行为">
渠道和功能插件消费共享核心行为,而不是直接接到供应商代码。
渠道和功能插件消费共享核心行为,而不是直接接到供应商代码。
</Step>
</Steps>
这样可以避免把某个 provider 的视频假设固化进核心。插件拥有供应商表面;核心拥有能力契约和回退行为。
这样可以避免将某个提供商的视频假设固化进核心。插件拥有供应商表面;核心拥有能力契约和回退行为。
视频生成已经使用同样的顺序:核心拥有类型化能力契约和运行时辅助工具,供应商插件则注册 `api.registerVideoGenerationProvider(...)` 实现。
视频生成已经用同样的顺序:核心拥有类型化能力契约和运行时辅助工具,供应商插件则注册 `api.registerVideoGenerationProvider(...)` 实现来对接它
需要具体的发布检查清单吗?请参见 [能力扩展手册](/zh-CN/plugins/architecture)。
需要具体的发布清单吗?请参见 [能力扩展手册](/zh-CN/plugins/architecture)。
## 契约强制执行
## 契约强制执行
插件 API 表面被有意设计为类型化,并集中在 `OpenClawPluginApi` 中。这个契约定义了受支持的注册点,以及插件可依赖的运行时辅助工具。
插件 API 表面被有意设计为类型化,并集中在 `OpenClawPluginApi` 中。这个契约定义了受支持的注册点,以及插件可依赖的运行时辅助工具。
这很重要,因为:
- 插件作者获得一个稳定的内部标准
- 核心可以拒绝重复所有权,例如两个插件注册相同的 provider id
- 插件作者可以获得一个稳定的内部标准
- 核心可以拒绝重复所有权,例如两个插件注册相同的提供商 id
- 启动过程可以为格式错误的注册暴露可执行的诊断信息
- 契约测试可以强制执行内置插件所有权,并防止静默漂移
有两层强制执行机制
强制执行分为两层
<AccordionGroup>
<Accordion title="运行时注册强制执行">
插件注册表会在插件加载时验证注册内容。例如:重复的 provider id、重复的语音 provider id以及格式错误的注册都会生成插件诊断信息,而不是导致未定义行为。
插件注册表会在插件加载时校验注册内容。例如:重复的提供商 id、重复的语音提供商 id 以及格式错误的注册,会产生插件诊断信息,而不是导致未定义行为。
</Accordion>
<Accordion title="契约测试">
在测试运行期间,内置插件会被捕获到契约注册表中,这样 OpenClaw 就能显式断言所有权。当前这用于模型 provider、语音 provider、Web 搜索 provider 和内置注册所有权。
在测试运行期间,内置插件会被捕获到契约注册表中,从而让 OpenClaw 可以显式断言所有权。如今这已用于模型提供商、语音提供商、Web 搜索提供商以及内置注册所有权。
</Accordion>
</AccordionGroup>
实际效果是OpenClaw 可以预先知道哪个插件拥有哪个表面。这使得核心和渠道能够无缝组合,因为所有权是被声明、类型化且可测试的,而不是隐含的。
实际效果是OpenClaw 能够预先知道哪个插件拥有哪个表面。因此,核心和渠道可以无缝组合,因为所有权是被声明、类型化并可测试的,而不是隐含的。
### 什么内容适合进入契约
### 什么应该属于契约
<Tabs>
<Tab title="契约">
<Tab title="好契约">
- 类型化
- 小而精
- 按能力划分
- 能力专属
- 由核心拥有
- 可被多个插件复用
- 可被渠道/功能在不了解供应商的前提下消费
- 可被渠道 / 功能消费,而无需了解供应商
</Tab>
<Tab title="坏的契约">
- 在核心中隐藏供应商特定策略
<Tab title="不良契约">
- 隐藏在核心中的供应商专属策略
- 绕过注册表的一次性插件逃生口
- 渠道代码直接深入某个供应商实现
- 直接深入供应商实现的渠道代码
- 不属于 `OpenClawPluginApi``api.runtime` 的临时运行时对象
</Tab>
</Tabs>
拿不准时,就提高抽象层级:先定义能力,再让插件接入它。
如有疑问,就提升抽象层级:先定义能力,再让插件接入它。
## 执行模型
原生 OpenClaw 插件与 Gateway 网关**在同一进程内**运行。它们不在沙箱中。已加载的原生插件与核心代码处于相同的进程级信任边界。
原生 OpenClaw 插件与 Gateway 网关**在同一进程内**运行。它们不受沙箱隔离。已加载的原生插件与核心代码处于相同的进程级信任边界
<Warning>
这意味着
影响包括
- 原生插件可以注册工具、网络处理器、hook 和服务
- 原生插件中的 bug 可能导致 Gateway 网关崩溃或失稳
- 恶意原生插件等同于在 OpenClaw 进程内执行任意代码
- 原生插件可以注册工具、网络处理器、钩子和服务
- 原生插件中的 bug 可能导致 Gateway 网关崩溃或不稳定
- 恶意原生插件等同于在 OpenClaw 进程内执行任意代码
</Warning>
兼容捆绑包默认更安全,因为 OpenClaw 当前将它们视为元数据/内容包。在当前版本中,这主要意味着内置 Skills。
兼容 bundle 默认情况下更安全,因为 OpenClaw 当前将其视为元数据 / 内容包。在当前版本中,这主要意味着内置 Skills。
对于非内置插件,请使用允许列表和显式安装/加载路径。应将工作区插件视为开发阶段代码,而不是生产默认项。
对于非内置插件,应使用 allowlist 和显式的安装 / 加载路径。应将工作区插件视为开发期代码,而不是生产默认项。
对于内置工作区包名,请让插件 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那么在该工作区插件被启用/加入允许列表时,它会有意覆盖内置副本。
- 这属于正常行为,并且对本地开发、补丁测试和热修复很有用。
- 内置插件信任是从源快照解析的——即加载时磁盘上的清单和代码——而不是从安装元数据解析。损坏或被替换的安装记录无法在实际源代码声明之外,悄悄扩大某个内置插件的信任表面。
- 如果某个工作区插件与某个内置插件具有相同 id那么在该工作区插件被启用 / 加入 allowlist 时,它会有意覆盖内置副本。
- 这很正常,而且对本地开发、补丁测试和热修复很有用。
- 内置插件信任是根据源码快照解析的——即加载时磁盘上的清单和代码——而不是根据安装元数据。损坏或被替换的安装记录不能在实际源码声明范围之外,悄悄扩大内置插件的信任表面。
</Note>
## 导出边界
OpenClaw 导出的是能力,而不是实现层面的便捷工具
OpenClaw 导出的是能力,而不是实现层面的便捷接口
应保持能力注册为公共接口。同时收紧非契约辅助导出:
应保持能力注册公开。应裁剪非契约辅助导出:
- 内置插件专辅助子路径
- 无意作为公共 API 的运行时管线路径
- 供应商专便捷辅助工具
- 属于实现细节的设置/新手引导辅助工具
- 内置插件专属的辅助子路径
- 无意作为公共 API 的运行时管道子路径
- 供应商专属的便捷辅助工具
- 属于实现细节的设置 / 新手引导辅助工具
出于兼容性和内置插件维护需要,一些内置插件辅助子路径仍保留在生成的 SDK 导出映射中。当前示例包括 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup`、`plugin-sdk/channel-config-schema-legacy` 以及若干 `plugin-sdk/matrix*` 接缝。应将它们视为已弃用的保留导出,而不是面向新第三方插件的推荐 SDK 模式。
出于兼容性和内置插件维护需要,一些内置插件辅助子路径仍保留在生成的 SDK 导出映射中。当前示例包括 `plugin-sdk/feishu`、`plugin-sdk/feishu-setup`、`plugin-sdk/zalo`、`plugin-sdk/zalo-setup`、`plugin-sdk/channel-config-schema-legacy`,以及若干 `plugin-sdk/matrix*` 接缝。应将这些视为已弃用的保留导出,而不是新第三方插件推荐采用的 SDK 模式。
## 内部机制参考
## 内部机制参考
关于加载流水线、注册表模型、provider 运行时 hook、Gateway 网关 HTTP 路由、message 工具 schema、渠道目标解析、provider 目录、上下文引擎插件,以及新增能力的指南,请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。
关于加载流水线、注册表模型、提供商运行时钩子、Gateway 网关 HTTP 路由、消息工具模式、渠道目标解析、提供商目录、上下文引擎插件,以及新增能力的指南,请参见 [插件架构内部机制](/zh-CN/plugins/architecture-internals)。
## 相关内容
- [构建插件](/zh-CN/plugins/building-plugins)
- [插件清单](/zh-CN/plugins/manifest)
- [插件设置](/zh-CN/plugins/sdk-setup)
- [插件 SDK 设置](/zh-CN/plugins/sdk-setup)