12. 插件 IPC 和主机服务
翻译说明: 本页是与 英文源规格 一一对应的机器辅助翻译。代码、协议字段和标识符保持原文;如翻译与英文源事实有歧义,以英文版本为准。
1. 目标
完成与插件相关的主机服务和 UI IPC,以便实现不依赖于临时约定。
2. 主进程服务
PluginManager
├─ PluginRegistryStore
├─ ManifestValidator
├─ PackageInstaller
├─ PermissionGateway
├─ ContributionRegistry
│ ├─ CommandRegistry
│ ├─ AgentToolRegistry
│ ├─ SkillRegistry
│ ├─ ThemeRegistry
│ └─ McpServerRegistry
├─ PluginRuntimeBroker
│ ├─ ServiceSupervisor
│ └─ MessageBus
├─ PluginPanelHostService
└─ MarketClient3. UI IPC(添加)
插件域
plugin/listplugin/detailplugin/loadDevplugin/reload— 解析注册的插件路径,在 Electron 中重新加载它 main,并刷新开发插件权限上限plugin/installFromPath✅plugin/installFromPackage✅plugin/enableplugin/disableplugin/uninstallplugin/reloadplugin/getLogsplugin/getPermissionsplugin/grantPermissionsplugin/revokePermissionsplugin/openDataDirplugin/openInstallDirplugin/openPanelplugin/setAutoUpdateplugin/themes✅ — 每个加载的插件的清理主题 CSS,用于主题 选择器和注入的<style>元素plugin/services✅ — 居民服务状态 (starting|running|stopped|failed) 加上重新启动计数,用于插件页面芯片
commandPalette 域
commandPalette/searchcommandPalette/executecommandPalette/listRecent
市场域(已实现)
market/searchmarket/getDetailmarket/installmarket/checkUpdatesmarket/applyUpdatesmarket/listProviders(目前为单一官方提供商)
4. 事件(主 → 渲染器)
plugin/event/changed(installed/enabled 更改)plugin/event/loadErrorplugin/event/permissionRequiredmarket/event/updateAvailable
附带的 pluginChanged 事件带有 reason,以便渲染器可以决定 重新获取的内容:install、loadDev、enable、disable、uninstall、crash、 service、market.install、market.applyUpdates。 service 在每个 监管过渡是其中最便宜的——只需要服务列表 重新加载。
4. 1 事件(主机→插件进程)
代理还将单向帧推送到插件的 utilityProcess:
{ t: "event", event: "bus.message", subscriptionId, message }没有回复帧,也没有背压:交付是一劳永逸的,所以 楔入的订阅者无法阻止发布者。孩子分派给处理程序 注册 subscriptionId 和任何 pi.events.on 侦听器;一次投掷 处理程序已记录,永远不会致命。这与最终使 pi.events.on / off 真实(参见 03-plugin-api.md §5)。
5. ContributionRegistry 行为
注册
- 密钥必须是唯一的
- 插件命令共享前缀:
plugin.<pluginId>.<commandId> - 插件工具前缀策略:
plugin_<pluginIdSafe>_<toolName>(在实现中修复)
查询
- 命令面板仅查询已启用+加载成功的贡献
- Agent 查看已注册的工具;无论风险如何,Plan 均不会收到任何插件工具 或授予状态
注销
- 删除 disable/unload/uninstall 上的所有内容,包括停止驻留 服务、断开 MCP 服务器、删除总线订阅以及删除 来自选择器的插件主题
6. RuntimeBroker 调用链
插件 API 调用:
plugin runtime
→ RPC to PluginRuntimeBroker
→ PermissionGateway.check
→ Host service execute
→ audit log
→ response7. PanelHost交互
- 打开面板时创建独立视图
- 传入pluginId /主题令牌
- 关闭时销毁视图和消息订阅
8. 故障隔离
- 插件API超时:返回TIMEOUT
- 运行时崩溃:标记load_error,清理贡献
- 面板崩溃:只关闭面板,不卸载插件(可提示重新加载)
实施(2026-07-29,ADR 0008): 经纪人居住在 electron/main/plugin-runtime.ts 和每个插件调用都是对 插件自己的 utilityProcess。预算:加载 15 秒,生命周期挂钩 5 秒,命令 30 秒, 工具 110 秒(根据 host-core 的 120 秒工具预算)。进程退出经纪人 使用 PLUGIN_CRASHED 拒绝挂起的调用,取消注册该插件的命令 和工具,关闭其面板,写入 plugin.crash 审核条目,并发出 toast 加上 pluginChanged 到渲染器。
9. 验收
1.插件列表IPC有效 2.命令面板IPC可以执行插件命令 3. Start/stop 触发贡献 registration/deregistration 4. 市场 IPC 在模拟提供商下端到端运行(后来的里程碑)
附录:代理工具调度协议(M5实现)
插件代理工具在桌面运行程序 (Electron main) 中执行,而 权限门和结果信封保留在 host-core 中:
1.模型调用plugin_<pluginIdSafe>_<toolName>; sidecar 转发它 像任何内置工具一样托管 tools.execute。 2. host-core 首先解析持久操作模式。在 Agent 中,它运行 正常权限流程(风险、会话授予、120 秒超时),然后发出 通知 plugins.execute{ executionId, sessionId, toolCallId, toolName, args }。 3. Plan 调用在主机策略步骤失败并显示 PLUGIN_DISABLED_IN_PLAN;他们 永远不会达到 Electron 或插件运行时。 Agent 呼叫继续 Electron主要执行注册的插件工具JS并通过RPC应答 plugins.resolveExecution { executionId, ok, content, errorCode? }。 4. host-core 解析待执行并返回一个标准 ToolsExecuteResult 到 sidecar。调度超时映射到 TOOL_TIMEOUT; unknown/unloaded 工具映射到 TOOL_NOT_FOUND。
面向模型的注册表根据提示获得插件工具:已注册主要通道 defs(fullName、描述、JSON 架构参数)到 agent.prompt,以及 运行时将它们保存在延迟目录中,而不是序列化每个 架构到第一个请求中。该模型通过加载匹配的插件工具 本地 ToolSearch 工具;下一轮接收选定的模式并 然后使用上面相同的主机 permission/dispatch 路径。协议涵盖 烟雾场景 E2E-024 和运行时加载场景 E2E-008a。
从插件的 MCP 服务器发现的工具会进入相同的注册表 plugin_<pluginIdSafe>_<serverId>_<toolName>,所以上面的步骤1-4不变; 只有步骤 3 内部有所不同,转发到 MCP 客户端而不是插件 JS。
技能使用单独的、更简单的路径。目录(id、名称、描述)是一部分 在基本系统提示符中,Skill 模式本身被推迟到后面 ToolSearch,其主体由 Electron main 的本地 Skill 工具获取 直接服务——sidecar从不保存技能文本和技能文档 仅当模型需要时才到达模型 (D174/D185)。