mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
feat: 重构处理器分发和插件加载模块,增强兼容性和错误处理,更新文档
This commit is contained in:
@@ -1,4 +1,63 @@
|
||||
"""插件侧 handler 调度器。
|
||||
"""处理器分发模块。
|
||||
|
||||
定义 HandlerDispatcher 类,负责将能力调用分发到具体的处理器函数。
|
||||
支持参数注入、流式执行、错误处理和生命周期回调。
|
||||
|
||||
核心职责:
|
||||
- 根据处理器 ID 查找处理器
|
||||
- 构建处理器参数(支持类型注解注入)
|
||||
- 执行处理器并处理结果
|
||||
- 处理异步生成器流式结果
|
||||
- 统一的错误处理
|
||||
|
||||
参数注入优先级:
|
||||
1. 按类型注解注入(支持 Optional[Type])
|
||||
2. 按参数名注入(兼容无类型注解)
|
||||
3. 从 legacy_args 注入(命令参数等)
|
||||
|
||||
支持的注入类型:
|
||||
- MessageEvent: 消息事件
|
||||
- Context: 运行时上下文
|
||||
|
||||
与旧版对比:
|
||||
旧版 HandlerExecutor:
|
||||
- 从 star_handlers_registry 获取处理器
|
||||
- 直接调用 handler(event, **args)
|
||||
- 无参数注入支持
|
||||
- 通过 JSON-RPC notification 发送流式结果
|
||||
- 错误通过 JSON-RPC error 响应
|
||||
|
||||
新版 HandlerDispatcher:
|
||||
- 从 LoadedHandler 映射获取处理器
|
||||
- 支持类型注解注入 (MessageEvent, Context)
|
||||
- 支持参数名注入 (event, ctx, context)
|
||||
- 支持 legacy_args 注入
|
||||
- 支持 Optional[Type] 类型
|
||||
- 支持默认值
|
||||
- 统一的错误处理和 on_error 回调
|
||||
|
||||
处理器签名兼容:
|
||||
# 旧版签名
|
||||
def handler(event: AstrMessageEvent) -> str:
|
||||
return "result"
|
||||
|
||||
# 新版签名(类型注入)
|
||||
async def handler(event: MessageEvent, ctx: Context) -> None:
|
||||
await event.reply("result")
|
||||
|
||||
# 新版签名(名字注入)
|
||||
async def handler(event, ctx) -> None:
|
||||
await ctx.platform.send(event.session_id, "result")
|
||||
|
||||
# 流式处理器
|
||||
async def streaming_handler(event: MessageEvent):
|
||||
yield "chunk 1"
|
||||
yield "chunk 2"
|
||||
|
||||
结果处理:
|
||||
- PlainTextResult: 调用 event.reply()
|
||||
- str: 调用 event.reply()
|
||||
- dict with "text": 调用 event.reply(str(item["text"]))
|
||||
|
||||
`HandlerDispatcher` 把运行时收到的 `handler.invoke` 请求转成真实 Python 调用。
|
||||
它的职责只包括参数注入、legacy 返回值兼容和错误回调;不负责 handler 发现或
|
||||
|
||||
@@ -1,4 +1,77 @@
|
||||
"""插件发现、环境准备和组件加载。
|
||||
"""插件加载模块。
|
||||
|
||||
定义插件发现、环境管理和加载的核心逻辑。
|
||||
支持新旧两种 Star 组件的兼容加载。
|
||||
|
||||
核心概念:
|
||||
PluginSpec: 插件规范,描述插件的基本信息
|
||||
PluginDiscoveryResult: 插件发现结果,包含成功和跳过的插件
|
||||
PluginEnvironmentManager: 插件虚拟环境管理器
|
||||
LoadedHandler: 加载后的处理器,包含描述符和可调用对象
|
||||
LoadedPlugin: 加载后的插件,包含处理器和实例
|
||||
|
||||
插件发现流程:
|
||||
1. 扫描 plugins_dir 下的子目录
|
||||
2. 检查 plugin.yaml 和 requirements.txt
|
||||
3. 解析 manifest_data 获取插件信息
|
||||
4. 验证必要字段(name, components, runtime.python)
|
||||
5. 返回 PluginDiscoveryResult
|
||||
|
||||
环境管理流程:
|
||||
1. 检查 .venv 目录是否存在
|
||||
2. 检查 Python 版本是否匹配
|
||||
3. 检查指纹是否变化(requirements 内容)
|
||||
4. 必要时重建虚拟环境
|
||||
5. 使用 uv 安装依赖
|
||||
|
||||
插件加载流程:
|
||||
1. 将插件目录添加到 sys.path
|
||||
2. 遍历 components 列表
|
||||
3. 动态导入组件类
|
||||
4. 判断是否为新版 Star
|
||||
5. 创建实例(新版直接实例化,旧版传入 legacy_context)
|
||||
6. 扫描处理器方法
|
||||
7. 构建 HandlerDescriptor
|
||||
|
||||
新旧 Star 组件兼容:
|
||||
新版 Star:
|
||||
- 继承自 Star 基类
|
||||
- __astrbot_is_new_star__ 返回 True
|
||||
- 无参构造函数
|
||||
- 通过 @handler 装饰器注册处理器
|
||||
|
||||
旧版 Star:
|
||||
- 不继承或 __astrbot_is_new_star__ 返回 False
|
||||
- 需要 legacy_context 参数
|
||||
- 通过 @xxx_handler 装饰器注册处理器
|
||||
- 使用 extras_configs 传递配置
|
||||
|
||||
与旧版对比:
|
||||
旧版 StarManager:
|
||||
- 通过 plugin.yaml 发现插件
|
||||
- 动态导入组件类并实例化
|
||||
- 注册到 star_handlers_registry
|
||||
- 使用 functools.partial 绑定实例
|
||||
- 无环境管理
|
||||
- 无指纹缓存
|
||||
|
||||
新版 loader.py:
|
||||
- PluginSpec 描述插件规范
|
||||
- PluginEnvironmentManager 管理虚拟环境
|
||||
- load_plugin() 加载并解析组件
|
||||
- LoadedHandler 封装处理器和描述符
|
||||
- 支持新旧 Star 组件兼容
|
||||
- 支持环境指纹缓存
|
||||
|
||||
plugin.yaml 格式:
|
||||
name: my_plugin
|
||||
author: author_name
|
||||
desc: Plugin description
|
||||
version: 1.0.0
|
||||
runtime:
|
||||
python: "3.11"
|
||||
components:
|
||||
- class: my_plugin.main:MyComponent
|
||||
|
||||
`loader` 是 runtime 与插件代码之间的边界层,负责三件事:
|
||||
|
||||
|
||||
@@ -1,4 +1,73 @@
|
||||
"""运行时协议对等端。
|
||||
"""协议对等端模块。
|
||||
|
||||
定义 Peer 类,封装双向传输通道上的消息收发、初始化握手、能力调用、
|
||||
流式事件转发与取消处理。这里的 peer 指"通信对端/本端"这一网络协议概念,
|
||||
而不是业务上的用户、群聊或会话对象。
|
||||
|
||||
核心职责:
|
||||
- 消息序列化/反序列化
|
||||
- 初始化握手协议
|
||||
- 能力调用(同步/流式)
|
||||
- 取消处理
|
||||
- 连接生命周期管理
|
||||
消息处理:
|
||||
入站:
|
||||
ResultMessage -> 唤醒等待的 Future
|
||||
EventMessage -> 投递到流式队列
|
||||
InitializeMessage -> 调用 initialize_handler
|
||||
InvokeMessage -> 创建任务调用 invoke_handler
|
||||
CancelMessage -> 取消对应的任务
|
||||
|
||||
出站:
|
||||
initialize() -> InitializeMessage
|
||||
invoke() -> InvokeMessage(stream=False)
|
||||
invoke_stream() -> InvokeMessage(stream=True)
|
||||
cancel() -> CancelMessage
|
||||
|
||||
与旧版对比:
|
||||
旧版 JSON-RPC:
|
||||
- 分离的 JSONRPCClient 和 JSONRPCServer
|
||||
- 通过 method 字段区分操作类型
|
||||
- 使用 JSONRPCRequest/Response 消息类型
|
||||
- 流式通过独立的 notification 实现
|
||||
- 无统一的取消机制
|
||||
|
||||
新版 Peer:
|
||||
- 统一的 Peer 抽象,既是客户端也是服务端
|
||||
- 通过 type 字段区分消息类型
|
||||
- 使用 InitializeMessage/InvokeMessage/EventMessage 等
|
||||
- 流式通过 EventMessage(phase=delta) 实现
|
||||
- 统一的 CancelMessage 取消机制
|
||||
|
||||
使用示例:
|
||||
# 作为客户端发起调用
|
||||
peer = Peer(transport=transport, peer_info=PeerInfo(...))
|
||||
await peer.start()
|
||||
output = await peer.initialize(handlers)
|
||||
result = await peer.invoke("llm.chat", {"prompt": "hello"})
|
||||
|
||||
# 作为服务端处理调用
|
||||
peer.set_invoke_handler(my_handler)
|
||||
await peer.start()
|
||||
|
||||
消息处理流程:
|
||||
入站消息:
|
||||
ResultMessage -> 唤醒等待的 Future
|
||||
EventMessage -> 投递到流式队列
|
||||
InitializeMessage -> 调用 _initialize_handler
|
||||
InvokeMessage -> 创建任务调用 _invoke_handler
|
||||
CancelMessage -> 取消对应的任务
|
||||
|
||||
出站消息:
|
||||
initialize() -> InitializeMessage
|
||||
invoke() -> InvokeMessage(stream=False)
|
||||
invoke_stream() -> InvokeMessage(stream=True)
|
||||
cancel() -> CancelMessage
|
||||
|
||||
取消机制:
|
||||
- CancelToken 用于检查取消状态
|
||||
- 入站任务在收到 CancelMessage 时被取消
|
||||
- 早到取消:在任务执行前检查 cancel_token,避免竞态条件
|
||||
|
||||
`Peer` 把 `Transport` 和 v4 协议消息模型接起来,负责:
|
||||
|
||||
@@ -344,7 +413,7 @@ class Peer:
|
||||
if isinstance(exc, AstrBotError):
|
||||
error = exc
|
||||
else:
|
||||
error = AstrBotError.protocol_error(f"协议消息处理失败: {exc}")
|
||||
error = AstrBotError.protocol_error(f"无法解析协议消息: {exc}")
|
||||
await self._fail_connection(error)
|
||||
raise error from exc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user