插件安装的定向同步与缓存复用
普通安装、重装、更新、启停和组件设置变更只同步受影响的插件;卸载按插件发送删除意图。手动刷新和设备重新连接仍使用完整清单对账。账户安装记录是期望状态,设备回执是本地物化状态,两者分别保存。
协议与兼容
Executor 在 runtime_features.pluginSync.protocolVersion 明确上报 2 后,Backend 才发送新协议。未上报、格式错误或版本不受支持时保留旧同步行为,不按 Wework 应用版本号推断能力。Python 和 Rust 的设备能力投影均保留该字段。
新协议复用 device:sync_capabilities 事件,保留现有 HTTP URL 和返回字段:
{
"mode": "merge",
"scope": "plugin_delta",
"plugin_sync": { "version": 2, "generation": 7, "complete": false },
"plugins": [],
"removed_plugins": [
{ "installed_plugin_id": 123, "name": "example", "marketplace": "wegent" }
]
}
完整插件对账使用 scope=plugins、complete=true;重新连接时完整能力同步仍可使用 mode=replace。选择能力的旧 API 在新设备上也进入有序插件同步,避免绕过增量同步的顺序保护。Skills、MCP、认证、退出和插件调用接口保持现有职责。
同账户有新旧设备时分别发送协议。新设备发起安装只等待自身同步,其他设备在后台处理;既有待安装记录、待卸载记录和重新连接对账承担失败恢复。旧设备仍可能等待原有全量操作。
并发与回执
- Backend 使用现有
Kind保存按用户划分的同步序号和设备水位,不增加表。快照和回执写入复用主干的账户级 Redis 租约及业务版本 CAS,在新会话中读取已提交状态;提交序号后释放租约和连接,网络调用不持有租约或数据库事务。 - 发出请求前持久化设备及插件的意图水位。持久化回执时重新获取租约、检查序号以及实际下发的版本、校验和、启用和组件状态,过期回执不能覆盖新结果;租约失效或业务版本冲突时拒绝写回。增量回执只更新受影响插件。
- Executor 保存已接受意图、完整清单水位、插件序号和删除墓碑。不同插件可以乱序到达;旧清单不能删除新安装,失败操作可以重试,卸载后迟到的安装不能复活插件。
- 插件完整清单与完整能力同步分别保存接受水位,复用同一请求序号。插件刷新不推进独立 Skills/MCP 的水位;较新的插件对账先执行时,旧重连请求仍同步尚未被更新的独立能力,同时跳过过期插件操作。较旧的完整能力请求不能覆盖较新完整能力请求的结果。
- 同序号、同目标的请求共享在途结果。不同序号即使目标相同,也必须重新检查顺序和本地健康状态,防止“安装→卸载→重装”错误复用首次安装结果。
- Executor 将持久水位与当前连接的认证绑定隔离,当前进程中的旧连接处理器失效,切换账号不会沿用另一账户的序号。
会话能力刷新
Executor 比较同步前后的有效插件内容、配置和独立技能;同步序号、安装时间等记录字段变化不递增能力版本。重连或重复同步没有改变有效能力时,不要求重建 Codex;内容变化及运行文件、配置或权限修复仍需生效。日志记录发生变化的插件和技能名称。
已知插件技能的布尔开关写入 Codex 原生技能配置并热更新,后续回合使用新设置,当前回合不会因切换被终止。无法确认仅有技能开关变化时,沿用能力失效后的空闲重建流程。批量开关部分失败会等待所有写入结束,清理缓存并重读实际状态,再返回原始错误。
连接器授权续期按 token 的绝对过期时间提前调度。纯 token 变化不递增激活能力版本,但接受授权更新(包括续期)会推进连接器状态版本 revision,使进行中的旧工具发现结果失效。sync_apps 在状态版本 revision 或同步请求序号 sync_generation 变化时拒绝迟到结果。规范化后的完整工具定义变化仍需生效,同名工具的描述和参数 schema 也参与比较;MCP 子进程调用工具时读取当前授权。
缓存与耗时
有可信 SHA256 时先校验本地共享包,再决定是否下载。版本相同但校验和变化、缓存内容损坏或包缺失会进入下载和验证。没有可信校验和的下载路径仍需下载。
运行目录保持与主干一致的行为:每次同步都从验证后的本地包重写运行目录和配置,不做状态比对跳过;缺失或损坏的运行文件借此自然修复。定向同步只下发变化的插件,未变化插件的运行目录不会被触碰。
共享包沿用主干的不可改写发布策略:既有包损坏时,即使重新下载的归档通过校验,也会拒绝覆盖并保留原有运行目录,需人工修复缓存。没有有效所有权记录、身份不符或符号链接占用的共享目录拒绝覆盖,不能根据目录名直接认领。
日志记录 plugin_sync_completed 的排队与整体耗时,以及插件的校验、下载、包处理、本地激活、字节数和缓存命中。Backend 记录 RPC 耗时、请求插件数量及同步序号。
验证与性能对比
executor/tests/plugin_install_performance.rs 使用真实临时文件系统、13 个预安装插件和连续 3 个新插件,仅模拟每次下载 10ms。将同一用例复制到 upstream/main(64def2c13)的临时源码快照,设置 WEGENT_PLUGIN_PERF_BASELINE=1;新代码运行默认模式。两侧编译时间不计入测量。
相同条件下,main 发送 14、15、16 个插件的完整清单,新方案发送 3 个单插件增量。以下为 2026-10-22 的一次 debug 构建历史测量,不代表当前提交重新测得的耗时;当时 16 个 ZIP 均为 329 字节:
| 指标 | main | 新方案 |
|---|---|---|
| 下载次数 | 45 | 3 |
| 下载字节数 | 14,805 | 987 |
| 下载累计耗时 | 533.720ms | 36.847ms |
| 三次安装整体耗时 | 1,432.304ms | 265.768ms |
| 已有插件运行目录变更数 | 13 | 0 |
本次下载次数减少 93.3%,整体耗时减少 81.4%。用例输出 PLUGIN_INSTALL_PERFORMANCE_RESULT JSON;模拟结果不能替代真实环境中 61.5/72.3/43.6 秒接口耗时的复测。复现新方案可在 executor/ 运行:
cargo test --test plugin_install_performance -- --nocapture
基线快照使用相同命令并设置 WEGENT_PLUGIN_PERF_BASELINE=1。两个源码目录应使用独立的 CARGO_TARGET_DIR,避免同包名及旧文件时间戳造成构建产物误复用。
聚焦回归覆盖新旧能力协商、并发安装、安装与卸载交错、同步期间状态变化、回执乱序、账号切换、失败恢复、缓存损坏和运行目录修复。既有桌面 plugin-auto-update 检查点增加并发安装仅同步目标插件、旧插件记录不变的断言;plugin-registration-coordination 检查点验证空插件对账先执行后,迟到的重连请求仍将独立 Skills/MCP 实际落盘。两者均由现有 CI 流程执行。未显式要求时不运行 E2E 或 ai:verify。