提供者钩子和目录
三个提供者层、完整的钩子顺序表、一个可运行的提供者示例、内置钩子形状,以及提供者目录如何合并。本文是插件架构内部机制指南的一部分。
提供者运行时钩子¶
提供者插件包含三个层:
- 清单元数据,用于低成本的预运行时查找:
setup.providers[].envVars、providerAuthAliases、providerAuthChoices和channelConfigs。 - 配置时钩子:
catalog加上applyConfigDefaults。 - 运行时钩子:40 多个可选钩子,涵盖认证、模型解析、流包装、 思考层级、重放策略和用量端点。参见 钩子顺序与用法。
OpenClaw 仍然负责通用代理循环、故障转移、转录处理和工具策略。这些钩子是提供者特定行为的扩展面,无需一整套自定义推理传输。
钩子查找首先使用已准备的生成结果或匹配的已加载注册表。 若未命中,提供者/模型作用域的发现会复用加载器的注册表缓存; 显式的运行时发现失效会清除该查找结果,而不会让另一个提供者缓存保留旧钩子。 为尝试而准备的提供者句柄会保留其选中的插件,而每个钩子都会接收当前的调用上下文。
合成认证查找包含来自声明提供者或 CLI 后端拥有者的仅认证发现条目。静态模型目录行不会替换这些认证实现。如果拥有者未提供合成认证钩子,查找将返回无合成结果,且不会加载无关的发现条目。对于没有声明拥有者的别名,仍然提供轻量级条目回退。外部认证捕获在只读 worker 工作之前仍会准备全新的结果。
当提供者拥有基于环境变量的凭据,且通用认证/状态/模型选择器路径无需加载插件运行时即可看到这些凭据时,请使用清单中的 setup.providers[].envVars。当一个提供者 ID 应复用另一个提供者 ID 的环境变量、认证配置文件、配置支持的认证以及 API 密钥接入选择时,请使用清单中的 providerAuthAliases。当接入/认证选择 CLI 界面需要知道提供者的选择 ID、组标签和简单的单标志认证接线,而无需加载提供者运行时,请使用清单中的 providerAuthChoices。将提供者运行时 envVars 保留用于面向操作者的提示,例如接入标签或 OAuth client-id/client-secret 设置变量。
通过所属的 channelConfigs.<id>.schema 和设置描述符来描述由环境变量驱动的渠道设置与认证。
钩子顺序与用法¶
对于模型/提供者插件,OpenClaw 大致按以下顺序调用钩子。“何时使用”列是快速决策指南。OpenClaw 不再调用的仅用于兼容性的提供者字段(例如 ProviderPlugin.capabilities 和 suppressBuiltInModel)特意未在此列出。
| 钩子 | 作用 | 何时使用 |
|---|---|---|
catalog |
在 models.json 生成期间将提供者配置发布到 models.providers |
提供者拥有目录或 base URL 默认值 |
applyConfigDefaults |
在配置物化期间应用提供者拥有的全局配置默认值 | 默认值取决于认证模式、环境或提供者模型族语义 |
| (内置模型查找) | OpenClaw 首先尝试常规注册表/目录路径 | (非插件钩子) |
normalizeModelId |
在查找前规范化遗留的或预览版 model-id 别名 | 提供者在规范模型解析前负责别名清理 |
normalizeTransport |
在通用模型组装前规范化提供者族的 api / baseUrl |
提供者负责同一传输族中自定义提供者 ID 的传输清理 |
normalizeConfig |
在运行时/提供者解析前规范化 models.providers.<id> |
提供者需要应由所属插件承载的配置清理 |
applyNativeStreamingUsageCompat |
对配置提供者应用原生流式用量兼容性重写 | 提供者需要端点驱动的原生流式用量元数据修复 |
resolveConfigApiKey |
在运行时认证加载前为配置提供者解析环境变量标记认证 | 提供者暴露自己的环境变量标记 API 密钥解析钩子 |
resolveSyntheticAuth |
在不持久化明文的情况下呈现本地/自托管或配置支持的认证 | 提供者可以使用合成/本地凭据标记运行 |
| 钩子 | 作用 | 使用时机 |
|---|---|---|
resolveExternalAuthProfiles |
叠加由提供方拥有的外部认证配置文件;对于 CLI/应用拥有的凭据,默认 persistence 为 runtime-only |
提供方复用外部认证凭据,而不持久化复制的刷新令牌;在清单中声明 contracts.externalAuthProviders |
shouldDeferSyntheticProfileAuth |
将已存储的合成配置文件占位符置于基于环境变量/配置的认证之后 | 提供方存储不应获得优先级的合成占位配置文件 |
resolveDynamicModel |
为尚未存在于本地注册表中的提供方拥有的模型 ID 提供同步回退 | 提供方接受任意上游模型 ID |
prepareDynamicModel |
返回异步准备好的模型,或在重试 resolveDynamicModel 之前预热可复用元数据 |
提供方在解析未知 ID 前需要网络元数据 |
normalizeResolvedModel |
在嵌入式运行器使用已解析模型之前的最终重写 | 提供方需要传输层重写,但仍使用核心传输层 |
normalizeToolSchemas |
在嵌入式运行器看到工具架构之前对其进行规范化 | 提供方需要传输族架构清理 |
inspectToolSchemas |
在规范化后显示提供方拥有的架构诊断信息 | 提供方希望获得关键字警告,而无需向核心教授提供方特定规则 |
resolveReasoningOutputMode |
选择原生与带标记的推理输出契约 | 提供方需要带标记的推理/最终输出,而不是原生字段 |
prepareExtraParams |
在通用流选项包装器之前对请求参数进行规范化 | 提供方需要默认请求参数或按提供方清理参数 |
createStreamFn |
使用自定义传输层完全替换常规流路径 | 提供方需要自定义线路协议,而不仅仅是包装器 |
wrapStreamFn |
在应用通用包装器之后的流包装器 | 提供方需要请求头/正文/模型兼容包装器,而不需要自定义传输层 |
reconcileLocalService |
在本地服务健康检查之后、每次请求之前协调提供方拥有的状态 | 受管理的本地路由器必须重新加载持久提供方状态,而无需将提供方策略移入核心 |
resolveTransportTurnState |
附加原生的每轮次请求头、元数据或 WebSocket 策略 | 提供方希望通用传输层发送提供方原生的轮次标识,或调整 WebSocket 请求头和回退冷却时间 |
resolveWebSocketSessionPolicy |
用于 WebSocket 策略的已弃用兼容钩子 | 现有插件将 WebSocket 字段迁移到 resolveTransportTurnState |
formatApiKey |
认证配置文件格式化器:已存储的配置文件成为运行时 apiKey 字符串 |
提供方存储额外认证元数据,并需要自定义运行时令牌格式 |
refreshOAuth |
用于自定义刷新端点或刷新失败策略的 OAuth 刷新覆盖 | 提供方不适合共享的 OpenClaw 刷新器 |
buildAuthDoctorHint |
在 OAuth 刷新失败时附加的修复提示 | 提供方在刷新失败后需要提供方拥有的认证修复指导 |
matchesContextOverflowError |
提供方拥有的上下文窗口溢出匹配器 | 提供方存在通用启发式方法会遗漏的原始溢出错误 |
classifyFailoverReason |
提供方拥有的故障转移原因分类 | 提供方可以将原始 API/传输错误映射为速率限制/过载等 |
| 钩子 | 作用 | 使用时机 |
|---|---|---|
isCacheTtlEligible |
代理/回传提供商的 Prompt 缓存策略 | 提供商需要代理特定的缓存 TTL 门控 |
buildMissingAuthMessage |
通用缺失认证恢复消息的替代 | 提供商需要提供商特定的缺失认证恢复提示 |
augmentModelCatalog |
发现后追加的合成/最终目录行(已弃用,见下文) | 提供商需要在 models list 和选择器中提供合成前向兼容行 |
resolveThinkingProfile |
模型特定的 /think 级别集、显示标签和默认值 |
提供商为所选模型暴露自定义思考阶梯或二元标签 |
isBinaryThinking |
开/关推理切换兼容性钩子 | 提供商仅暴露二元思考开/关 |
supportsXHighThinking |
xhigh 推理支持兼容性钩子 |
提供商希望仅在部分模型上启用 xhigh |
resolveDefaultThinkingLevel |
默认 /think 级别兼容性钩子 |
提供商拥有某个模型族的默认 /think 策略 |
isModernModelRef |
用于实时配置过滤和冒烟选择的现代模型匹配器 | 提供商拥有实时/冒烟首选模型匹配 |
prepareRuntimeAuth |
在推理前将已配置的凭据交换为实际的运行时 Token/密钥 | 提供商需要 Token 交换或短期请求凭据 |
resolveUsageAuth |
解析 /usage 及相关状态界面的用量/计费凭据 |
提供商需要自定义用量/配额 Token 解析或不同的用量凭据 |
fetchUsageSnapshot |
在认证解析后获取并规范化提供商特定的用量/配额快照 | 提供商需要提供商特定的用量端点或负载解析器 |
createEmbeddingProvider |
为记忆/搜索构建提供商拥有的嵌入适配器 | 记忆嵌入行为属于提供商插件 |
buildReplayPolicy |
返回控制提供商转录处理的回放策略 | 提供商需要自定义转录策略(例如,剥离思考块) |
sanitizeReplayHistory |
在通用转录清理后重写回放历史 | 提供商需要超出共享压缩辅助的提供商特定回放重写 |
validateReplayTurns |
嵌入式运行器之前的最终回放轮次验证或重塑 | 提供商传输需要在通用清理后进行更严格的轮次验证 |
onModelSelected |
运行提供商拥有的选择后副作用 | 当模型变为活动时,提供商需要遥测或提供商拥有的状态 |
reconcileLocalService 仅针对已配置的本地服务运行,包括从当前 Gateway 进程外部复用的健康进程。保持其低成本、幂等且可感知中止。拒绝会阻止提供商请求并释放其租约,而不会将健康进程归类为启动失败。
规范化分发是钩子特定的:
- 模型引用在
normalizeModelId分发之前应用一次清单声明的模型 ID 规范化。匹配的提供商钩子可以细化该准备好的模型 ID;空结果会保持其不变。OpenClaw 不会尝试其他提供商的规范化钩子,也不会在之后重新应用清单规则。 引用解析读取所选运行时注册表,而不激活插件。可执行规范化需要一个准备好的运行时所有者;没有所有者的读取仅使用静态清单策略。 直接注册的提供商拥有其 ID;兼容别名仅在不存在字面提供商时匹配,从而保留仅别名路由和显式 API 所有者资格。 normalizeTransport首先尝试匹配的提供商。只有当它未更改api或baseUrl,并且提供商没有models.providers.<id>条目时,才会尝试其他传输钩子,并在第一次更改时停止。normalizeConfig首先使用拥有捆绑提供商的轻量级策略表面。如果该表面没有normalizeConfig钩子,OpenClaw 可以调用匹配的运行时所有者,前提是允许运行时加载,并且当提供配置时,该所有者具有显式插件激活。它从不扫描其他提供商的钩子,也不会在拥有钩子返回无更改后继续回退。 配置组装传递allowRuntimePluginLoad: false,因此它在不加载提供商运行时的情况下使用捆绑策略。
Google 系列配置清理由 Google 插件自身的
normalizeConfig 钩子实现,并与它的轻量策略界面共享。它不是
独立的核心兼容性兜底。
如果提供商需要完全自定义的通信协议或自定义请求执行器, 那属于另一类扩展。这些钩子用于仍然运行在 OpenClaw 正常推理循环上的提供商行为。
resolveUsageAuth 决定 OpenClaw 应调用 fetchUsageSnapshot,还是
回退到用于用量/状态界面的通用凭据解析。当提供商
拥有用量凭据时返回
{ token, accountId?, subscriptionType?, rateLimitTier? }(可选的计划元数据会流入
fetchUsageSnapshot);当由提供商拥有的用量鉴权已处理请求,并且
必须抑制通用 API 密钥/OAuth 回退时,返回
{ handled: true };当提供商未处理用量鉴权时,返回 null 或 undefined。
在清单的
providerUsageAuthEnvVars 中声明组织或计费凭据。这可以让通用发现和密钥脱敏
界面识别它们,而不会将它们变成推理鉴权候选项。
提供商示例¶
example-proxy、exchangeToken 和 fetchExampleProxyUsage 是你自己的提供商 id 和供应商 API 调用的占位符,
而不是导出的 OpenClaw 辅助函数。
api.registerProvider({
id: "example-proxy",
label: "Example Proxy",
auth: [],
catalog: {
order: "simple",
run: async (ctx) => {
const apiKey = ctx.resolveProviderApiKey("example-proxy").apiKey;
if (!apiKey) {
return null;
}
return {
provider: {
baseUrl: "https://proxy.example.com/v1",
apiKey,
api: "openai-completions",
models: [{ id: "auto", name: "Auto" }],
},
};
},
},
resolveDynamicModel: (ctx) => ({
id: ctx.modelId,
name: ctx.modelId,
provider: "example-proxy",
api: "openai-completions",
baseUrl: "https://proxy.example.com/v1",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 8192,
}),
prepareRuntimeAuth: async (ctx) => {
const exchanged = await exchangeToken(ctx.apiKey);
return {
apiKey: exchanged.token,
baseUrl: exchanged.baseUrl,
expiresAt: exchanged.expiresAt,
};
},
resolveUsageAuth: async (ctx) => {
const auth = await ctx.resolveOAuthToken();
return auth ? { token: auth.token } : null;
},
fetchUsageSnapshot: async (ctx) => {
return await fetchExampleProxyUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn);
},
});
内置示例¶
内置提供商插件组合上述钩子,以适配各供应商的目录、
鉴权、思考、重放和用量需求。权威钩子集合位于每个插件的 extensions/ 下;本页说明其形态,而不是
照搬列表。
透传目录提供商
OpenRouter、Kilocode、Z.AI 和 xAI 注册 catalog 以及
resolveDynamicModel / prepareDynamicModel,以便在 OpenClaw 静态目录之前呈现上游
模型 id。
OAuth 和用量端点提供商
GitHub Copilot、Gemini CLI、ChatGPT Codex、MiniMax、Xiaomi 和 z.ai 将
prepareRuntimeAuth 或 formatApiKey 与 resolveUsageAuth +
fetchUsageSnapshot 配对,以负责令牌交换和 /usage 集成。
重放和对话记录清理家族
共享命名家族(google-gemini、passthrough-gemini、
anthropic-by-model、hybrid-anthropic-openai)让提供商通过 buildReplayPolicy 选择加入
对话记录策略,而不是每个插件重新实现清理。
仅目录提供商
byteplus、cloudflare-ai-gateway、huggingface、kimi-coding、nvidia、
qianfan、synthetic、together、venice、vercel-ai-gateway 和
volcengine 仅注册 catalog,并运行在共享推理循环上。
Anthropic 专用流辅助函数
Beta 请求头、/fast / serviceTier 和 context1m 位于 Anthropic 插件公开的 api.ts / contract-api.ts 接缝
(wrapAnthropicProviderStream、resolveAnthropicBetas、
resolveAnthropicFastMode、resolveAnthropicServiceTier)中,而不是在
通用 SDK 中。
提供商目录¶
提供商插件可以使用
registerProvider({ catalog: { run(...) { ... } } }) 为推理定义模型目录。
catalog.run(...) 返回与 OpenClaw 写入
models.providers 的相同形状:
- 一个提供商条目使用
{ provider } - 多个提供商条目使用
{ providers }
当插件拥有提供商特定的模型 id、基础 URL
默认值或受鉴权控制的模型元数据时,使用 catalog。
catalog.order 控制插件目录相对于 OpenClaw 内置隐式提供商的合并时机:
simple:普通 API 密钥或环境变量驱动的提供商profile:当存在鉴权配置文件时出现的提供商paired:合成多个相关提供商条目的提供商late:最后处理,在其他隐式提供商之后
在键冲突时,较晚的提供商获胜,因此插件可以有意覆盖具有相同提供商 id 的内置提供商条目。
插件还可以通过
api.registerModelCatalogProvider({ provider, kinds, staticCatalog, liveCatalog
}) 发布只读模型行。这是列表/帮助/选择器界面的前向路径,并支持
text、voice、image_generation、video_generation 和 music_generation
行。提供商插件仍负责实时端点调用、令牌交换和供应商响应映射;核心负责通用行形状、来源标签和媒体工具帮助格式化。媒体生成提供商注册会根据 defaultModel、models 和 capabilities 自动合成静态目录行。
兼容性:
discovery曾是catalog的旧别名。OpenClaw 已在 2026.4.26 中移除该别名及其弃用警告- 将
discovery重命名为catalog。仍注册discovery的提供商插件不会发布任何目录行 augmentModelCatalog已弃用;内置提供商应通过registerModelCatalogProvider发布补充行。其移除门槛为 2026-10-01
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw