如何迁移
有序的迁移步骤。请按顺序执行;每个步骤都是自包含的。属于 Plugin SDK 迁移 指南的一部分。
托管节点工作区获取¶
节点宿主命令应在使用返回的工作区之前等待 context.acquireManagedWorkspaceAsync(request),并在 finally 中释放其租约。宿主会在获取前后检查确切的调用会话,如果调用关闭,则释放迟到的租约,并将已准备工作区的 SQLite 工作保持在节点事件循环之外。在开始外部工作之前,继续检查命令取消。
在 2026.9.4 中发布的同步 context.acquireManagedWorkspace(request) 回调仍可用于外部插件兼容性,但已弃用。其返回值仍保持同步。内置命令使用异步对应函数;需要该对应函数的插件应报告不可用的宿主能力,而不是回退到同步获取。移除该已弃用回调需要一个明确批准的、未来的破坏性 Plugin SDK 发布。next-plugin-sdk-major 门禁本身并不授权移除,也不会缩短现有兼容窗口。
如何迁移¶
1. 迁移运行时配置加载/写入辅助函数
内置插件应停止直接调用 api.runtime.config.loadConfig() 和 api.runtime.config.writeConfigFile(...)。优先使用已经传入当前调用路径的配置。需要当前进程快照的长生命周期处理器可以使用 api.runtime.config.current()。长生命周期代理工具应在 execute 内读取 ctx.getRuntimeConfig(),以便在配置写入之前创建的工具仍能看到刷新后的配置。
配置写入应通过事务辅助函数进行,并带有明确的写入后策略:
await api.runtime.config.mutateConfigFile({
afterWrite: { mode: "auto" },
mutate(draft) {
draft.plugins ??= {};
},
});
当更改需要干净的网关重启时,使用 afterWrite: { mode: "restart", reason: "..." };仅当调用方拥有后续处理并有意抑制重载规划器时,使用 afterWrite: { mode: "none", reason: "..." }。变更结果包含用于测试和日志的带类型 followUp 摘要;网关仍负责应用或安排重启。
loadConfig 和 writeConfigFile 已从插件运行时中移除。内置插件和仓库运行时代码由 pnpm check:deprecated-api-usage 和 pnpm check:no-runtime-action-load-config 保护:新的生产插件用法会直接失败,直接配置写入会失败,网关服务器方法必须使用请求运行时快照,运行时频道发送/操作/客户端辅助函数必须从其边界接收配置,长生命周期运行时模块允许零个环境 loadConfig() 调用。
新插件代码应避免使用宽泛的 openclaw/plugin-sdk/config-runtime 桶模块。请使用适合任务的窄子路径:
| 需求 | 导入 |
|---|---|
配置类型,例如 OpenClawConfig |
openclaw/plugin-sdk/config-contracts |
| 插件入口配置查找 | api.pluginConfig |
| 配置合并 | 配置边界处的插件本地逻辑 |
| 当前运行时快照读取 | openclaw/plugin-sdk/runtime-config-snapshot |
| 配置写入 | openclaw/plugin-sdk/config-mutation |
| 会话存储辅助函数 | openclaw/plugin-sdk/session-store-runtime |
| Markdown 表格配置 | api.runtime.channel.text.resolveMarkdownTableMode |
| 频道组策略、提及要求和发送者工具策略 | openclaw/plugin-sdk/channel-policy |
| 提供方默认组策略回退辅助函数 | openclaw/plugin-sdk/runtime-group-policy |
| 机密输入解析 | openclaw/plugin-sdk/secret-input-runtime |
| 模型/会话覆盖 | openclaw/plugin-sdk/model-session-runtime |
api.pluginConfig 是注册作用域的,不是实时 getter。替换 resolveLivePluginConfigObject(...) 时,需要通过运行时边界提供的当前配置保持新鲜度。注入的 Markdown 解析器保留频道/账户优先级和频道默认值;markdown-table-runtime 是私有的、仅限 JavaScript 的宿主导出。
请单独检查命名类型。config-contracts 不导出 TtsMode、TtsPersonaConfig、TtsPersonaFallbackPolicy 或 SessionResetMode;session-store-runtime 也不导出 SessionResetMode。需要这些名称的现有调用方必须保留保留的类型导入,或显式适配其类型。Talk 配置、cron-store 操作、上下文可见性配置解析和危险名称检查也缺少完整的现代类型化公共映射。缺失的公共契约需要 SDK 所有者决策,而不是导入私有的聚焦实现。
内置插件及其测试受扫描器保护,以避免宽泛桶模块,使导入和模拟保持在其所需行为的本地。桶模块仍为外部兼容性而存在,但新代码不应依赖它。
2. 将嵌入式工具结果扩展迁移到中间件
内置插件必须将仅限嵌入式运行时的 api.registerEmbeddedExtensionFactory(...) 工具结果处理器替换为运行时中立中间件:
// OpenClaw runtime tools and Codex runtime dynamic tools (result may be
// transformed). Codex-native tool results are also relayed for observation,
// but their transformed output never reaches the model: the Codex
// PostToolUse hook contract cannot replace a native tool response.
api.registerAgentToolResultMiddleware(async (event) => {
return compactToolResult(event);
}, {
runtimes: ["openclaw", "codex"],
});
同时更新插件清单:
已安装插件也可以注册工具结果中间件,前提是显式启用,并且每个目标运行时都在 contracts.agentToolResultMiddleware 中声明。未声明的已安装中间件注册会被拒绝。
3. 将审批原生处理器迁移到能力事实
支持审批的通道插件通过 approvalCapability.nativeRuntime 以及共享运行时上下文注册表暴露原生审批行为:
- 将
approvalCapability.handler.loadRuntime(...)替换为approvalCapability.nativeRuntime。 - 将审批专用的认证/投递从旧版
plugin.auth/plugin.approvals接线迁移到approvalCapability。 ChannelPlugin.approvals已从公开通道插件契约中移除;请将投递/原生/渲染字段迁移到approvalCapability。plugin.auth仅保留用于通道登录/登出流程;核心不再从那里读取审批认证钩子。- 通过
openclaw/plugin-sdk/channel-runtime-context注册通道拥有的运行时对象(客户端、令牌、Bolt 应用)。 - 不要从原生审批处理器发送插件拥有的重路由通知;核心负责根据实际投递结果发出已路由至其他位置的通知。
- 将
channelRuntime传入createChannelManager(...)时,请提供真实的createPluginRuntime().channel接口表面 - 部分存根会被拒绝。
有关当前审批能力布局,请参阅 通道插件。
4. 审计 Windows 包装器回退行为
如果你的插件使用 openclaw/plugin-sdk/windows-spawn,未解析的 Windows .cmd/.bat 包装器现在会失败关闭,除非你显式传入 allowShellFallback: true:
// Before
const program = applyWindowsSpawnProgramPolicy({ candidate });
// After
const program = applyWindowsSpawnProgramPolicy({
candidate,
// Only set this for trusted compatibility callers that intentionally
// accept shell-mediated fallback.
allowShellFallback: true,
});
如果你的调用方并非有意依赖 shell 回退,请不要设置 allowShellFallback,而是处理抛出的错误。
5. 查找已弃用的导入
grep -r "plugin-sdk/compat" my-plugin/
grep -r "plugin-sdk/infra-runtime" my-plugin/
grep -r "plugin-sdk/config-runtime" my-plugin/
grep -r "openclaw/extension-api" my-plugin/
6. 替换为聚焦导入
请检查导出名称和类型化公开契约,以及导入路径。一些函数已重命名;并非每个保留的辅助函数或命名类型都有现代公开替代项:
// Before (deprecated backwards-compatibility layer)
import {
createChannelReplyPipeline,
createPluginRuntimeStore,
} from "openclaw/plugin-sdk/compat";
// After (modern focused imports)
import {
createChannelMessageReplyPipeline as createChannelReplyPipeline,
} from "openclaw/plugin-sdk/channel-outbound";
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
显式别名可保留现有 createChannelReplyPipeline(...) 调用点。现代导出项是 createChannelMessageReplyPipeline;有关其余函数和命名类型,请参阅 保留的通道门面映射。
对于宿主端辅助函数,请使用注入的插件运行时,而不是直接导入:
// Before (deprecated extension-api bridge)
import { runEmbeddedAgent } from "openclaw/extension-api";
const result = await runEmbeddedAgent({ sessionId, prompt });
// After (injected runtime)
const result = await api.runtime.agent.runEmbeddedAgent({ sessionId, prompt });
其他旧版桥接辅助函数也采用相同模式:
| 旧导入 | 现代等效项 |
|---|---|
resolveAgentDir |
api.runtime.agent.resolveAgentDir |
resolveAgentWorkspaceDir |
api.runtime.agent.resolveAgentWorkspaceDir |
resolveAgentIdentity |
api.runtime.agent.resolveAgentIdentity |
resolveThinkingDefault |
api.runtime.agent.resolveThinkingDefault |
resolveAgentTimeoutMs |
api.runtime.agent.resolveAgentTimeoutMs |
ensureAgentWorkspace |
api.runtime.agent.ensureAgentWorkspace |
| 会话存储辅助函数 | api.runtime.agent.session.* |
7. 替换宽泛的 infra-runtime 导入
openclaw/plugin-sdk/infra-runtime 仍为外部兼容性而存在,但新代码应使用其实际需要的受支持接口表面:
| 需求 | 类型化公开导入或注入 API |
|---|---|
| 新的系统事件生产者 | api.runtime.system.enqueueSystemEvent |
| 心跳唤醒请求 | api.runtime.system.requestHeartbeat |
| 通道活动遥测 | api.runtime.channel.activity.record 和 .get |
createDedupeCache、resolveGlobalDedupeCache |
openclaw/plugin-sdk/dedupe-runtime |
| 安全的本地文件/媒体路径、常规文件检查以及符号链接父级检查 | openclaw/plugin-sdk/security-runtime(其本身是一个已弃用的宽泛桶文件) |
fetchWithSsrFGuard、固定调度器辅助函数、LookupFn、SsrFPolicy |
openclaw/plugin-sdk/ssrf-runtime |
| 审批请求/解决类型 | openclaw/plugin-sdk/approval-runtime |
| 审批回复负载和命令辅助函数 | openclaw/plugin-sdk/approval-reply-runtime |
collectErrorGraphCandidates、extractErrorCode、formatErrorMessage、formatUncaughtError、readErrorName、toErrorObject |
openclaw/plugin-sdk/error-runtime |
generateSecureToken、generateSecureUuid |
openclaw/plugin-sdk/core |
parseFiniteNumber、parseStrictFiniteNumber、parseStrictInteger、parseStrictNonNegativeInteger、parseStrictPositiveInteger |
openclaw/plugin-sdk/string-coerce-runtime |
这些是符号特定的映射,而不是对整个桶文件的替代。诸如 heartbeat-runtime、delivery-queue-runtime、fetch-runtime、runtime-fetch 和 file-lock 之类的私有本地条目是仅限 JavaScript 的宿主导出,而不是类型化第三方 API。心跳事件/摘要/可见性辅助函数、待处理投递排空、传输就绪状态、并发以及文件锁定在此处没有等效的现代类型化公开映射。在 SDK 所有者做出决定之前,请保留这些操作的现有兼容性导入。
fetchWithSsrFGuard 不是调度器感知 fetch 的直接替代项:它接受一个选项对象并返回 { response, finalUrl, release, ... },而不是裸 Response;调用方必须释放其资源。命名类型 PinnedDispatcherPolicy、GuardedFetchOptions 和 GuardedFetchResult 并未由 ssrf-runtime 导出。同样,dedupe-runtime 不导出旧版 DedupeCache 或 DedupeCacheOptions 名称。请显式迁移类型用法,而不是假定函数迁移也会迁移其类型。
错误映射未覆盖 hasErrnoCode、isErrno、stringifyNonErrorCause、ErrorKind 或 detectErrorKind;最后一个辅助函数保留了对旧版子串分类的处理。数值和随机映射同样未覆盖所有计时器、过期、十六进制、小数或整数辅助函数。在它们的公共契约得到解决之前,请保留这些不受支持的保留导入。
系统事件快照检查和消费辅助函数目前仅可通过已弃用的 openclaw/plugin-sdk/infra-runtime 兼容层使用;没有现代公共替代方案。当前快照携带一个不透明的 id,对应一个排队中的事件。在返回快照以供消费时,请通过复制和序列化保留该 id。旧版无 ID 的调用方仍保留结构化匹配,这在队列变动后可能产生歧义。不要将该 ID 视为持久或在重启后仍然有效。
文件锁嵌套是按所有者作用域划分的。仅在同一逻辑操作中的嵌套获取时传递相同的 reentrantOwner;普通锁定时应省略它。切勿使用进程级常量,因为无关工作会错误地共享临界区。
捆绑插件已针对 infra-runtime 设置了扫描器防护,因此仓库代码不会退回到宽泛的 barrel。
8. 迁移频道路由辅助函数
新的频道路由代码使用 openclaw/plugin-sdk/channel-route。旧的路由键名称仍作为兼容别名保留:
| 旧辅助函数 | 现代辅助函数 |
|---|---|
channelRouteIdentityKey(...) |
channelRouteDedupeKey(...) |
channelRouteKey(...) |
channelRouteCompactKey(...) |
现代路由辅助函数会在原生审批、回复抑制、入站去重、cron 投递和会话路由中一致地规范化 { channel, to, accountId, threadId }。
频道插件使用 messaging.targetResolver.resolveTarget(...) 进行目标 ID 规范化以及目录未命中回退,在核心需要早期对端类型时使用 messaging.inferTargetChatType(...),并使用 messaging.resolveOutboundSessionRoute(...) 处理提供商原生的会话和线程标识。
9. 构建和测试
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw