AIRI 插件平台架构解析:Eventa 传输、双平面模型与多设备编排
2026/9/12 9:29:53 网站建设 项目流程

AIRI 插件平台架构解析:Eventa 传输、双平面模型与多设备编排

【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi

AIRI(Project AIRI)是一个面向多运行时的插件化陪伴平台,其插件系统围绕「一个 API 表面、多种传输、多设备协同」构建:插件、桥接(Bridge)与查看器(Viewer)通过 Eventa 消息传输通信,插件宿主(Plugin Host)统一装载插件并路由控制与数据流量。本文基于仓库中的架构设计文档 packages/plugin-sdk/docs/design/architecture.md,并结合 plugin-sdk 源码 深入讲解双平面分离、插件生命周期、能力模型、部署模式与验证策略,读完你将掌握 AIRI 插件平台从设计意图到运行时实现的全貌,并能在自己的插件或宿主接入中复用这套思路。

背景:为什么 AIRI 需要一套插件平台

AIRI 需要同时运行在桌面(Electron)、Web 与移动端(Pocket),并保持一套干净的插件 API 表面。插件既要能注册 UI、声明能力,也要能与设备特定的桥接交换数据。为了让系统具备可扩展性,架构文档明确要求:高频数据流必须与生命周期、配置类流量分离

同时,运行时的依赖编排被有意拆分到独立设计文档(capability-orchestration.md)中,让本文聚焦于平台的「形态」与「平面」划分,避免架构讨论被编排细节稀释。

设计目标与非目标

Goals

  • 在多个运行时之间提供统一的插件 API 表面
  • 将生命周期与配置流量从高频数据流中分离
  • 同一套协议支持本地插件与远程插件;
  • 允许多个查看器与桥接通过共享控制平面协同;
  • 保持部署灵活性:嵌入式、外部进程或远程插件宿主均可。

Non-goals

  • 不在本文中定义完整的插件生命周期状态机(交给 capability-orchestration.md);
  • 不规定具体 UI 布局或查看器实现;
  • 不实现 Eventa 适配器之外的新传输层

总体提案:控制平面与数据平面分离

架构的核心提案非常清晰:

  • 所有控制与数据流量统一走Eventa
  • 专用控制平面承载配置、权限、UI 注册与路由策略;
  • 数据平面承载音频、视觉、遥测等高吞吐流;
  • 插件运行在插件宿主内,宿主负责装载插件入口点并暴露 SDK;
  • 桥接被视为仅提供数据与动作的设备侧集成,不拥有 UI。

控制平面(Control Plane)

控制平面承担生命周期、配置、路由策略、权限与 UI 贡献。文档列出的典型控制消息包括:

  • control:hello
  • control:announce
  • control:plugin:register
  • control:plugin:config:get
  • control:plugin:config:set
  • control:capability:grant
  • control:capability:revoke
  • control:ui:register

数据平面(Data Plane)

数据平面承担实时、高吞吐的流式数据。典型数据消息包括:

  • data:context:update
  • data:vision:frame
  • data:audio:stream
  • data:transcript
  • data:character:output

传输选项

两个平面都使用 Eventa 消息,传输层提供两种可选形态:

  1. 两个 WebSocket 端点(控制与数据各自独立);
  2. 一个多路复用连接 + 命名空间(namespace 隔离)。

这种设计的动机在文档 Q&A 中直接给出:生命周期流量与高频数据流对可靠性(reliability)和服务质量(QoS)的需求不同,物理或逻辑上隔离可以各自按需优化。

插件宿主与查看器

插件宿主(Plugin Host)是一个 Node 进程,职责包括:

  • 装载插件入口点(entrypoint);
  • 暴露 AIRI SDK;
  • 注册 UI 贡献;
  • 协商能力(capabilities);
  • 连接控制平面与数据平面。

在源码层面,这一角色由 core.ts 中的ExtensionHost类承担。从类定义与注释可以推断,宿主内部组合了多个服务:ExtensionSessionService(会话管理)、DependencyService(能力注册表)、KitRegistryService(Kit 注册)、PermissionService(权限校验)、ResourceService(资源提供)、KitApiBindingRegistryService(模块绑定管理)。文档注释给出的调用链为:

caller -> ExtensionHost.start -> FileSystemLoader.resolveEntrypointFor -> FileSystemLoader.loadExtensionFor -> ExtensionHost.startExtension

查看器(Viewer)负责渲染 UI 与角色输出,文档给出的示例包括:

  • 带 Configurator 特性的 Electron Stage;
  • Web Configurator 客户端;
  • Pocket Stage 客户端。

插件生命周期概述

