插件内部
本页面涵盖 OpenClaw 插件系统的内部架构。
公共功能模型
功能是 OpenClaw 内部的公共原生插件模型。每个 原生 OpenClaw 插件针对一个或多个功能类型进行注册:| 功能 | 注册方法 | 示例插件 |
|---|---|---|
| 文本推理 | api.registerProvider(...) | openai, anthropic |
| 语音 | api.registerSpeechProvider(...) | elevenlabs, microsoft |
| 媒体理解 | api.registerMediaUnderstandingProvider(...) | openai, google |
| 图像生成 | api.registerImageGenerationProvider(...) | openai, google |
| Web 搜索 | api.registerWebSearchProvider(...) | google |
| 渠道 / 消息传递 | api.registerChannel(...) | msteams, matrix |
外部兼容性立场
功能模型已在核心中落地,并供当前的捆绑/原生插件 使用,但外部插件兼容性仍需比“既然已导出,即已冻结”更严格的标准。 当前指南:- 现有外部插件: 保持基于钩子的集成正常工作;将此视为兼容性基线
- 新捆绑/原生插件: 优先使用显式功能注册,而不是供应商特定的内部访问或仅限钩子的新设计
- 采用功能注册的外部插件: 允许,但除非文档明确将某个合同标记为稳定,否则将特定于功能的辅助界面视为不断演进
- 功能注册 API 是预期的方向
- 在过渡期间,传统钩子仍然是外部插件最安全的不破坏路径
- 导出的辅助子路径并非全部等效;优先使用窄文档合同,而不是偶然的辅助导出
插件形态
OpenClaw 根据每个已加载插件的实际注册行为(不仅仅是静态元数据)将其归类为一种形态:- 单一功能 — 仅注册一种功能类型(例如仅提供商的插件,如
mistral) - 混合功能 — 注册多种功能类型(例如
openai拥有文本推理、语音、媒体理解和图像生成) - 仅钩子 — 仅注册钩子(类型化或自定义),不注册功能、工具、命令或服务
- 非功能 — 注册工具、命令、服务或路由,但不注册功能
openclaw plugins inspect <id> 查看插件的形态和功能细分。有关详细信息,请参阅 CLI 参考。
传统钩子
before_agent_start 钩子作为仅钩子插件的兼容性路径仍然受支持。现实世界中的传统插件仍然依赖它。
方向:
- 保持其正常工作
- 将其记录为传统内容
- 对于模型/提供商覆盖工作,优先使用
before_model_resolve - 对于提示词修改工作,优先使用
before_prompt_build - 仅在实际使用量下降且固件覆盖证明迁移安全后才移除
兼容性信号
当您运行openclaw doctor 或 openclaw plugins inspect <id> 时,您可能会看到以下标签之一:
| Signal | 含义 |
|---|---|
| 配置有效 | 配置解析正常且插件已解析 |
| 兼容性建议 | 插件使用了受支持但较旧的模式(例如 hook-only) |
| 遗留警告 | 插件使用了 before_agent_start,该功能已弃用 |
| 硬错误 | 配置无效或插件加载失败 |
hook-only 和 before_agent_start 都不会破坏您的插件 —
hook-only 仅是建议性的,而 before_agent_start 仅触发警告。这些
信号也会出现在 openclaw status --all 和 openclaw plugins doctor 中。
架构概览
OpenClaw 的插件系统有四层:- 清单 + 设备发现
OpenClaw 从配置的路径、工作区根目录、
全局扩展根目录和捆绑扩展中查找候选插件。设备发现首先读取原生
openclaw.plugin.json清单以及支持的捆绑清单。 - 启用 + 验证 核心决定已发现的插件是启用、禁用、阻止,还是 为内存等独占槽位选中。
- 运行时加载 原生 OpenClaw 插件通过 jiti 在进程内加载,并将 能力注册到中央注册表中。兼容的捆绑包被规范化为 注册表记录,而无需导入运行时代码。
- 表面消费 OpenClaw 的其余部分读取注册表以公开工具、渠道、提供商 设置、钩子、HTTP 路由、CLI 命令和服务。
- 设备发现 + 配置验证应从 清单/架构元数据 工作 而无需执行插件代码
- 原生运行时行为来自插件模块的
register(api)路径
渠道插件和共享消息工具
渠道插件不需要为正常的聊天操作注册单独的发送/编辑/反应工具。OpenClaw 在核心中保留一个共享的message 工具,
渠道插件拥有其背后的特定于渠道的设备发现和执行。
当前的边界是:
- 核心拥有共享的
message工具宿主、提示连接、会话/线程 记录以及执行分派 - 渠道插件拥有范围限定的操作发现、能力发现以及任何特定于渠道的架构片段
- 渠道插件通过其操作适配器执行最终操作
ChannelMessageActionAdapter.describeMessageTool(...)。那个统一的发现调用允许插件一起返回其可见的操作、能力和架构贡献,以便这些部分不会分离。
Core 将运行时作用域传递到该发现步骤中。重要字段包括:
accountIdcurrentChannelIdcurrentThreadTscurrentMessageIdsessionKeysessionIdagentId- 可信的入站
requesterSenderId
message 工具中硬编码特定于渠道的分支。
这就是为什么嵌入式运行器路由更改仍然是插件工作的原因:运行器负责将当前聊天/会话身份转发到插件发现边界,以便共享 message 工具为当前回合暴露正确的渠道拥有的表面。
对于渠道拥有的执行助手,捆绑插件应将执行运行时保留在其自己的扩展模块内。Core 不再拥有 Discord、
Slack、Telegram 或 WhatsApp 消息操作运行时(位于 src/agents/tools 下)。
我们不发布单独的 plugin-sdk/*-action-runtime 子路径,捆绑插件应直接从其扩展拥有的模块导入自己的本地运行时代码。
特别是对于投票,有两种执行路径:
outbound.sendPoll是适合常见投票模型的渠道的共享基线actions.handleAction("poll")是特定于渠道的投票语义或额外投票参数的首选路径
功能所有权模型
OpenClaw 将原生插件视为 公司 或 功能 的所有权边界,而不是不相关集成的零碎集合。 这意味着:- 公司插件通常应该拥有该公司所有面向 OpenClaw 的表面
- 功能插件通常应该拥有它引入的完整功能表面
- 渠道应该使用共享的核心功能,而不是临场重新实现提供商的行为
- 捆绑的
openai插件拥有 OpenAI 模型提供商行为以及 OpenAI 语音 + 媒体理解 + 图像生成行为 - 捆绑的
elevenlabs插件拥有 ElevenLabs 语音行为 - 捆绑的
microsoft插件拥有 Microsoft 语音行为 - 捆绑的
google插件拥有 Google 模型提供商行为以及 Google 媒体理解 + 图像生成 + 网络搜索行为 - 捆绑的
minimax、mistral、moonshot和zai插件拥有其 媒体理解后端 voice-call插件是一个功能插件:它拥有呼叫传输、工具、 CLI、路由和运行时,但它使用核心 TTS/STT 功能,而不是 发明第二个语音堆栈
- 即使 OpenAI 跨越文本模型、语音、图像和未来的视频,它也仅位于一个插件中
- 另一个供应商可以为其自己的表面区域做同样的事情
- 渠道不关心哪个供应商插件拥有该提供商;它们使用核心公开的共享功能契约
- 插件 = 所有权边界
- 功能 = 多个插件可以实现或使用的核心契约
- 在核心中定义缺失的功能
- 通过插件 API/运行时以类型化的方式暴露它
- 针对该能力连接渠道/功能
- 允许供应商插件注册实现
能力分层
在决定代码归属位置时,请使用此思维模型:- 核心能力层:共享编排、策略、回退、配置合并规则、交付语义和类型化合约
- 供应商插件层:供应商特定的 API、身份验证、模型目录、语音合成、图像生成、未来的视频后端、使用端点
- 渠道/功能插件层:Slack/Discord/语音呼叫/等集成,它消费核心能力并将其呈现于某个界面
- 核心拥有回复时的 TTS 策略、回退顺序、首选项和渠道交付
openai、elevenlabs和microsoft拥有合成实现voice-call消费电话 TTS 运行时助手
多能力公司插件示例
公司插件在外部看来应该具有内聚性。如果 OpenClaw 针对模型、语音、媒体理解和网络搜索有共享合约,供应商可以在一个地方拥有其所有界面:- 一个插件拥有供应商界面
- 核心仍然拥有能力合约
- 渠道和功能插件消费
api.runtime.*助手,而不是供应商代码 - 合约测试可以断言该插件注册了它声称拥有的能力
能力示例:视频理解
OpenClaw 已经将图像/音频/视频理解视为一种共享能力。同样的所有权模型也适用于此:- 核心定义媒体理解合约
- 供应商插件视情况注册
describeImage、transcribeAudio和describeVideo - 渠道和功能插件消费共享的核心行为,而不是直接连接到供应商代码
契约与执行
插件 API 表面是经过有意类型设计并集中在OpenClawPluginApi 中的。该契约定义了支持的注册点以及插件可以依赖的运行时辅助工具。
为什么这很重要:
- 插件作者获得一个稳定的内部标准
- 核心可以拒绝重复的所有权,例如两个插件注册相同的提供商 ID
- 启动时可以针对格式错误的注册提供可操作的诊断信息
- 契约测试可以强制执行捆绑插件的所有权,并防止静默偏差
- 运行时注册执行 插件注册表会在插件加载时验证注册。例如: 重复的提供商 ID、重复的语音提供商 ID 和格式错误的 注册会生成插件诊断信息,而不是未定义的行为。
- 契约测试 捆绑插件在测试运行期间会被捕获到契约注册表中,以便 OpenClaw 可以显式断言所有权。目前这用于模型 提供商、语音提供商、网络搜索提供商和捆绑注册 所有权。
契约中应包含什么
良好的插件契约是:- 有类型的
- 小型的
- 针对特定能力的
- 由核心拥有
- 可被多个插件重用
- 可被渠道/功能消费,而无需供应商知识
- 隐藏在核心中的特定于供应商的策略
- 绕过注册表的一次性插件应急手段
- 直接深入到供应商实现中的渠道代码
- 不属于
OpenClawPluginApi或api.runtime一部分的临时的运行时对象
执行模型
原生 OpenClaw 插件与 Gateway(网关) 运行在同一进程中。它们并非沙箱隔离。已加载的原生插件与核心代码拥有相同的进程级信任边界。 影响:- 原生插件可以注册工具、网络处理程序、钩子和服务
- 原生插件的错误可能会导致网关崩溃或不稳定
- 恶意的原生插件等同于在 OpenClaw 进程内执行任意代码
@openclaw/<id>,或者当包有意暴露更窄的插件角色时,使用批准的类型后缀,如 -provider、-plugin、-speech、-sandbox 或 -media-understanding。
重要信任说明:
plugins.allow信任的是插件 ID,而非来源出处。- 当启用或加入允许列表时,与捆绑插件具有相同 ID 的工作区插件会有意覆盖该捆绑副本。
- 这是正常且有用的行为,适用于本地开发、补丁测试和热修复。
导出边界
OpenClaw 导出的是能力,而非实现便利性。 保持能力注册公开。裁剪非契约的辅助导出:- 特定于捆绑插件的辅助子路径
- 并非公共 API 的运行时管道子路径
- 特定于供应商的便利辅助工具
- 属于实现细节的设置/新手引导辅助工具
加载管道
启动时,OpenClaw 大致执行以下操作:- 发现候选插件根目录
- 读取原生或兼容捆绑包清单以及包元数据
- 拒绝不安全的候选者
- 规范化插件配置 (
plugins.enabled,allow,deny,entries,slots,load.paths) - 决定是否启用每个候选插件
- 通过 jiti 加载已启用的原生模块
- 调用原生
register(api)钩子并将注册信息收集到插件注册表中 - 将注册表暴露给命令/运行时界面
清单优先行为
清单是控制平面的唯一真实来源。OpenClaw 使用它来:- 识别插件
- 发现已声明的频道/技能/配置架构或打包能力
- 验证
plugins.entries.<id>.config - 增强控制 UI 标签/占位符
- 显示安装/目录元数据
加载器缓存的内容
OpenClaw 为以下内容保留简短的进程内缓存:- 发现结果
- 清单注册表数据
- 已加载的插件注册表
- 设置
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1或OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1以禁用这些缓存。 - 使用
OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS和OPENCLAW_PLUGIN_MANIFEST_CACHE_MS调整缓存窗口。
注册表模型
已加载的插件不会直接修改随机的核心全局变量。它们会注册到一个中央插件注册表中。 该注册表跟踪:- 插件记录(身份、来源、起源、状态、诊断信息)
- 工具
- 旧版钩子和类型化钩子
- 频道
- 提供商
- 网关 RPC 处理程序
- HTTP 路由
- CLI 注册器
- 后台服务
- 插件拥有的命令
- 插件模块 -> 注册表注册
- 核心运行时 -> 注册表使用
会话绑定回调
绑定会话的插件可以在批准被解决时做出反应。 使用api.onConversationBindingResolved(...) 在绑定请求被批准或拒绝后接收回调:
status:"approved"或"denied"decision:"allow-once"、"allow-always"或"deny"binding:已批准请求的已解决绑定request:原始请求摘要、分离提示、发送者 ID 和 会话元数据
提供程序运行时挂钩
提供程序插件现在有两层:- 清单元数据:
providerAuthEnvVars用于在运行时加载之前进行廉价的环境认证查找,加上providerAuthChoices用于在运行时加载之前进行廉价的 新手引导/认证选择 标签和 CLI 标志元数据 - 配置时挂钩:
catalog/ 传统discovery - 运行时挂钩:
resolveDynamicModel、prepareDynamicModel、normalizeResolvedModel、capabilities、prepareExtraParams、wrapStreamFn、formatApiKey、refreshOAuth、buildAuthDoctorHint、isCacheTtlEligible、buildMissingAuthMessage、suppressBuiltInModel、augmentModelCatalog、isBinaryThinking、supportsXHighThinking、resolveDefaultThinkingLevel、isModernModelRef、prepareRuntimeAuth、resolveUsageAuth、fetchUsageSnapshot
providerAuthEnvVars。当新手引导/身份验证选择 CLI 界面需要知道提供商的选择 ID、组标签和简单的单标志身份验证连线,而不加载提供商运行时时,请使用清单 providerAuthChoices。保留提供商运行时 envVars 用于面向操作员的提示,例如新手引导标签或 OAuth client-id/client-secret 设置变量。
挂钩顺序和用法
对于模型/提供商插件,OpenClaw 大致按此顺序调用挂钩。“何时使用”列是快速决策指南。| # | 挂钩 | 作用 | 何时使用 |
|---|---|---|---|
| 1 | catalog | 在 models.json 生成期间将提供商配置发布到 models.providers | 提供商拥有目录或基本 URL 默认值 |
| — | (内置模型查找) | OpenClaw 首先尝试正常的注册表/目录路径 | (不是插件挂钩) |
| 2 | resolveDynamicModel | 针对提供商拥有但尚未在本地注册表中的模型 ID 的同步回退 | 提供商接受任意上游模型 ID |
| 3 | prepareDynamicModel | 异步预热,然后 resolveDynamicModel 再次运行 | 提供商在解析未知 ID 之前需要网络元数据 |
| 4 | normalizeResolvedModel | 嵌入式运行器使用解析的模型之前的最终重写 | 提供商需要传输重写但仍使用核心传输 |
| 5 | capabilities | 共享核心逻辑使用的提供商拥有的对话记录/工具元数据 | 提供商需要对话记录/提供商系列的特殊处理 |
| 6 | prepareExtraParams | 通用流选项包装器之前的请求参数规范化 | 提供商需要默认请求参数或按提供商清理参数 |
| 7 | wrapStreamFn | 应用通用包装器之后的流包装器 | 提供商需要请求头/正文/模型兼容性包装器,而无需自定义传输 |
| 8 | formatApiKey | Auth-profile formatter:存储的配置文件成为运行时 apiKey 字符串 | 提供商存储额外的身份验证元数据,并且需要自定义运行时令牌形状 |
| 9 | refreshOAuth | OAuth 刷新覆盖,用于自定义刷新端点或刷新失败策略 | 提供商不适合共享的 pi-ai 刷新器 |
| 10 | buildAuthDoctorHint | 当 OAuth 刷新失败时附加的修复提示 | 提供商在刷新失败后需要提供商拥有的身份验证修复指导 |
| 11 | isCacheTtlEligible | 针对代理/回程提供商的提示缓存策略 | 提供商需要特定于代理的缓存 TTL 门控 |
| 12 | buildMissingAuthMessage | 通用缺少身份验证恢复消息的替换 | 提供商需要特定于提供商的缺少身份验证恢复提示 |
| 13 | suppressBuiltInModel | 过时的上游模型抑制以及可选的用户可见错误提示 | 提供商需要隐藏过时的上游行或将其替换为供应商提示 |
| 14 | augmentModelCatalog | 发现后附加的合成/最终目录行 | 提供商需要 models list 和选择器中的合成向前兼容行 |
| 15 | isBinaryThinking | 针对二元思维提供商的开/关推理切换 | 提供商仅公开二元思维的开/关 |
| 16 | supportsXHighThinking | 所选模型的 xhigh 推理支持 | 提供商希望仅在模型的一个子集上启用 xhigh |
| 17 | resolveDefaultThinkingLevel | 特定模型系列的默认 /think 级别 | 提供商拥有模型系列的默认 /think 策略 |
| 18 | isModernModelRef | 用于实时配置文件过滤和烟雾选择的现代模型匹配器 | 提供商拥有实时/烟雾首选模型匹配 |
| 19 | prepareRuntimeAuth | 在推理之前将配置的凭证交换为实际的运行时令牌/密钥 | 提供商需要令牌交换或短期请求凭证 |
| 20 | resolveUsageAuth | 解析 /usage 的使用/计费凭据以及相关的状态界面 | 提供商需要自定义的使用/配额令牌解析或不同的使用凭据 |
| 21 | fetchUsageSnapshot | 在解析身份验证后,获取并规范化提供商特定的使用/配额快照 | 提供商需要提供商特定的使用端点或负载解析器 |
提供商示例
内置示例
- Anthropic 使用
resolveDynamicModel、capabilities、buildAuthDoctorHint、resolveUsageAuth、fetchUsageSnapshot、isCacheTtlEligible、resolveDefaultThinkingLevel和isModernModelRef,因为它拥有 Claude 4.6 前向兼容性、提供商系列提示、身份验证修复指导、使用 端点集成、提示缓存资格,以及 Claude 默认/自适应 思维策略。 - OpenAI 使用
resolveDynamicModel、normalizeResolvedModel和capabilities加上buildMissingAuthMessage、suppressBuiltInModel、augmentModelCatalog、supportsXHighThinking和isModernModelRef, 因为它拥有 GPT-5.4 前向兼容性、直接 OpenAIopenai-completions->openai-responses规范化、Codex 感知的身份验证 提示、Spark 抑制、合成 OpenAI 列表行,以及 GPT-5 思考 / 实时模型策略。 - OpenRouter 使用
catalog加上resolveDynamicModel和prepareDynamicModel,因为该提供商是透传的,并且可能会在 OpenClaw 的静态目录更新之前公开新的 模型 ID;它还使用capabilities、wrapStreamFn和isCacheTtlEligible,以将 特定于提供商的请求标头、路由元数据、推理补丁和 提示缓存策略排除在核心之外。 - GitHub Copilot 使用
catalog、auth、resolveDynamicModel和capabilities,以及prepareRuntimeAuth和fetchUsageSnapshot,因为它 需要提供商拥有的设备登录、模型回退行为、Claude 转录怪癖、 GitHub 令牌 -> Copilot 令牌交换,以及提供商拥有的使用 端点。 - OpenAI Codex 使用
catalog、resolveDynamicModel、normalizeResolvedModel、refreshOAuth和augmentModelCatalog,以及prepareExtraParams、resolveUsageAuth和fetchUsageSnapshot,因为它 仍在核心 OpenAI 传输上运行,但拥有其传输/基本 URL 规范化、OAuth 刷新回退策略、默认传输选择、 合成 Codex 目录行以及 ChatGPT 使用端点集成。 - Google AI Studio 和 Gemini CLI OAuth 使用
resolveDynamicModel和isModernModelRef,因为它们拥有 Gemini 3.1 前向兼容回退和 现代模型匹配;Gemini CLI OAuth 还使用formatApiKey、resolveUsageAuth和fetchUsageSnapshot进行令牌格式化、令牌 解析和配额端点连接。 - Moonshot 使用
catalog以及wrapStreamFn,因为它仍使用共享 OpenAI 传输,但需要提供商拥有的思考负载规范化。 - Kilocode 使用
catalog、capabilities、wrapStreamFn和isCacheTtlEligible,因为它需要提供商拥有的请求头、 推理负载规范化、Gemini 转录提示和 Anthropic 缓存 TTL 门控。 - Z.AI 使用
resolveDynamicModel、prepareExtraParams、wrapStreamFn、isCacheTtlEligible、isBinaryThinking、isModernModelRef、resolveUsageAuth和fetchUsageSnapshot,因为它拥有 GLM-5 回退、tool_stream默认值、二元思考 UX、现代模型匹配以及使用授权和配额获取。 - Mistral、OpenCode Zen 和 OpenCode Go 仅使用
capabilities,以便将转录/工具怪癖排除在核心之外。 - 仅目录捆绑的提供商(如
byteplus、cloudflare-ai-gateway、huggingface、kimi-coding、modelstudio、nvidia、qianfan、synthetic、together、venice、vercel-ai-gateway和volcengine)仅使用catalog。 - Qwen 门户使用
catalog、auth和refreshOAuth。 - MiniMax 和 Xiaomi 使用
catalog加上使用挂钩,因为它们的/usage行为由插件拥有,即使推断仍然通过共享传输运行。
运行时辅助工具
插件可以通过api.runtime 访问选定的核心辅助工具。对于 TTS:
textToSpeech返回用于文件/语音笔记表面的正常核心 TTS 输出负载。- 使用核心
messages.tts配置和提供商选择。 - 返回 PCM 音频缓冲区 + 采样率。插件必须为提供商重新采样/编码。
listVoices对于每个提供商是可选的。将其用于供应商拥有的语音选择器或设置流程。- 语音列表可以包含更丰富的元数据,例如区域设置、性别和个性标签,用于感知提供商的选择器。
- OpenAI 和 ElevenLabs 目前支持电话。Microsoft 不支持。
api.registerSpeechProvider(...) 注册语音提供商。
- 将 TTS 策略、回退和回复传递保留在核心中。
- 使用语音提供商来实现供应商拥有的合成行为。
- 传统的 Microsoft
edge输入会被规范化为microsoft提供商 ID。 - 首选的所有权模型是以公司为导向的:一个供应商插件可以拥有文本、语音、图像和未来的媒体提供商,随着 OpenClaw 添加这些功能合约。
- 将编排、回退、配置和渠道连线保留在核心中。
- 将供应商行为保留在提供商插件中。
- 增量扩展应保持类型化:新的可选方法、新的可选结果字段、新的可选功能。
- 如果 OpenClaw 稍后添加新功能(例如视频生成),请先定义核心功能合约,然后让供应商插件对其进行注册。
api.runtime.mediaUnderstanding.*是用于图像/音频/视频理解的首选共享接口。- 使用核心媒体理解音频配置 (
tools.media.audio) 和提供商回退顺序。 - 当未生成转录输出时(例如跳过/不支持的输入),返回
{ text: undefined }。 api.runtime.stt.transcribeAudioFile(...)保留为兼容性别名。
api.runtime.subagent 启动后台子代理运行:
provider和model是可选的每次运行覆盖,而不是持久的会话更改。- OpenClaw 仅针对受信任的调用方遵守这些覆盖字段。
- 对于插件拥有的回退运行,操作员必须使用
plugins.entries.<id>.subagent.allowModelOverride: true选择加入。 - 使用
plugins.entries.<id>.subagent.allowedModels将受信任的插件限制为特定的规范provider/model目标,或使用"*"显式允许任何目标。 - 不受信任的插件子代理运行仍然有效,但覆盖请求将被拒绝,而不是静默回退。
api.registerWebSearchProvider(...) 注册网络搜索提供商。
注意:
- 将提供商选择、凭据解析和共享请求语义保留在核心中。
- 使用网络搜索提供商进行特定于供应商的搜索传输。
- 对于需要搜索行为但不依赖代理工具封装的功能/渠道插件,
api.runtime.webSearch.*是首选的共享接口。
Gateway(网关) HTTP 路由
插件可以使用api.registerHttpRoute(...) 公开 HTTP 端点。
path:网关 HTTP 服务器下的路由路径。auth:必填。使用"gateway"要求正常的网关身份验证,或使用"plugin"进行插件管理的身份验证/Webhook 验证。match:可选。"exact"(默认)或"prefix"。replaceExisting:可选。允许同一插件替换其自己现有的路由注册。handler:当路由处理了请求时返回true。
api.registerHttpHandler(...)已过时。请使用api.registerHttpRoute(...)。- 插件路由必须显式声明
auth。 - 除非
replaceExisting: true,否则将拒绝精确的path + match冲突,并且一个插件不能替换另一个插件的路由。 - 将拒绝具有不同
auth级别的重叠路由。请将exact/prefix传递链仅保留在同一身份验证级别。
插件 SDK 导入路径
在编写插件时,使用 SDK 子路径而不是单一的openclaw/plugin-sdk 导入:
openclaw/plugin-sdk/plugin-entry用于插件注册原语。openclaw/plugin-sdk/core用于通用的面向插件的共享合约。- 用于共享设置/身份验证/回复/Webhook 连接的稳定渠道原语,如
openclaw/plugin-sdk/channel-setup、openclaw/plugin-sdk/channel-pairing、openclaw/plugin-sdk/channel-contract、openclaw/plugin-sdk/channel-feedback、openclaw/plugin-sdk/channel-inbound、openclaw/plugin-sdk/channel-lifecycle、openclaw/plugin-sdk/channel-reply-pipeline、openclaw/plugin-sdk/command-auth、openclaw/plugin-sdk/secret-input和openclaw/plugin-sdk/webhook-ingress。channel-inbound是防抖、提及匹配、信封格式化和入站信封上下文辅助函数的共享归宿。 - 用于共享运行时/配置辅助函数的域子路径,如
openclaw/plugin-sdk/channel-config-helpers、openclaw/plugin-sdk/allow-from、openclaw/plugin-sdk/channel-config-schema、openclaw/plugin-sdk/channel-policy、openclaw/plugin-sdk/config-runtime、openclaw/plugin-sdk/infra-runtime、openclaw/plugin-sdk/agent-runtime、openclaw/plugin-sdk/lazy-runtime、openclaw/plugin-sdk/reply-history、openclaw/plugin-sdk/routing、openclaw/plugin-sdk/status-helpers、openclaw/plugin-sdk/runtime-store和openclaw/plugin-sdk/directory-runtime。 openclaw/plugin-sdk/channel-runtime仅保留为兼容性垫片。新代码应改为导入范围更窄的原语。- 捆绑扩展的内部内容仍保持私有。外部插件应仅使用
openclaw/plugin-sdk/*子路径。OpenClaw 核心/测试代码可以使用extensions/<id>/index.js、api.js、runtime-api.js、setup-entry.js下的仓库公共入口点以及范围狭窄的文件,如login-qr-api.js。切勿从核心或另一个扩展导入extensions/<id>/src/*。 - 仓库入口点划分:
extensions/<id>/api.js是辅助函数/类型汇总桶,extensions/<id>/runtime-api.js是仅运行时汇总桶,extensions/<id>/index.js是捆绑插件入口,而extensions/<id>/setup-entry.js是设置插件入口。 - 不再保留捆绑的渠道品牌公共子路径。特定渠道的辅助函数和运行时接缝位于
extensions/<id>/api.js和extensions/<id>/runtime-api.js之下;公共 SDK 契约是通用的共享原语。
- 新代码请避免使用根
openclaw/plugin-sdkbarrel。 - 首先优先使用狭窄的稳定原语。较新的 setup/pairing/reply/
feedback/contract/inbound/threading/command/secret-input/webhook/infra/
allowlist/status/message-工具 子路径是新的捆绑和外部插件工作的预期合约。
目标解析/匹配属于
openclaw/plugin-sdk/channel-targets。 消息操作门控和反应消息 ID 辅助工具属于openclaw/plugin-sdk/channel-actions。 - 捆绑的特定于扩展的辅助 barrels 默认是不稳定的。如果一个辅助工具仅被捆绑扩展需要,请将其保留在扩展的本地
api.js或runtime-api.js接缝之后,而不是将其提升到openclaw/plugin-sdk/<extension>中。 - 除非被显式添加回公共合约,否则渠道品牌的捆绑 bars 保持私有。
- 诸如
image-generation、media-understanding和speech之类的特定于功能的子路径之所以存在,是因为捆绑/原生插件今天在使用它们。它们的存在本身并不意味着每个导出的辅助工具都是长期冻结的外部合约。
消息工具架构
插件应拥有特定于渠道的describeMessageTool(...) 架构
贡献。将特定于提供商的字段保留在插件中,而不是在共享核心中。
对于共享的可移植架构片段,请重用通过 openclaw/plugin-sdk/channel-actions 导出的通用辅助工具:
createMessageToolButtonsSchema()用于按钮网格样式的有效载荷createMessageToolCardSchema()用于结构化卡片有效载荷
渠道目标解析
渠道插件应拥有特定于渠道的目标语义。保持共享的出站主机通用性,并使用消息适配器表面来处理提供商规则:messaging.inferTargetChatType({ to })决定在目录查找之前是否将规范化目标 视为direct、group还是channel。messaging.targetResolver.looksLikeId(raw, normalized)告诉核心(core)一个输入是否应该直接跳到类似 ID 的解析,而不是目录搜索。- 当核心在规范化之后或目录未命中之后需要最终的提供商拥有的解析时,
messaging.targetResolver.resolveTarget(...)是插件回退选项。 - 一旦解析了目标,
messaging.resolveOutboundSessionRoute(...)负责提供商特定的会话路由构建。
- 对于在搜索对等方/组之前应该发生的类别决策,请使用
inferTargetChatType。 - 对于“将其视为显式/原生目标 ID”的检查,请使用
looksLikeId。 - 请将
resolveTarget用于提供商特定的规范化回退,而不是用于广泛的目录搜索。 - 请将提供商原生的 ID(如聊天 ID、线程 ID、JID、句柄和房间 ID)保留在
target值或提供商特定的参数中,而不是通用 SDK 字段中。
配置支持的目录
从配置派生目录条目的插件应将该逻辑保留在插件中,并重用openclaw/plugin-sdk/directory-runtime 中的共享辅助程序。
当渠道需要配置支持的对等方/组时,请使用此功能,例如:
- 允许列表驱动的私信对等方
- 配置的渠道/组映射
- 账户范围的静态目录回退
directory-runtime 中的共享辅助程序仅处理通用操作:
- 查询过滤
- 限制应用
- 去重/规范化辅助程序
- 构建
ChannelDirectoryEntry[]
提供商目录
提供商插件可以使用registerProvider({ catalog: { run(...) { ... } } }) 定义用于推理的模型目录。
catalog.run(...) 返回与 OpenClaw 写入 models.providers 相同的形状:
{ provider }用于一个提供商条目{ providers }用于多个提供商条目
catalog。
catalog.order 控制插件的目录相对于 OpenClaw 内置的隐式提供商合并的时间:
simple: 纯 API 密钥或环境变量驱动的提供商profile: 当身份验证配置文件存在时出现的提供商paired: 综合多个相关提供商条目的提供商late: 最后一遍,在其他隐式提供商之后
discovery仍作为旧版别名工作- 如果同时注册了
catalog和discovery,OpenClaw 将使用catalog
只读渠道检查
如果您的插件注册了渠道,建议在实现resolveAccount(...) 的同时也实现 plugin.config.inspectAccount(cfg, accountId)。
原因:
resolveAccount(...)是运行时路径。它允许假定凭据已完全物化,并且在缺少所需机密时可以快速失败。- 仅为了描述配置,
openclaw status、openclaw status --all、openclaw channels status、openclaw channels resolve等只读命令路径以及 doctor/config 修复流程不应需要物化运行时凭据。
inspectAccount(...) 行为:
- 仅返回描述性的帐户状态。
- 保留
enabled和configured。 - 在相关时包含凭据源/状态字段,例如:
tokenSource、tokenStatusbotTokenSource、botTokenStatusappTokenSource、appTokenStatussigningSecretSource、signingSecretStatus
- 您不需要仅为了报告只读可用性而返回原始令牌值。返回
tokenStatus: "available"(以及匹配的源字段)对于状态样式的命令来说就足够了。 - 当凭据通过 SecretRef 配置但在当前命令路径中不可用时,请使用
configured_unavailable。
包打包
插件目录可能包含一个带有openclaw.extensions 的 package.json:
name/<fileBase>。
如果您的插件导入了 npm 依赖项,请将其安装在该目录中,以便 node_modules 可用(npm install / pnpm install)。
安全防护:每个 openclaw.extensions 条目在解析符号链接后必须保留在插件目录内。转义包目录的条目将被拒绝。
安全说明:openclaw plugins install 使用 npm install --ignore-scripts(无生命周期脚本)安装插件依赖项。请保持插件依赖树为“纯 JS/TS”,并避免需要 postinstall 构建的包。
可选:openclaw.setupEntry 可以指向一个仅用于设置的轻量级模块。当 OpenClaw 需要为已禁用的渠道插件提供设置界面,或者当渠道插件已启用但尚未配置时,它会加载 setupEntry 而不是完整的插件入口。当您的主插件入口还连接工具、钩子或其他仅运行时代码时,这可以使启动和设置变得更轻量。
可选:openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen 可以使渠道插件在网关的预监听启动阶段选择进入相同的 setupEntry 路径,即使渠道已经配置也是如此。
仅当 setupEntry 完全覆盖网关开始监听之前必须存在的启动界面时,才使用此选项。实际上,这意味着设置入口必须注册启动所依赖的每个渠道拥有的能力,例如:
- 渠道注册本身
- 任何必须在网关开始监听之前可用的 HTTP 路由
- 任何必须在同一窗口期间存在的网关方法、工具或服务
渠道目录元数据
渠道插件可以通过openclaw.channel 宣布设置/发现元数据,并通过 openclaw.install 提供安装提示。这使得核心目录保持无数据。
示例:
~/.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": {...} } } ] }。
上下文引擎插件
上下文引擎插件拥有会话上下文的编排,包括摄入、组装和压缩。通过插件中的api.registerContextEngine(id, factory) 注册它们,然后使用 plugins.slots.contextEngine 选择活动引擎。
当您的插件需要替换或扩展现有的默认上下文管道,而不仅仅是添加内存搜索或钩子时,请使用此方法。
compact() 的实现并明确地委托它:
添加新功能
当插件需要不符合当前 API 的行为时,不要通过私有侵入绕过插件系统。添加缺失的功能。 推荐顺序:- 定义核心契约 决定核心应该拥有哪些共享行为:策略、回退、配置合并、生命周期、面向渠道的语义和运行时辅助程序形状。
- 添加类型化的插件注册/运行时表面
使用最小有用的类型化功能表面扩展
OpenClawPluginApi和/或api.runtime。 - 连接核心 + 渠道/功能消费者 渠道和功能插件应该通过核心使用新功能,而不是直接导入供应商实现。
- 注册供应商实现 然后供应商插件针对该功能注册其后端。
- 添加契约覆盖 添加测试,以确所有权和注册形状随时间保持明确。
能力清单
添加新能力时,实现通常应该同时涉及以下层面: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/contracts/registry.ts中的所有权/合约断言docs/中的操作员/插件文档
能力模板
最小模式:- 核心拥有能力合约 + 编排
- 供应商插件拥有供应商实现
- 功能/渠道插件使用运行时辅助工具
- 合约测试明确所有权
本页面源自 openclaw/openclaw,由 BeaversLab 翻译,遵循 MIT 协议 发布。