Files
AstrBot/openspec/changes/abp-plugin-loader/design.md

3.4 KiB
Raw Blame History

Context

ABP 协议第一阶段完成了核心握手、传输层和事件系统。当前 OutOfProcessPluginLoader 已实现,但:

  1. PluginLoader trait 未定义InProcess 模式缺失
  2. tools/list 端点未实现,工具发现依赖它
  3. Python FFI 绑定未完成Python 层无法调用 Rust 核心
  4. 配置集成未落地,无 PluginRegistry

Goals / Non-Goals

Goals:

  • 实现 PluginLoader trait统一进程内/外加载逻辑
  • 实现 InProcessPluginLoaderPython 模块直接加载
  • 实现 tools/list 端点和工具 Schema 验证
  • 完成 Python FFI 绑定链路
  • 落地 config.yaml 插件配置和 PluginRegistry

Non-Goals:

  • 不实现 Stars → ABP 插件迁移(下一阶段)
  • 不实现 WebUI 插件配置界面config.yaml 落地即可)
  • 不改变 Rust 核心源码(仅调用已有接口)

Decisions

1. PluginLoader Trait 设计

决定:定义抽象 trait包含 load()unload()reload()get_plugin_info() 方法。

class PluginLoader(ABC):
    @abstractmethod
    async def load(self, config: PluginConfig) -> PluginInstance: ...

    @abstractmethod
    async def unload(self, plugin_id: str) -> None: ...

    @abstractmethod
    async def reload(self, plugin_id: str) -> PluginInstance: ...

替代方案

  • 工厂模式(被否定):增加抽象层级,当前场景不需要
  • 统一接口参数(被否定):进程内/外行为差异大,分离更清晰

2. InProcessPluginLoader 实现

决定Python 模块直接导入,插件实例化后存入 Dict[str, PluginInstance]

理由

  • 无进程通信开销,性能最优
  • 与项目 "Rust 核心 + Python 胶水层" 架构一致
  • 插件需遵循 ABPPluginProtocol 接口约定

3. 工具发现架构

决定ToolRegistry 统一管理,tools/list 聚合所有插件工具。

ToolRegistry
├── register(plugin_id, tools)
├── unregister(plugin_id)
├── list_tools() -> List[ToolDef]
└── call_tool(name, args) -> ToolResult

理由

  • 中心化管理避免冲突
  • Schema 验证在注册时执行
  • 跨插件工具调用统一入口

4. FFI 绑定链路

决定Python → Rust _core.so → ABP PluginLoader。

Python PluginManager
  → ctypes / cffi 调用 _core.so
  → Rust abp_plugin_loader_* 函数
  → 返回 Python 对象(通过 .pyi 类型提示)

理由

  • Rust 源码待提交,当前仅使用编译产物
  • _core.pyi 提供类型检查
  • anyio 异步调用通过 run_in_executor 封装

Risks / Trade-offs

风险 影响 缓解措施
Rust 源码未提交,接口可能变 FFI 调用失败 接口版本化,核心保持向后兼容
InProcess 插件崩溃影响主进程 稳定性下降 进程内插件加超时保护 + 错误隔离
工具 Schema 验证复杂度 开发体验下降 JSON Schema 仅校验格式,不校验业务逻辑

Migration Plan

  1. Phase 1PluginLoader trait + InProcessPluginLoader对现有 OutOfProcess 透明)
  2. Phase 2tools/list + ToolRegistry
  3. Phase 3FFI 绑定 + config.yaml 集成
  4. Phase 4:测试覆盖 + 文档

Open Questions

  • Q1: InProcess 插件是否需要独立的沙箱隔离?(当前:无)
  • Q2: 工具注册时 Schema 校验严格程度?(当前:格式校验 + 必需字段)
  • Q3: PluginRegistry 是否需要持久化?(当前:内存,进程重启丢失)