架构文档给出了与 core.ts 生命周期注释 相呼应的生命周期图,覆盖模块声明(announcement)、配置与能力阶段:

在源码实现中,startExtension(core.ts)揭示了对应的运行时细节:

  • 每个扩展会话拥有phase状态,取值'setting-up' | 'ready' | 'failed' | 'stopped'
  • 会话上下文ctx提供kits(扩展级 Kit 注册表)与modules.register(...)(模块级注册,返回带独立订阅与清理回调的ExtensionModuleContext);
  • 权限采用双层模型:扩展授权是包/会话级「天花板」,模块级 Kit 使用按「扩展授权 ∩ 模块请求」推导的模块授权进行校验(见 core.ts 头部注释);
  • 失败路径会把会话标记为failed并执行完整清理(cleanupExtensionSession),避免泄漏绑定、订阅与模块资源。

更细的能力依赖编排、等待阶段与就绪门控(readiness gate)在 capability-orchestration.md 中定义。

桥接与远程插件

桥接(Bridge)把外部设备与服务接入 AIRI。它们不拥有 UI,只提供数据与动作。文档示例包括:

  • VS Code 扩展:提供编辑器上下文与命令;
  • 浏览器扩展:提供页面上下文;
  • Minecraft 服务:提供游戏事件与命令。

远程插件(Remote Plugin)是任意语言编写的服务,通过 Eventa 连接并注册能力。文档明确它们更适用于服务端集成与非 JS/TS 技术栈——远程插件只要求能讲 WebSocket 上的 Eventa 协议,不需要 npm 或 JS 运行时。

传输抽象

所有 SDK 调用都是传输无关的。宿主决定通信走本地 IPC 还是远程 RPC,而插件 API 保持不变。

这一点在 channels/index.ts 中有实现支撑:createExtensionChannelScope创建「扩展身份 + Eventa context」的通道作用域,createModuleChannelScope从扩展作用域派生出模块身份,并复用同一 Eventa context。身份信息(idsessionIdversion)随上下文绑定,使协议流量天然携带归属信息。

配套设计文档 multi-transport.md 进一步规划了PluginTransport联合类型:

export type PluginTransport = | { kind: 'in-memory' } | { kind: 'websocket', url: string, protocols?: string[] } | { kind: 'web-worker', worker: Worker } | { kind: 'node-worker', worker: import('node:worker_threads').Worker } | { kind: 'electron', target: 'main' | 'renderer', webContentsId?: number }

其核心原则是:每个插件实例一个 Eventa context,由宿主的createPluginContext(transport)在生命周期方法调用前创建,并通过createApis(ctx)把 API 绑定到该 context——本地插件(in-memory / worker)与远程插件(WebSocket)共享同一 API 表面,互不串扰。

能力模型(Capability Model)

每个节点在注册时声明能力,控制平面根据策略授予/拒绝权限并路由请求。文档给出的能力示例:

  • context.read
  • context.write
  • ui.panel
  • ui.widget
  • vision.capture
  • vision.stream
  • device.mobile.sensors

源码层面,能力由 dependencies.ts 中的DependencyService维护,它是一个带快照与等待原语的内存能力注册表

  • announce(key, metadata):声明能力,状态置为announced
  • markReady(key, metadata):状态置为ready唤醒所有等待者
  • markDegraded/withdraw:置为degraded/withdrawn
  • waitFor(key, timeoutMs = 15000):若已 ready 立即返回,否则注册等待回调,超时抛出Capability ... is not ready after ...错误;
  • waitForMany(keys, timeoutMs):并行等待多个能力。

协议侧,capabilities/index.ts 定义了跨边界的 RPC 契约:protocolCapabilityWaitproj-airi:plugin-sdk:apis:protocol:capabilities:wait)与protocolCapabilitySnapshot...capabilities:snapshot),返回可序列化的CapabilityDescriptor

interface CapabilityDescriptor { key: string state: 'announced' | 'ready' | 'degraded' | 'withdrawn' metadata?: Record<string, unknown> updatedAt: number }

这与 capability-orchestration.md 的「快照权威、事件增量」原则一致:等待者先查快照,能力已就绪则立即放行,避免「错过就绪信号」的竞态。

部署模式

插件宿主支持三种部署形态:

  1. 嵌入式:内嵌在 Electron 主进程中,安装即用(install-and-go);
  2. 外部 Node 进程:支持热重载与进程隔离;
  3. 远程服务器:实现跨设备连续性。

这与 package.json 的导出结构 相印证:./plugin-host子路径通过条件导出区分noderuntimes/node/index.mjs)与defaultruntimes/web/index.mjs)实现,且运行时字面量被限定为electron | node | web(见 types.ts)。

