mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
chore: commit all changes
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
schema: spec-driven
|
||||
created: 2026-03-27
|
||||
@@ -1,119 +0,0 @@
|
||||
## Context
|
||||
|
||||
ABP 协议第一阶段完成了核心握手、传输层和事件系统。当前 `OutOfProcessPluginLoader` 已实现,但:
|
||||
1. `PluginLoader` trait 未定义,InProcess 模式缺失
|
||||
2. `tools/list` 端点未实现,工具发现依赖它
|
||||
3. Python FFI 绑定未完成,Python 层无法调用 Rust 核心
|
||||
4. 配置集成未落地,无 PluginRegistry
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 实现 `PluginLoader` trait,统一进程内/外加载逻辑
|
||||
- 实现 `InProcessPluginLoader`,Python 模块直接加载
|
||||
- 实现 `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()` 方法。
|
||||
|
||||
```python
|
||||
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 实现
|
||||
|
||||
> **⚠️ 架构约束**:核心加载逻辑在 Rust FFI,Python 仅做胶水层
|
||||
|
||||
**决定**:`PluginLoader` trait 定义在 Python,`load/unload/reload` 实现调用 Rust FFI(`load_plugin()`/`unload_plugin()`)。
|
||||
|
||||
```python
|
||||
class InProcessPluginLoader(PluginLoader):
|
||||
async def load(self, plugin_id, config, data_dirs):
|
||||
# 调用 Rust FFI: _core.load_plugin(config)
|
||||
result = await rust_ffi.load_plugin(plugin_id, config, data_dirs)
|
||||
return PluginInstance(plugin_id, result.instance, ...)
|
||||
```
|
||||
|
||||
**理由**:
|
||||
- 核心加载逻辑在 Rust(线程安全、错误隔离)
|
||||
- Python 胶水层仅做类型转换和聚合
|
||||
- 符合 config.yaml `rust_core` 规范
|
||||
|
||||
### 3. 工具发现架构
|
||||
|
||||
**决定**:`ToolRegistry` 统一管理,`tools/list` 聚合所有插件工具。
|
||||
|
||||
```
|
||||
ToolRegistry
|
||||
├── register(plugin_id, tools)
|
||||
├── unregister(plugin_id)
|
||||
├── list_tools() -> List[ToolDef]
|
||||
└── call_tool(name, args) -> ToolResult
|
||||
```
|
||||
|
||||
**理由**:
|
||||
- 中心化管理避免冲突
|
||||
- Schema 验证在注册时执行
|
||||
- 跨插件工具调用统一入口
|
||||
|
||||
### 4. FFI 绑定链路
|
||||
|
||||
> **⚠️ 禁止 ctypes**:所有 FFI 必须通过 PyO3(rust-ffi.md 规范)
|
||||
|
||||
**决定**:Python → PyO3 `_core.so` → ABP PluginLoader。
|
||||
|
||||
```
|
||||
Python PluginRegistry (_internal/)
|
||||
→ PyO3 调用 _core.so
|
||||
→ Rust abp_plugin_loader_* 函数
|
||||
→ 返回 Python 对象(通过 .pyi 类型提示)
|
||||
```
|
||||
|
||||
**理由**:
|
||||
- PyO3 是 Rust 官方 Python 绑定方案
|
||||
- `rust-ffi.md` 明确禁止 ctypes
|
||||
- `_core.pyi` 提供类型检查
|
||||
- anyio 异步调用通过 `run_in_executor` 封装
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| 风险 | 影响 | 缓解措施 |
|
||||
|------|------|----------|
|
||||
| Rust 源码未提交,接口可能变 | FFI 调用失败 | 接口版本化,核心保持向后兼容 |
|
||||
| InProcess 插件崩溃影响主进程 | 稳定性下降 | 进程内插件加超时保护 + 错误隔离 |
|
||||
| 工具 Schema 验证复杂度 | 开发体验下降 | JSON Schema 仅校验格式,不校验业务逻辑 |
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. **Phase 1**:PluginLoader trait + Python 聚合层(调用 Rust FFI)
|
||||
2. **Phase 2**:tools/list + ToolRegistry(Rust FFI + Python 聚合)
|
||||
3. **Phase 3**:PyO3 FFI 绑定 + config.yaml 集成
|
||||
4. **Phase 4**:测试覆盖 + 文档
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Q1: InProcess 插件是否需要独立的沙箱隔离?(当前:无)
|
||||
- Q2: 工具注册时 Schema 校验严格程度?(当前:格式校验 + 必需字段)
|
||||
- Q3: PluginRegistry 是否需要持久化?(当前:内存,进程重启丢失)
|
||||
@@ -1,32 +0,0 @@
|
||||
## Why
|
||||
|
||||
ABP 协议实现第一阶段完成了核心握手、传输层和事件系统。当前 PluginLoader trait 和 InProcess 插件加载尚未实现,工具发现依赖 `tools/list`,FFI 绑定也未完成。这些是 ABP 插件系统真正可用的最后几块拼图。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **PluginLoader trait**:定义插件加载抽象,支持进程内/外两种模式
|
||||
- **InProcessPluginLoader**:实现 Python 模块直接加载(无需进程通信)
|
||||
- **tools/list 端点**:插件暴露可用工具列表
|
||||
- **工具 Schema 验证**:JSON Schema Draft-07 校验
|
||||
- **跨插件工具发现**:统一聚合所有插件的工具
|
||||
- **FFI 绑定**:Python 胶水层调用 Rust ABP 核心
|
||||
- **配置集成**:config.yaml 插件配置落地,PluginRegistry 实现
|
||||
- **测试完善**:单元测试 + 集成测试覆盖
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `abp-plugin-loader`: 插件加载器 trait 和实现(InProcess/OutOfProcess)
|
||||
- `abp-tool-discovery`: 工具注册、Schema 验证、跨插件发现
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `abp-protocol`: FFI 绑定补充(Python → Rust 核心调用链路)
|
||||
- `abp-tool-router`: 增加 `tools/list` 端点实现
|
||||
|
||||
## Impact
|
||||
|
||||
- **新增**:`astrbot/core/plugin/` 扩展(loader 模块)
|
||||
- **修改**:`astrbot/core/plugin/plugin_manager.py`(FFI 绑定)
|
||||
- **依赖**:Rust 核心 `_core.so` 已编译,源码待提交 `astrbot/rust/src/`
|
||||
@@ -1,57 +0,0 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: PluginLoader Trait
|
||||
ABP 插件加载器抽象接口,定义进程内/外插件的统一加载方式。
|
||||
|
||||
#### Scenario: Load In-Process Plugin
|
||||
- **WHEN** 配置指定 `load_mode: "in_process"`
|
||||
- **THEN** `InProcessPluginLoader` 直接导入 Python 模块
|
||||
- **AND** 实例化插件,传入 context、user_config、data_dirs
|
||||
- **AND** 将插件实例注册到 `PluginRegistry`
|
||||
|
||||
#### Scenario: Load Out-of-Process Plugin
|
||||
- **WHEN** 配置指定 `load_mode: "out_of_process"`
|
||||
- **THEN** `OutOfProcessPluginLoader` 启动插件子进程
|
||||
- **AND** 建立传输层连接(Stdio/Unix Socket/HTTP)
|
||||
- **AND** 执行握手协议交换配置
|
||||
|
||||
#### Scenario: Unload Plugin
|
||||
- **WHEN** 调用 `loader.unload(plugin_id)`
|
||||
- **THEN** 关闭插件连接/释放模块引用
|
||||
- **AND** 从 `PluginRegistry` 注销插件
|
||||
|
||||
#### Scenario: Reload Plugin
|
||||
- **WHEN** 调用 `loader.reload(plugin_id)`
|
||||
- **THEN** 卸载现有插件实例
|
||||
- **AND** 重新加载并初始化插件
|
||||
|
||||
### Requirement: In-Process Plugin Loading
|
||||
进程内插件由 Rust FFI 核心管理生命周期,Python 胶水层仅做聚合。
|
||||
|
||||
#### Scenario: In-Process Plugin Invocation
|
||||
- **WHEN** 调用进程内插件方法(如 `handle_event`)
|
||||
- **THEN** 通过 Rust FFI `load_plugin()` 加载
|
||||
- **AND** Python PluginRegistry 聚合插件实例
|
||||
- **AND** 调用通过 Rust FFI 转发
|
||||
|
||||
#### Scenario: In-Process Plugin Context
|
||||
- **WHEN** 插件实例化时
|
||||
- **THEN** Rust 核心传入 context 对象
|
||||
- **AND** 传入 user_config(来自握手)
|
||||
- **AND** 传入 data_dirs(数据目录路径)
|
||||
|
||||
### Requirement: PluginRegistry
|
||||
全局插件实例注册表,管理所有已加载插件。
|
||||
|
||||
#### Scenario: Register Plugin Instance
|
||||
- **WHEN** 插件加载成功时
|
||||
- **THEN** `PluginRegistry` 存储 plugin_id → PluginInstance 映射
|
||||
- **AND** 插件暴露的工具注册到 `ToolRegistry`
|
||||
|
||||
#### Scenario: Query Plugin by ID
|
||||
- **WHEN** 调用 `registry.get_plugin(plugin_id)`
|
||||
- **THEN** 返回插件实例或 None
|
||||
|
||||
#### Scenario: List All Plugins
|
||||
- **WHEN** 调用 `registry.list_plugins()`
|
||||
- **THEN** 返回所有已注册插件的元数据列表
|
||||
@@ -1,59 +0,0 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: tools/list Endpoint
|
||||
插件通过 `tools/list` 端点暴露可用工具列表。
|
||||
|
||||
#### Scenario: List Plugin Tools
|
||||
- **WHEN** 主进程调用 `tools/list` 方法
|
||||
- **THEN** 插件返回 `{ "tools": [ToolDef, ...] }`
|
||||
- **AND** 每个 ToolDef 包含 name、description、parameters(JSON Schema)
|
||||
|
||||
#### Scenario: Empty Tools List
|
||||
- **WHEN** 插件无可用工具
|
||||
- **THEN** 返回 `{ "tools": [] }`
|
||||
|
||||
### Requirement: Tool Schema Validation
|
||||
注册工具时进行 JSON Schema Draft-07 格式校验。
|
||||
|
||||
#### Scenario: Valid Tool Schema
|
||||
- **WHEN** 工具定义通过 Schema 校验
|
||||
- **THEN** 工具注册到 `ToolRegistry`
|
||||
- **AND** 可被 `tools/call` 调用
|
||||
|
||||
#### Scenario: Invalid Tool Schema
|
||||
- **WHEN** 工具定义 Schema 校验失败
|
||||
- **THEN** 记录警告日志
|
||||
- **AND** 跳过该工具(不注册)
|
||||
|
||||
### Requirement: ToolRegistry
|
||||
> **架构约束**:核心路由在 Rust FFI(`tool_router.rs`),Python 层仅做聚合
|
||||
|
||||
中心化工具注册表,支持跨插件工具发现和调用。
|
||||
|
||||
#### Scenario: Register Tool
|
||||
- **WHEN** 插件调用 `registry.register(plugin_id, tools)`
|
||||
- **THEN** 工具按 plugin_id 隔离存储
|
||||
- **AND** 执行 Schema 校验
|
||||
|
||||
#### Scenario: Discover All Tools
|
||||
- **WHEN** 调用 `registry.list_tools()`
|
||||
- **THEN** 聚合所有插件注册的工具(通过 Rust FFI `list_tools()`)
|
||||
- **AND** 每个工具标记来源 plugin_id
|
||||
|
||||
#### Scenario: Call Tool
|
||||
- **WHEN** 调用 `registry.call_tool(tool_name, args)`
|
||||
- **THEN** 转发调用到 Rust FFI `route_tool_call()`
|
||||
- **AND** 返回执行结果
|
||||
|
||||
#### Scenario: Tool Not Found
|
||||
- **WHEN** 调用不存在的工具
|
||||
- **THEN** Rust FFI 抛出 `ToolNotFoundError` 错误
|
||||
- **AND** 错误码 -32203
|
||||
|
||||
### Requirement: Cross-Plugin Tool Discovery
|
||||
聚合多个插件的工具,提供统一发现接口。
|
||||
|
||||
#### Scenario: Aggregate Tools from Multiple Plugins
|
||||
- **WHEN** 多个插件注册了工具
|
||||
- **THEN** `ToolRegistry` 聚合所有工具
|
||||
- **AND** 工具名可配置为 `plugin_name/tool_name` 格式避免冲突
|
||||
@@ -1,49 +0,0 @@
|
||||
## 1. PluginLoader Trait & Python 聚合层
|
||||
|
||||
> **架构边界**:核心加载逻辑在 Rust FFI,Python 胶水层仅做类型转换和聚合
|
||||
|
||||
- [ ] 1.1 Define `PluginLoader` abstract base class in `astrbot/_internal/protocols/abp/loader.py`
|
||||
- [ ] 1.2 Define `PluginInstance` dataclass (plugin_id, instance, metadata)
|
||||
- [ ] 1.3 Define `PluginRegistry` class in `astrbot/_internal/protocols/abp/registry.py` (Python 聚合层,调用 Rust FFI)
|
||||
- [ ] 1.4 Add `register()` and `unregister()` methods to PluginRegistry
|
||||
- [ ] 1.5 Add `load_plugin()` / `unload_plugin()` wrapper calling Rust FFI
|
||||
|
||||
## 2. Tool Discovery & Registry
|
||||
|
||||
> **架构边界**:`tool_router.rs` 核心在 Rust,Python 层仅做聚合和转发
|
||||
|
||||
- [ ] 2.1 Create `astrbot/_internal/protocols/abp/tool_registry.py`
|
||||
- [ ] 2.2 Implement `ToolDef` dataclass (name, description, parameters schema)
|
||||
- [ ] 2.3 Implement `ToolRegistry.register(plugin_id, tools)` with Schema validation (Python)
|
||||
- [ ] 2.4 Implement `ToolRegistry.list_tools()` (aggregate all plugins via Rust FFI `list_tools()`)
|
||||
- [ ] 2.5 Implement `ToolRegistry.call_tool(tool_name, args)` (delegate to Rust FFI `route_tool_call()`)
|
||||
- [ ] 2.6 Implement `tools/list` JSON-RPC endpoint in plugin base class
|
||||
- [ ] 2.7 Add JSON Schema Draft-07 validation (jsonschema library)
|
||||
|
||||
## 3. FFI Bindings
|
||||
|
||||
> **⚠️ 禁止使用 ctypes**:所有 FFI 必须通过 PyO3 绑定(rust-ffi.md 规范)
|
||||
|
||||
- [ ] 3.1 Audit existing `_core.pyi` for missing ABP types
|
||||
- [ ] 3.2 Add `plugin_loader_*` FFI function signatures to rust-ffi.md (if missing)
|
||||
- [ ] 3.3 Implement Python → Rust plugin loader calls via **PyO3** binding
|
||||
- [ ] 3.4 Add async wrapper using `run_in_executor` for PyO3 FFI calls
|
||||
- [ ] 3.5 Update `astrbot/_internal/protocols/abp/manager.py` to use FFI bindings
|
||||
|
||||
## 4. Configuration Integration
|
||||
|
||||
- [ ] 4.1 Define `plugins` section in `config.yaml` schema
|
||||
- [ ] 4.2 Implement `PluginConfig` dataclass parsing
|
||||
- [ ] 4.3 Integrate PluginRegistry initialization into AstrBot startup
|
||||
- [ ] 4.4 Add connection pooling for Unix Socket transport
|
||||
- [ ] 4.5 Write integration test for config → plugin loading flow
|
||||
|
||||
## 5. Testing
|
||||
|
||||
- [ ] 5.1 Write unit tests for PluginLoader trait
|
||||
- [ ] 5.2 Write unit tests for Python PluginRegistry (mock Rust FFI)
|
||||
- [ ] 5.3 Write unit tests for ToolRegistry
|
||||
- [ ] 5.4 Write integration tests for plugin loading (requires Rust FFI stub)
|
||||
- [ ] 5.5 Write integration tests for tools/list + tools/call flow
|
||||
- [ ] 5.6 Run `ruff check .` and `ruff format .`
|
||||
- [ ] 5.7 Run `uvx ty check` for type validation
|
||||
@@ -1,156 +0,0 @@
|
||||
# Rust FFI 接口规范
|
||||
|
||||
## 概述
|
||||
|
||||
AstrBot 采用 **Rust 核心 + Python 胶水层** 架构。Rust 核心编译为 `_core.so`,通过 FFI 暴露接口供 Python 调用。
|
||||
|
||||
**绑定方案**:使用 [PyO3](https://pyo3.rs/)(`rust/src/lib.rs` 导出 `#[pymodule]`),Python 端通过 `ffi` 模块调用。
|
||||
|
||||
**禁止使用 `ctypes`** —— 所有 FFI 交互必须通过 PyO3 绑定。
|
||||
|
||||
## 核心模块布局
|
||||
|
||||
```
|
||||
astrbot/rust/src/
|
||||
├── lib.rs # 入口,导出 #[pymodule]
|
||||
├── orchestrator.rs # AstrbotOrchestrator 主协调器
|
||||
├── abp/ # ABP 协议实现
|
||||
│ ├── mod.rs
|
||||
│ ├── protocol.rs # 握手、消息路由
|
||||
│ ├── loader.rs # 插件加载器
|
||||
│ ├── transport.rs # Stdio/Unix Socket/HTTP
|
||||
│ └── error.rs # ABP 错误码
|
||||
├── message/ # 消息缓冲(双缓冲区)
|
||||
│ ├── mod.rs
|
||||
│ ├── input_buffer.rs
|
||||
│ └── output_buffer.rs
|
||||
├── flow_control.rs # 流控引擎
|
||||
├── tool_router.rs # 工具路由(Internal/MCP/Skills)
|
||||
└── agent.rs # Agent 协调
|
||||
```
|
||||
|
||||
## FFI 函数签名
|
||||
|
||||
### orchestrator.rs
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `get_orchestrator()` | `def get_orchestrator() -> AstrbotOrchestrator` | `AstrbotOrchestrator` | 单例获取 |
|
||||
| `orchestrator.start()` | `def start(self) -> None` | `None` | 启动核心 |
|
||||
| `orchestrator.stop()` | `def stop(self) -> None` | `None` | 停止核心 |
|
||||
| `orchestrator.is_running()` | `def is_running(self) -> bool` | `bool` | 运行状态 |
|
||||
| `orchestrator.register_star()` | `def register_star(self, name: str, handler: str) -> None` | `None` | 注册 Star |
|
||||
| `orchestrator.unregister_star()` | `def unregister_star(self, name: str) -> None` | `None` | 注销 Star |
|
||||
| `orchestrator.list_stars()` | `def list_stars(self) -> list[str]` | `list[str]` | 列出 Stars |
|
||||
| `orchestrator.record_activity()` | `def record_activity(self) -> None` | `None` | 记录活动 |
|
||||
| `orchestrator.get_stats()` | `def get_stats(self) -> dict` | `dict[str, Any]` | 获取统计 |
|
||||
| `orchestrator.set_protocol_connected()` | `def set_protocol_connected(self, protocol: str, connected: bool) -> None` | `None` | 设置协议连接状态 |
|
||||
| `orchestrator.get_protocol_status()` | `def get_protocol_status(self, protocol: str) -> dict | None` | `dict[str, Any] \| None` | 获取协议状态 |
|
||||
|
||||
### abp/protocol.rs(ABP 插件协议)
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `plugin_initialize()` | `def plugin_initialize(config: dict) -> InitializeResult` | `InitializeResult` | 初始化握手 |
|
||||
| `plugin_start()` | `def plugin_start(self, plugin_id: str) -> None` | `None` | 启动插件 |
|
||||
| `plugin_stop()` | `def plugin_stop(self, plugin_id: str) -> None` | `None` | 停止插件 |
|
||||
| `plugin_reload()` | `def plugin_reload(self, plugin_id: str) -> None` | `None` | 重载插件 |
|
||||
| `plugin_config_update()` | `def plugin_config_update(self, plugin_id: str, config: dict) -> None` | `None` | 更新配置 |
|
||||
|
||||
### abp/loader.rs(插件加载器)
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `load_plugin()` | `def load_plugin(self, plugin_config: dict) -> PluginHandle` | `PluginHandle` | 加载插件 |
|
||||
| `unload_plugin()` | `def unload_plugin(self, plugin_id: str) -> None` | `None` | 卸载插件 |
|
||||
| `list_loaded_plugins()` | `def list_loaded_plugins(self) -> list[str]` | `list[str]` | 列出已加载 |
|
||||
|
||||
### abp/transport.rs(传输层)
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `create_stdio_transport()` | `def create_stdio_transport(cmd: str, args: list[str]) -> Transport` | `Transport` | 创建 stdio 传输 |
|
||||
| `create_unix_transport()` | `def create_unix_transport(path: str) -> Transport` | `Transport` | 创建 Unix Socket 传输 |
|
||||
| `create_http_transport()` | `def create_http_transport(url: str) -> Transport` | `Transport` | 创建 HTTP/SSE 传输 |
|
||||
|
||||
### message/input_buffer.rs(输入缓冲区)
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `enqueue_message()` | `def enqueue_message(self, event: dict) -> str` | `str` | 入队,返回 message_id |
|
||||
| `dequeue_messages()` | `def dequeue_messages(self, limit: int) -> list[dict]` | `list[dict]` | 批量出队 |
|
||||
| `get_queue_depth()` | `def get_queue_depth(self, session_id: str) -> int` | `int` | 获取队列深度 |
|
||||
| `clear_queue()` | `def clear_queue(self, session_id: str) -> None` | `None` | 清空队列 |
|
||||
|
||||
### message/output_buffer.rs(输出缓冲区)
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `enqueue_result()` | `def enqueue_result(self, session_id: str, result: dict) -> str` | `str` | 入队 |
|
||||
| `dequeue_result()` | `def dequeue_result(self, session_id: str) -> dict \| None` | `dict \| None` | 出队(非阻塞) |
|
||||
| `set_dispatch_strategy()` | `def set_dispatch_strategy(self, strategy: str) -> None` | `None` | 设置分发策略 |
|
||||
|
||||
### flow_control.rs(流控引擎)
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `set_rate_limit()` | `def set_rate_limit(self, requests: int, period: float) -> None` | `None` | 设置限流 |
|
||||
| `acquire()` | `def acquire(self) -> bool` | `bool` | 获取令牌(非阻塞) |
|
||||
| `wait_for_token()` | `def wait_for_token(self, timeout: float) -> bool` | `bool` | 等待令牌(阻塞) |
|
||||
|
||||
### tool_router.rs(工具路由)
|
||||
|
||||
| 函数 | Python 签名 | 返回类型 | 说明 |
|
||||
|------|-------------|----------|------|
|
||||
| `register_internal_tool()` | `def register_internal_tool(self, name: str, schema: dict) -> None` | `None` | 注册内部工具 |
|
||||
| `register_mcp_server()` | `def register_mcp_server(self, name: str, transport: Transport) -> None` | `None` | 注册 MCP 服务器 |
|
||||
| `route_tool_call()` | `def route_tool_call(self, tool_name: str, arguments: dict) -> ToolResult` | `ToolResult` | 路由工具调用 |
|
||||
| `list_tools()` | `def list_tools(self) -> list[dict]` | `list[dict]` | 列出所有工具 |
|
||||
|
||||
## 类型映射
|
||||
|
||||
| Rust 类型 | Python 类型 | 说明 |
|
||||
|-----------|------------|------|
|
||||
| `bool` | `bool` | - |
|
||||
| `i32`, `i64` | `int` | - |
|
||||
| `f64` | `float` | - |
|
||||
| `String` | `str` | - |
|
||||
| `Vec<T>` | `list[T]` | - |
|
||||
| `HashMap<K,V>` | `dict[K,V]` | - |
|
||||
| `Option<T>` | `T \| None` | - |
|
||||
| `Result<T, E>` | 异常或 T | 失败抛 Python 异常 |
|
||||
|
||||
## 错误处理
|
||||
|
||||
Rust 层返回的错误统一转换为 Python 异常:
|
||||
|
||||
| ABP 错误码 | Python 异常 |
|
||||
|------------|-------------|
|
||||
| -32200 | `PluginNotFoundError` |
|
||||
| -32201 | `PluginNotReadyError` |
|
||||
| -32202 | `PluginCrashedError` |
|
||||
| -32203 | `ToolNotFoundError` |
|
||||
| -32204 | `ToolCallFailedError` |
|
||||
| -32205 | `HandlerNotFoundError` |
|
||||
| -32206 | `HandlerError` |
|
||||
| -32207 | `EventSubscribeError` |
|
||||
| -32208 | `PermissionDeniedError` |
|
||||
| -32209 | `ConfigError` |
|
||||
| -32210 | `DependencyMissingError` |
|
||||
| -32211 | `VersionMismatchError` |
|
||||
| -32603 | `InternalError` |
|
||||
|
||||
## 实现要求
|
||||
|
||||
1. **所有函数必须线程安全**(Rust 核心使用 `Arc<Mutex<T>>` 保护共享状态)
|
||||
2. **异步操作在 Rust 内部完成**,Python 侧得到的是 Future 或直接结果
|
||||
3. **不得在 FFI 边界传递闭包或函数指针**
|
||||
4. **版本化接口**:FFI 接口变更时提升 `__version__`,保持向后兼容
|
||||
5. **文档注释**:Rust 代码使用 `///` 注释,会通过 PyO3 生成 Python docstring
|
||||
|
||||
## 相关文件
|
||||
|
||||
- [config.yaml](config.yaml) - 项目架构说明(包含 rust_core、internal_package 等 directive)
|
||||
- [abp.md](abp.md) - ABP 协议规范
|
||||
- [agent-message.md](agent-message.md) - 消息处理规范
|
||||
- `openspec/changes/abp-protocol-implementation/` - ABP 实现 change proposal(含详细任务清单)
|
||||
Reference in New Issue
Block a user