清单与入口点(Manifest & Entrypoints)

插件通过清单文件声明元数据,并提供运行时入口点。文档给出的示例:

{ "id": "airi.vscode", "name": "AIRI VS Code", "version": "1.0.0", "capabilities": ["context.read", "ui.panel", "commands"], "entrypoints": { "node": "./dist/node/index.js" } }

实际宿主代码中,清单格式由ExtensionManifestV1(types.ts)定义,比文档示例更严格、更完整:

export interface ExtensionManifestV1 { apiVersion: 'v1' entrypoints: { default?: string electron?: string node?: string web?: string } id: string kind: 'manifest.extension.airi.moeru.ai' permissions: ModulePermissionDeclaration }

要点说明:

  • kind固定为manifest.extension.airi.moeru.ai,作为清单类型判别器;
  • 入口点可按运行时细分,FileSystemLoader.resolveEntrypointFor(fs.ts)的解析顺序为:entrypoints.<runtime>entrypoints.defaultentrypoints.electron(兼容遗留清单);
  • permissions声明包级/会话级权限天花板,其 schema(permissionDeclarationSchema)将权限划分为五类区域,每类各有动作白名单:
    • apisinvoke/emit
    • capabilitieswait/snapshot
    • pipelineshook/process/emit/manage
    • processorsregister/execute/manage
    • resourcesread/write/subscribe

插件入口点本身通过defineExtension(...)(define.ts)导出,约定id必须与清单中的id一致(startExtension会做一致性校验),setup(ctx)是通用的编写入口,通过ctx.kits使用宿主安装的 Kit。

Kit API 命名与 Eventa 契约

仓库 README(packages/plugin-sdk/README.md)补充了 Kit 开发的命名约定,与架构的「SDK 调用传输无关」原则直接呼应:

名称含义
gameletKitApisKit 包导出的共享 Eventa API 契约(通常是defineInvokeEventa(...)条目组成的映射)
gameletKitService宿主侧 Kit 行为实现,拥有真实副作用(如 UI 挂载/更新/清理)
gameletKitctx.kits.use(...)消费的 Kit 定义,拥有身份、版本、可用性策略与客户端创建
gamelets返回给插件作者的客户端实例(多操作时建议复数命名空间)
createGameletKit(...)把依赖注入gameletKit的工厂,支持本地客户端与远程 Eventa 客户端

关键约束:共享的产物是 Eventa API 契约,而不是实现函数。本地客户端可直接调用gameletKitService,远程客户端通过 Eventa 调用同一 API,两者对外暴露相同的编写形态;跨进程/网络时需要复用共享的 Eventa invoke 契约,不得发明invokeGamelet之类的 Kit 专属传输方法名。

验证与测试

验收标准(Criteria)

  • 插件可被宿主装载,并注册 UI 与能力;
  • 桥接可连接并被控制平面发现;
  • 数据平面流与控制平面流量保持隔离;
  • 同一插件 API 表面在桌面、Web、移动端表现一致。

测试与 QA(Test & QA)

  • 集成测试:host + viewer + bridge,验证控制平面路由;
  • 集成测试:数据平面以高频数据源流式传输;
  • 兼容性测试:同一插件入口点在多个运行时下运行。

从源码结构看,这些验收标准已被测试工程承接:plugin-host目录下存在 core.test.ts、runtimes/shared/services/下的dependencies.test.tspermissions.test.tskits.test.tsbindings.test.ts等单测,以及testdata/中覆盖正常插件、错误插件、注入宿主 API 插件、无连接插件、可停止入口点等场景的测试夹具。

进度与后续规划

  • Status:Active design(活跃设计阶段);
  • Next Steps
    1. 让运行时文档与最新的插件上下文、传输策略对齐;
    2. 从 capability-orchestration.md 集成能力注册表与就绪门控生命周期迁移;
    3. 按语言扩充远程插件示例。

常见问题(Q&A)

Q: 为什么拆分控制平面与数据平面?A: 生命周期流量与高频数据流对可靠性和 QoS 的需求不同,物理或逻辑隔离可以各自按需优化,避免高频流拖垮配置/权限等关键控制消息。

Q: 桥接会渲染 UI 吗?A: 不会。UI 通过控制平面贡献给查看器,桥接只提供数据与动作。

Q: 远程插件可以不使用 JS 或 npm 吗?A: 可以。远程插件只需通过 WebSocket 讲 Eventa 协议,语言无关。

相关文档

  • 多传输插件上下文 Multi-Transport Plugin Contexts
  • 能力导向的模块编排 Capability-Oriented Module Orchestration
  • Plugin SDK 源码
  • Plugin SDK 说明文档

【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询