mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-17 01:46:07 +00:00
feat(agent-runner): enforce 4.x host-owned execution
This commit is contained in:
@@ -48,7 +48,9 @@ MessageAggregator (消息聚合)
|
||||
QueryPool → Controller → Pipeline (固定阶段链)
|
||||
│ │
|
||||
│ ▼
|
||||
│ RequestRunner (local-agent / dify / n8n / ...)
|
||||
│ AgentRunner Host orchestrator
|
||||
│ ▼
|
||||
│ plugin AgentRunner
|
||||
│
|
||||
▼
|
||||
adapter.reply_message() / adapter.send_message()
|
||||
@@ -71,13 +73,14 @@ adapter.reply_message() / adapter.send_message()
|
||||
▼
|
||||
EventBus (统一事件总线)
|
||||
│
|
||||
▼
|
||||
EventRouter (事件路由引擎, 读取 Bot 的 event_handlers 配置)
|
||||
├─→ Plugin EventListener observers(始终广播,不参与响应仲裁)
|
||||
│
|
||||
├─→ PipelineHandler — 现有流水线(完整 Stage 链)
|
||||
├─→ AgentHandler — 直接调用 RequestRunner(轻量 AI 处理)
|
||||
├─→ WebhookHandler — POST 到外部服务(Dify/n8n webhook 等)
|
||||
└─→ PluginHandler — 分发给插件 EventListener
|
||||
▼
|
||||
EventRouter (读取 Bot 的 event_bindings)
|
||||
│
|
||||
├─→ Pipeline target — 完整 Stage 链,仅消息事件
|
||||
├─→ Agent target — 独立 Agent,经插件 AgentRunner 执行
|
||||
└─→ discard — 明确丢弃
|
||||
│
|
||||
▼
|
||||
统一平台 API
|
||||
@@ -141,20 +144,13 @@ pkg/platform/adapters/
|
||||
|
||||
详见 [03-adapter-structure.md](./03-adapter-structure.md)。
|
||||
|
||||
### 3.4 事件处理器(Event Handler)
|
||||
### 3.4 事件响应目标与观察者
|
||||
|
||||
> **2026-06 方向修订**:四种 Handler 分类法已演进为「事件 → 处理器」统一路由。Pipeline 与 Agent 是长期并存、场景不同的同级处理器:Pipeline 面向消息事件的完整 Stage 链,Agent 面向其声明支持的消息或非消息事件;插件 EventListener 保留为观察者角色。详见 [07-agent-orchestration.md](./07-agent-orchestration.md)。本节保留原设计供对照。
|
||||
Pipeline 与 Agent 是长期并存、场景不同的同级处理器。Pipeline 保留完整 Stage 链,面向消息处理;Agent 是独立配置对象,选择一个已安装的插件 AgentRunner,并可声明消息或非消息事件能力。Bot 的 `event_bindings` 只负责把事件绑定到既有 Pipeline、独立 Agent 或 `discard`。
|
||||
|
||||
四种处理器类型,用户在 WebUI 的 Bot 管理页面配置:
|
||||
插件 EventListener 是观察者:事件先广播给有权限的监听器,随后路由器再选择一个响应目标。Webhook、Dify、n8n 等外部执行方式若需要作为响应者,应由对应 AgentRunner 插件表达,而不是增加另一套 Host Handler 主链。
|
||||
|
||||
| 类型 | 说明 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| **pipeline** | 现有流水线机制,完整的多 Stage 处理链(PreProcessor → MessageProcessor → PostProcessor 等) | 复杂消息处理,需要完整的预处理/后处理流程 |
|
||||
| **agent** | 直接调用 RequestRunner(local-agent / dify / n8n / coze / dashscope / langflow / tbox),从 Pipeline 中解耦 | 轻量级 AI 处理、直接对接外部 LLMOps 平台处理各类事件 |
|
||||
| **webhook** | 将事件 POST 到外部 URL,根据响应执行动作 | 对接自建服务、Dify/n8n 的 Webhook 触发器、自定义后端 |
|
||||
| **plugin** | 分发给插件 EventListener 处理 | 插件自定义逻辑 |
|
||||
|
||||
配置存储在 Bot 表的 `event_handlers` JSON 字段中,通过 WebUI 编排面板管理。
|
||||
现有 Pipeline 不会被转换为 Agent,Pipeline 内的 runner 配置也不会复制到独立 Agent。用户需要 Agent 时自行创建并绑定。
|
||||
|
||||
详见 [04-event-routing.md](./04-event-routing.md)。
|
||||
|
||||
@@ -173,8 +169,8 @@ pkg/platform/adapters/
|
||||
| 1 | 事件处理器配置粒度 | 每个 Bot 独立配置 | Bot 是用户操作的核心单元,不同 Bot 可能对接不同业务场景 |
|
||||
| 2 | 适配器特有 API | 统一抽象 + `call_platform_api` 透传 | 通用 API 覆盖大部分场景,透传机制保证灵活性,避免每个适配器导出独立的类型化 API 包 |
|
||||
| 3 | 向后兼容策略 | 兼容层适配 | 保留旧事件类型和 API 作为新系统的 alias/wrapper,现有插件无需修改 |
|
||||
| 4 | 处理器配置存储 | Bot 表新增 `event_handlers` JSON 字段 | 简单直接,避免新增关联表;替代现有 `use_pipeline_uuid` |
|
||||
| 5 | Agent 处理器定位 | 从 Pipeline 中解耦 RequestRunner | 不是所有事件都需要完整 Pipeline Stage 链;Agent 处理器提供轻量级 AI 处理路径,支持所有现有 Runner |
|
||||
| 4 | 处理器配置存储 | Bot 表使用 `event_bindings`,目标引用原始 Pipeline 或独立 Agent UUID | 路由关系不复制处理器配置,Pipeline/Agent 各自保持事实源 |
|
||||
| 5 | Agent 处理器定位 | 独立 Agent + 插件 AgentRunner | Host 不再内置具体 runner;不同 AgentRunner 通过统一协议接入 |
|
||||
| 6 | 事件命名方式 | 命名空间式(`message.received`) | 清晰的分类层级,便于通配匹配(`message.*`),与 WebUI 配置天然对应 |
|
||||
|
||||
## 5. 文档索引
|
||||
@@ -194,7 +190,7 @@ pkg/platform/adapters/
|
||||
| 仓库 | 改动范围 |
|
||||
|------|----------|
|
||||
| **langbot-plugin-sdk** | 事件定义、实体模型、API 接口、适配器基类、通信协议扩展 |
|
||||
| **LangBot**(后端) | 适配器实现、事件路由引擎、Bot 实体扩展、数据库迁移、RequestRunner 解耦 |
|
||||
| **LangBot**(后端) | 适配器实现、事件路由引擎、Bot/Agent 实体、AgentRunner Host 编排 |
|
||||
| **LangBot**(前端) | Bot 事件处理器编排面板 |
|
||||
| **langbot-wiki** | 新架构文档、插件开发指南更新、适配器开发指南 |
|
||||
| **langbot-plugin-demo** | 示例更新(使用新事件和 API) |
|
||||
|
||||
@@ -490,18 +490,19 @@ class PlatformSpecificEvent(Event):
|
||||
│
|
||||
5. EventBus 分发
|
||||
│
|
||||
6. EventRouter 查询 Bot 的 event_handlers 配置
|
||||
│ 匹配事件类型 → 找到对应的 Handler
|
||||
│ 支持通配符:'message.*' 匹配所有消息事件
|
||||
│ 未匹配到 → 走默认 Handler(plugin,保持向后兼容)
|
||||
6. EventBus 向有权限的 Plugin EventListener 广播观察者事件
|
||||
│ observer 不占用响应目标,也不参与 priority 仲裁
|
||||
│
|
||||
7. Handler 处理事件
|
||||
│ PipelineHandler → 进入 Pipeline 流水线
|
||||
│ AgentHandler → 调用 RequestRunner
|
||||
│ WebhookHandler → POST 到外部 URL
|
||||
│ PluginHandler → 分发给插件 EventListener
|
||||
7. EventRouter 查询 Bot 的 event_bindings
|
||||
│ 精确/通配匹配 event_pattern,应用 filters 与 priority
|
||||
│ 选择一个 Pipeline、Agent 或 discard 目标
|
||||
│
|
||||
8. Handler 执行完毕,可能通过 API 执行响应动作
|
||||
8. 目标处理事件
|
||||
│ Pipeline → 进入完整 Pipeline 流水线(仅消息事件)
|
||||
│ Agent → Host 编排已安装的插件 AgentRunner
|
||||
│ discard → 不产生响应
|
||||
│
|
||||
9. 处理器执行完毕,可能通过 Host 授权 API 执行响应动作
|
||||
(发消息、编辑消息、踢人、同意好友请求等)
|
||||
```
|
||||
|
||||
|
||||
@@ -1,747 +1,174 @@
|
||||
# 事件路由与编排
|
||||
|
||||
> **2026-06 方向修订**:本文档的四种 handler_type(pipeline / agent / webhook / plugin)分类法已被「事件 → 处理器(Agent / Pipeline)」统一编排取代,收编映射与新数据模型见 [07-agent-orchestration.md](./07-agent-orchestration.md)。本文档中的事件匹配规则(§4)、`use_pipeline_uuid` 路由迁移策略(§6)、WebUI 交互骨架(§7)与 webhook 请求/响应格式(§5.4)仍然有效。
|
||||
> 状态:当前实施模型(2026-07-12)。本文以 Pipeline / Agent 平级并存为准,不再保留早期 `pipeline / agent / webhook / plugin` 四种 Handler 草案。
|
||||
|
||||
## 1. 概述
|
||||
## 1. 路由边界
|
||||
|
||||
事件路由是 EBA 架构的核心机制:事件从适配器产生后,经由 EventBus 进入 EventRouter,由 EventRouter 根据 Bot 的配置将事件分发到对应的处理器(Handler)。
|
||||
EBA 将事件处理拆成两个互不替代的阶段:
|
||||
|
||||
**配置方式**:用户在 WebUI 的 Bot 管理页面通过可视化编排面板管理事件处理器配置,配置数据存储在数据库的 Bot 表 `event_handlers` JSON 字段中。
|
||||
1. **观察者广播**:EventBus 把事件广播给有权限的插件 EventListener。观察者可记录、同步或执行受控副作用,但不占用响应目标。
|
||||
2. **响应者仲裁**:EventRouter 按 Bot 的 `event_bindings` 选择一个 Pipeline、独立 Agent 或 `discard`。
|
||||
|
||||
Pipeline 与 Agent 是平级处理器:
|
||||
|
||||
| 处理器 | 配置事实源 | 执行路径 | 事件范围 |
|
||||
| --- | --- | --- | --- |
|
||||
| Pipeline | Pipeline 表与完整 Stage 配置 | MessageAggregator -> QueryPool -> RuntimePipeline | 消息事件,首版为 `message.received` |
|
||||
| Agent | Agent 表中的 runner 与 runner config | AgentRunner Host orchestrator -> plugin AgentRunner | Agent/Runner 声明支持的消息或非消息事件 |
|
||||
| discard | 无处理器配置 | 明确结束路由 | 任意事件 |
|
||||
|
||||
插件 EventListener 不是第三种响应目标。Webhook、Dify、n8n、Coze 等外部系统需要响应事件时,由对应 AgentRunner 插件承接。
|
||||
|
||||
## 2. 数据模型
|
||||
|
||||
### 2.1 Bot 实体扩展
|
||||
### 2.1 独立 Agent
|
||||
|
||||
在 `bots` 表新增 `event_handlers` 字段:
|
||||
Agent 保存自己的 Runner 选择与配置,不嵌入 Pipeline,也不复制 Pipeline 的 AI stage:
|
||||
|
||||
```python
|
||||
class Bot(Base):
|
||||
__tablename__ = "bots"
|
||||
|
||||
uuid: str # 主键
|
||||
class Agent(Base):
|
||||
uuid: str
|
||||
name: str
|
||||
description: str
|
||||
adapter: str
|
||||
adapter_config: dict # JSON
|
||||
enable: bool
|
||||
|
||||
# 新增
|
||||
event_handlers: list # JSON — 事件处理器配置列表
|
||||
|
||||
# 保留(过渡期后弃用)
|
||||
use_pipeline_name: str # deprecated
|
||||
use_pipeline_uuid: str # deprecated
|
||||
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
emoji: str
|
||||
kind: str # 固定为 "agent"
|
||||
component_ref: str # AgentRunner id
|
||||
config: dict # runner + runner_config
|
||||
enabled: bool
|
||||
supported_event_patterns: list[str]
|
||||
```
|
||||
|
||||
### 2.2 EventHandler 配置结构
|
||||
当前配置形状:
|
||||
|
||||
`event_handlers` 字段存储一个 JSON 数组,每个元素定义一条事件路由规则:
|
||||
```json
|
||||
{
|
||||
"runner": {
|
||||
"id": "plugin:langbot-team/LocalAgent/default"
|
||||
},
|
||||
"runner_config": {
|
||||
"plugin:langbot-team/LocalAgent/default": {
|
||||
"model": {
|
||||
"primary": "model-uuid",
|
||||
"fallbacks": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Runner id 来自已安装插件的 AgentRunner manifest。Host 不维护 LocalAgent、Dify 或其他具体实现的内置分支。
|
||||
|
||||
### 2.2 EventBinding
|
||||
|
||||
Bot 维护事件到处理器的引用:
|
||||
|
||||
```python
|
||||
class EventHandlerConfig(pydantic.BaseModel):
|
||||
"""单条事件处理器配置"""
|
||||
|
||||
event_type: str
|
||||
"""匹配的事件类型
|
||||
|
||||
支持精确匹配和通配符:
|
||||
- "message.received" — 精确匹配
|
||||
- "message.*" — 匹配 message 命名空间下所有事件
|
||||
- "group.*" — 匹配 group 命名空间下所有事件
|
||||
- "*" — 匹配所有事件(兜底)
|
||||
"""
|
||||
|
||||
handler_type: str
|
||||
"""处理器类型: "pipeline" | "agent" | "webhook" | "plugin" """
|
||||
|
||||
handler_config: dict = {}
|
||||
"""处理器的具体配置,结构取决于 handler_type"""
|
||||
|
||||
enabled: bool = True
|
||||
"""是否启用此规则"""
|
||||
|
||||
priority: int = 0
|
||||
"""优先级,数字越大越先匹配(同一事件类型有多条规则时)"""
|
||||
|
||||
description: str = ""
|
||||
"""规则描述(供 WebUI 显示)"""
|
||||
class EventBinding(BaseModel):
|
||||
id: str
|
||||
event_pattern: str # 精确、namespace.* 或 *
|
||||
target_type: str # agent | pipeline | discard
|
||||
target_uuid: str | None # Agent/Pipeline 原始 UUID
|
||||
filters: list[dict]
|
||||
priority: int
|
||||
enabled: bool
|
||||
description: str
|
||||
```
|
||||
|
||||
### 2.3 各 Handler 类型的 handler_config 结构
|
||||
|
||||
#### pipeline
|
||||
|
||||
```json
|
||||
{
|
||||
"handler_type": "pipeline",
|
||||
"handler_config": {
|
||||
"pipeline_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
将事件作为消息事件传入现有 Pipeline 流水线。仅适用于 `message.received` 事件。
|
||||
|
||||
#### agent
|
||||
|
||||
```json
|
||||
{
|
||||
"handler_type": "agent",
|
||||
"handler_config": {
|
||||
"runner": "local-agent",
|
||||
"runner_config": {
|
||||
"model_uuid": "...",
|
||||
"prompt": "你是一个群组助理,请处理以下事件:{event_summary}",
|
||||
"tools_enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"handler_type": "agent",
|
||||
"handler_config": {
|
||||
"runner": "dify-service-api",
|
||||
"runner_config": {
|
||||
"base_url": "https://api.dify.ai/v1",
|
||||
"api_key": "...",
|
||||
"app_type": "agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
直接调用 RequestRunner 处理事件。可用的 runner 包括:
|
||||
- `local-agent` — 内置 LLM Agent
|
||||
- `dify-service-api` — Dify 平台
|
||||
- `n8n-service-api` — n8n 工作流
|
||||
- `coze-api` — Coze (扣子)
|
||||
- `dashscope-app-api` — 阿里百炼
|
||||
- `langflow-api` — Langflow
|
||||
- `tbox-app-api` — 蚂蚁 Tbox
|
||||
|
||||
Agent 处理器不经过 Pipeline 的多 Stage 流程,而是直接构建上下文并调用 Runner。适用于所有事件类型。
|
||||
|
||||
**Agent Handler 与 Pipeline 的关系**:
|
||||
- Pipeline 是完整的多 Stage 处理链(PreProcessor → MessageProcessor(内含Runner) → PostProcessor → ...),适合复杂消息处理
|
||||
- Agent Handler 是轻量级的,直接调用 Runner,跳过 PreProcessor/PostProcessor 等阶段
|
||||
- Pipeline 内部的 AI Stage 仍然使用 Runner,所以 Runner 本身被两种 Handler 共享
|
||||
- 用户可以根据场景选择:消息处理用 Pipeline(更多控制),其他事件用 Agent(更直接)
|
||||
|
||||
#### webhook
|
||||
|
||||
```json
|
||||
{
|
||||
"handler_type": "webhook",
|
||||
"handler_config": {
|
||||
"url": "https://example.com/webhook/langbot-events",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Authorization": "Bearer xxx"
|
||||
},
|
||||
"timeout": 30,
|
||||
"retry_count": 3,
|
||||
"retry_interval": 5,
|
||||
"response_actions": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
将事件序列化为 JSON POST 到外部 URL。支持的特性:
|
||||
- **认证**:通过 headers 配置(Bearer Token、API Key 等)
|
||||
- **重试**:配置重试次数和间隔
|
||||
- **响应动作**:如果 `response_actions` 为 true,解析响应 JSON 中的 `actions` 字段并执行(如发送消息、同意好友请求等)
|
||||
|
||||
Webhook 请求体格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"type": "group.member_joined",
|
||||
"timestamp": 1700000000.0,
|
||||
"bot_uuid": "...",
|
||||
"adapter_name": "telegram",
|
||||
"group": { "id": "...", "name": "..." },
|
||||
"member": { "id": "...", "nickname": "..." }
|
||||
},
|
||||
"bot": {
|
||||
"uuid": "...",
|
||||
"name": "...",
|
||||
"adapter": "telegram"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
响应体格式(当 `response_actions` 为 true 时):
|
||||
|
||||
```json
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"type": "send_message",
|
||||
"params": {
|
||||
"target_type": "group",
|
||||
"target_id": "123456",
|
||||
"message": [{ "type": "Plain", "text": "欢迎新成员!" }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "call_platform_api",
|
||||
"params": {
|
||||
"action": "pin_message",
|
||||
"params": { "chat_id": "123456", "message_id": "789" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### plugin
|
||||
|
||||
```json
|
||||
{
|
||||
"handler_type": "plugin",
|
||||
"handler_config": {
|
||||
"plugin_filter": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
将事件分发给插件的 EventListener 处理。
|
||||
|
||||
- `plugin_filter`:可选的插件名过滤列表,为空表示分发给所有插件
|
||||
- 沿用现有的插件事件分发机制(按优先级遍历插件,支持 `prevent_postorder`)
|
||||
|
||||
### 2.4 完整配置示例
|
||||
|
||||
一个 Bot 的 `event_handlers` 配置示例:
|
||||
示例:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"event_type": "message.received",
|
||||
"handler_type": "pipeline",
|
||||
"handler_config": {
|
||||
"pipeline_uuid": "default-pipeline-uuid"
|
||||
},
|
||||
"enabled": true,
|
||||
"priority": 10,
|
||||
"description": "消息事件使用默认流水线处理"
|
||||
},
|
||||
{
|
||||
"event_type": "group.member_joined",
|
||||
"handler_type": "agent",
|
||||
"handler_config": {
|
||||
"runner": "local-agent",
|
||||
"runner_config": {
|
||||
"model_uuid": "gpt-4o-mini",
|
||||
"prompt": "有新成员 {member_name} 加入了群组 {group_name},请生成一条欢迎消息。"
|
||||
}
|
||||
},
|
||||
"enabled": true,
|
||||
"priority": 0,
|
||||
"description": "新成员入群时用 AI 生成欢迎消息"
|
||||
},
|
||||
{
|
||||
"event_type": "friend.request_received",
|
||||
"handler_type": "webhook",
|
||||
"handler_config": {
|
||||
"url": "https://my-server.com/api/friend-request",
|
||||
"response_actions": true
|
||||
},
|
||||
"enabled": true,
|
||||
"priority": 0,
|
||||
"description": "好友请求转发到自建服务处理"
|
||||
},
|
||||
{
|
||||
"event_type": "*",
|
||||
"handler_type": "plugin",
|
||||
"handler_config": {},
|
||||
"enabled": true,
|
||||
"priority": -100,
|
||||
"description": "所有事件兜底发给插件处理"
|
||||
}
|
||||
{
|
||||
"id": "binding-message",
|
||||
"event_pattern": "message.received",
|
||||
"target_type": "pipeline",
|
||||
"target_uuid": "pipeline-uuid",
|
||||
"filters": [],
|
||||
"priority": 100,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"id": "binding-member-joined",
|
||||
"event_pattern": "group.member_joined",
|
||||
"target_type": "agent",
|
||||
"target_uuid": "agent-uuid",
|
||||
"filters": [],
|
||||
"priority": 50,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 3. EventBus 设计
|
||||
Binding 只保存引用与路由条件。它不复制 Pipeline 或 Agent 配置。
|
||||
|
||||
EventBus 是事件的中转站,接收来自各个 RuntimeBot 的事件,交由 EventRouter 处理。
|
||||
## 3. 匹配与仲裁
|
||||
|
||||
```python
|
||||
class EventBus:
|
||||
"""事件总线"""
|
||||
事件模式支持:
|
||||
|
||||
def __init__(self, ap: Application):
|
||||
self.ap = ap
|
||||
self.event_router = EventRouter(ap)
|
||||
- 精确匹配:`group.member_joined`
|
||||
- 命名空间通配:`group.*`
|
||||
- 全局通配:`*`
|
||||
|
||||
async def emit(
|
||||
self,
|
||||
event: Event,
|
||||
adapter: AbstractPlatformAdapter,
|
||||
):
|
||||
"""接收并分发事件
|
||||
路由按以下顺序处理:
|
||||
|
||||
Args:
|
||||
event: 统一事件对象
|
||||
adapter: 产生此事件的适配器实例
|
||||
"""
|
||||
# 1. 全局事件日志
|
||||
self.ap.logger.debug(
|
||||
f"EventBus: {event.type} from bot {event.bot_uuid}"
|
||||
)
|
||||
1. 忽略 `enabled = false` 的 binding。
|
||||
2. 检查 `event_pattern` 与结构化 filters。
|
||||
3. 校验目标存在、启用且声明支持该事件。
|
||||
4. 按 `priority` 从高到低选择;同优先级按稳定列表顺序。
|
||||
5. 只执行一个响应目标。
|
||||
|
||||
# 2. 交由 EventRouter 路由处理
|
||||
await self.event_router.route(event, adapter)
|
||||
Pipeline 目标只能匹配消息事件。非消息事件不得伪装成用户文本塞进 Pipeline。
|
||||
|
||||
## 4. 执行流程
|
||||
|
||||
```text
|
||||
Platform adapter
|
||||
-> normalized event
|
||||
-> EventBus
|
||||
-> authorized Plugin EventListener observers
|
||||
-> EventRouter
|
||||
-> Pipeline target -> full Pipeline stage chain
|
||||
-> Agent target -> AgentRunner Host orchestrator
|
||||
-> discard -> stop
|
||||
-> Host delivery/platform API
|
||||
```
|
||||
|
||||
## 4. EventRouter 设计
|
||||
### 4.1 Pipeline target
|
||||
|
||||
EventRouter 是事件路由引擎,根据 Bot 的 `event_handlers` 配置决定事件的处理方式。
|
||||
消息事件按原有方式构造 Query,经 MessageAggregator、QueryPool 和完整 Pipeline Stage 链执行。Pipeline 可以继续使用 AgentRunner 作为 AI stage 的实现,但 Pipeline 本身不会因此变成 Agent。
|
||||
|
||||
```python
|
||||
class EventRouter:
|
||||
"""事件路由引擎"""
|
||||
### 4.2 Agent target
|
||||
|
||||
def __init__(self, ap: Application):
|
||||
self.ap = ap
|
||||
self.handlers: dict[str, AbstractEventHandler] = {
|
||||
"pipeline": PipelineHandler(ap),
|
||||
"agent": AgentHandler(ap),
|
||||
"webhook": WebhookHandler(ap),
|
||||
"plugin": PluginHandler(ap),
|
||||
}
|
||||
Host 读取独立 Agent 的 Runner id/config,构造 event-first context、run-scoped resources 与 delivery policy,再调用插件 AgentRunner。Runner 输出由 Host 统一归一化、记录和投递。
|
||||
|
||||
async def route(
|
||||
self,
|
||||
event: Event,
|
||||
adapter: AbstractPlatformAdapter,
|
||||
):
|
||||
"""路由事件到对应处理器"""
|
||||
AgentRunner 可通过 SDK/Python `AgentRunAPIProxy.call_tool` 或 SDK-owned scoped MCP bridge 回调 Host 能力。两条路径都映射到 `PluginToRuntimeAction.CALL_TOOL`,使用相同的 run authorization、Host execution Query、ToolManager 和 Box session 规则。Box session 是 Host canonical scope 的固定长度安全哈希;同一平台会话稳定、不同 scope 隔离、缺少 identity 时 fail closed,Runner 不配置 sandbox scope。
|
||||
|
||||
# 1. 获取 Bot 配置
|
||||
bot = await self.ap.platform_mgr.get_bot_by_uuid(event.bot_uuid)
|
||||
if not bot:
|
||||
return
|
||||
### 4.3 Observer side effects
|
||||
|
||||
# 2. 获取事件处理器配置
|
||||
event_handlers = bot.bot_entity.event_handlers or []
|
||||
观察者与响应者可以同时工作。为避免编辑、reaction 等合成事件重复触发不可逆操作,Host 应按事件能力和授权过滤观察者可用 API,并记录副作用结果。Observer 广播不作为 fallback 响应。
|
||||
|
||||
# 3. 匹配规则(按 priority 降序排列)
|
||||
matched_handlers = self._match_handlers(event.type, event_handlers)
|
||||
## 5. Pipeline 与 Agent 的并存规则
|
||||
|
||||
if not matched_handlers:
|
||||
# 未匹配到任何规则 → 默认交给插件处理(向后兼容)
|
||||
await self.handlers["plugin"].handle(event, adapter, {})
|
||||
return
|
||||
1. Pipeline 与 Agent 保留各自的持久化、编辑和执行语义。
|
||||
2. 处理器聚合页面可以统一展示二者,但不会创建第三份处理器记录。
|
||||
3. 旧 Pipeline 仍是 Pipeline;其 runner config 不迁移、不复制为独立 Agent。
|
||||
4. 需要 Agent 的用户新建 Agent、选择已安装 AgentRunner,再建立 event binding。
|
||||
5. 一个 Bot 可按不同事件同时绑定 Pipeline 与 Agent。
|
||||
|
||||
# 4. 执行第一个匹配的 Handler
|
||||
# (未来可扩展为多个 Handler 串行/并行执行)
|
||||
handler_config = matched_handlers[0]
|
||||
handler = self.handlers.get(handler_config.handler_type)
|
||||
## 6. WebUI 约束
|
||||
|
||||
if handler:
|
||||
await handler.handle(event, adapter, handler_config.handler_config)
|
||||
else:
|
||||
self.ap.logger.warning(
|
||||
f"Unknown handler type: {handler_config.handler_type}"
|
||||
)
|
||||
处理器入口展示带类型标识的 Agent 与 Pipeline。Bot 事件编排器应:
|
||||
|
||||
def _match_handlers(
|
||||
self,
|
||||
event_type: str,
|
||||
handlers: list[EventHandlerConfig],
|
||||
) -> list[EventHandlerConfig]:
|
||||
"""匹配事件类型到处理器配置
|
||||
- 按 adapter manifest 展示可用事件;
|
||||
- 非消息事件不提供 Pipeline 目标;
|
||||
- Agent 目标按 `supported_event_patterns` 过滤;
|
||||
- 展示 priority、filters、enabled 与 discard;
|
||||
- 保存前校验目标 UUID 与 `target_type` 一致。
|
||||
|
||||
匹配规则:
|
||||
1. 精确匹配:event_type == handler.event_type
|
||||
2. 命名空间通配:handler.event_type 为 "message.*" 时匹配所有 "message.xxx"
|
||||
3. 全局通配:handler.event_type 为 "*" 时匹配所有事件
|
||||
4. 按 priority 降序排列
|
||||
5. 只返回 enabled=True 的规则
|
||||
"""
|
||||
matched = []
|
||||
for handler in handlers:
|
||||
if not handler.enabled:
|
||||
continue
|
||||
if self._event_type_matches(event_type, handler.event_type):
|
||||
matched.append(handler)
|
||||
Pipeline 的配置、Debug Chat 和 Monitoring 继续使用 Pipeline 页面;Agent 使用独立表单配置 Runner 与事件能力。
|
||||
|
||||
matched.sort(key=lambda h: h.priority, reverse=True)
|
||||
return matched
|
||||
## 7. 版本与迁移边界
|
||||
|
||||
@staticmethod
|
||||
def _event_type_matches(event_type: str, pattern: str) -> bool:
|
||||
"""判断事件类型是否匹配模式"""
|
||||
if pattern == "*":
|
||||
return True
|
||||
if pattern == event_type:
|
||||
return True
|
||||
if pattern.endswith(".*"):
|
||||
namespace = pattern[:-2]
|
||||
return event_type.startswith(namespace + ".")
|
||||
return False
|
||||
```
|
||||
此功能按当前 4.x schema 直接实现,不提供 LangBot 3.x 数据库或配置升级路径,也不读取旧 Runner 字段作为 fallback。旧 Pipeline 中的 runner 配置不会生成独立 Agent;用户按新产品模型添加 Agent 即可。
|
||||
|
||||
## 5. 事件处理器(Handler)实现
|
||||
|
||||
### 5.1 Handler 基类
|
||||
|
||||
```python
|
||||
class AbstractEventHandler(abc.ABC):
|
||||
"""事件处理器基类"""
|
||||
|
||||
def __init__(self, ap: Application):
|
||||
self.ap = ap
|
||||
|
||||
@abc.abstractmethod
|
||||
async def handle(
|
||||
self,
|
||||
event: Event,
|
||||
adapter: AbstractPlatformAdapter,
|
||||
config: dict,
|
||||
) -> None:
|
||||
"""处理事件
|
||||
|
||||
Args:
|
||||
event: 统一事件对象
|
||||
adapter: 适配器实例(用于调用平台 API 发送响应)
|
||||
config: handler_config 配置
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
### 5.2 PipelineHandler
|
||||
|
||||
将消息事件注入现有 Pipeline 流水线处理。
|
||||
|
||||
```python
|
||||
class PipelineHandler(AbstractEventHandler):
|
||||
"""Pipeline 处理器 — 将事件送入现有 Pipeline 流水线"""
|
||||
|
||||
async def handle(self, event, adapter, config):
|
||||
pipeline_uuid = config.get("pipeline_uuid")
|
||||
|
||||
if not isinstance(event, MessageReceivedEvent):
|
||||
self.ap.logger.warning(
|
||||
f"PipelineHandler only supports MessageReceivedEvent, "
|
||||
f"got {event.type}"
|
||||
)
|
||||
return
|
||||
|
||||
# 将 MessageReceivedEvent 转换为现有的 Query 并投入 QueryPool
|
||||
# 复用现有的 MessageAggregator + QueryPool + Pipeline 机制
|
||||
launcher_type = (
|
||||
LauncherTypes.PERSON
|
||||
if event.chat_type == ChatType.PRIVATE
|
||||
else LauncherTypes.GROUP
|
||||
)
|
||||
|
||||
await self.ap.msg_aggregator.add_message(
|
||||
bot_uuid=event.bot_uuid,
|
||||
launcher_type=launcher_type,
|
||||
launcher_id=event.chat_id,
|
||||
sender_id=event.sender.id,
|
||||
message_event=event.to_legacy_event(), # 转换为 FriendMessage/GroupMessage
|
||||
message_chain=event.message_chain,
|
||||
adapter=adapter,
|
||||
pipeline_uuid=pipeline_uuid,
|
||||
)
|
||||
```
|
||||
|
||||
### 5.3 AgentHandler
|
||||
|
||||
直接调用 RequestRunner 处理事件,不经过 Pipeline Stage 链。
|
||||
|
||||
```python
|
||||
class AgentHandler(AbstractEventHandler):
|
||||
"""Agent 处理器 — 直接调用 RequestRunner 处理事件"""
|
||||
|
||||
async def handle(self, event, adapter, config):
|
||||
runner_name = config.get("runner", "local-agent")
|
||||
runner_config = config.get("runner_config", {})
|
||||
|
||||
# 1. 查找 Runner 类
|
||||
runner_cls = None
|
||||
for r in preregistered_runners:
|
||||
if r.name == runner_name:
|
||||
runner_cls = r
|
||||
break
|
||||
|
||||
if not runner_cls:
|
||||
self.ap.logger.error(f"Runner not found: {runner_name}")
|
||||
return
|
||||
|
||||
# 2. 构建事件上下文(将事件信息整理为 Runner 可处理的格式)
|
||||
event_context = self._build_event_context(event, runner_config)
|
||||
|
||||
# 3. 实例化并调用 Runner
|
||||
runner = runner_cls(self.ap, self._build_runner_pipeline_config(config))
|
||||
|
||||
response_messages = []
|
||||
async for result in runner.run(event_context):
|
||||
response_messages.append(result)
|
||||
|
||||
# 4. 发送响应(如果 Runner 产生了回复)
|
||||
if response_messages and isinstance(event, MessageReceivedEvent):
|
||||
# 将 Runner 输出转换为 MessageChain 并回复
|
||||
reply_chain = self._build_reply_chain(response_messages)
|
||||
await adapter.reply_message(event, reply_chain)
|
||||
|
||||
def _build_event_context(self, event, runner_config):
|
||||
"""将事件构建为 Runner 可处理的上下文
|
||||
|
||||
对于消息事件,直接使用消息内容。
|
||||
对于其他事件,根据 runner_config 中的 prompt 模板生成描述文本。
|
||||
"""
|
||||
...
|
||||
|
||||
def _build_runner_pipeline_config(self, config):
|
||||
"""将 handler_config 转换为 Runner 需要的 pipeline_config 格式"""
|
||||
...
|
||||
```
|
||||
|
||||
### 5.4 WebhookHandler
|
||||
|
||||
将事件 POST 到外部 URL。
|
||||
|
||||
```python
|
||||
class WebhookHandler(AbstractEventHandler):
|
||||
"""Webhook 处理器 — 将事件 POST 到外部 URL"""
|
||||
|
||||
async def handle(self, event, adapter, config):
|
||||
url = config.get("url")
|
||||
method = config.get("method", "POST")
|
||||
headers = config.get("headers", {})
|
||||
timeout = config.get("timeout", 30)
|
||||
retry_count = config.get("retry_count", 3)
|
||||
response_actions = config.get("response_actions", False)
|
||||
|
||||
# 1. 构建请求体
|
||||
bot = await self.ap.platform_mgr.get_bot_by_uuid(event.bot_uuid)
|
||||
payload = {
|
||||
"event": event.model_dump(),
|
||||
"bot": {
|
||||
"uuid": bot.bot_entity.uuid,
|
||||
"name": bot.bot_entity.name,
|
||||
"adapter": bot.bot_entity.adapter,
|
||||
}
|
||||
}
|
||||
|
||||
# 2. 发送请求(带重试)
|
||||
response = await self._send_with_retry(
|
||||
url, method, headers, payload, timeout, retry_count
|
||||
)
|
||||
|
||||
# 3. 处理响应动作
|
||||
if response_actions and response:
|
||||
await self._execute_response_actions(
|
||||
response, adapter, event
|
||||
)
|
||||
|
||||
async def _execute_response_actions(self, response, adapter, event):
|
||||
"""执行响应中的动作列表"""
|
||||
actions = response.get("actions", [])
|
||||
for action in actions:
|
||||
action_type = action.get("type")
|
||||
params = action.get("params", {})
|
||||
|
||||
if action_type == "send_message":
|
||||
chain = MessageChain.model_validate(params.get("message", []))
|
||||
await adapter.send_message(
|
||||
params["target_type"],
|
||||
params["target_id"],
|
||||
chain,
|
||||
)
|
||||
elif action_type == "reply":
|
||||
chain = MessageChain.model_validate(params.get("message", []))
|
||||
await adapter.reply_message(event, chain)
|
||||
elif action_type == "call_platform_api":
|
||||
await adapter.call_platform_api(
|
||||
params["action"],
|
||||
params.get("params", {}),
|
||||
)
|
||||
elif action_type == "approve_friend_request":
|
||||
await adapter.approve_friend_request(
|
||||
params["request_id"],
|
||||
params.get("approve", True),
|
||||
)
|
||||
# ... 更多动作类型
|
||||
```
|
||||
|
||||
### 5.5 PluginHandler
|
||||
|
||||
将事件分发给插件的 EventListener。
|
||||
|
||||
```python
|
||||
class PluginHandler(AbstractEventHandler):
|
||||
"""Plugin 处理器 — 分发给插件 EventListener"""
|
||||
|
||||
async def handle(self, event, adapter, config):
|
||||
plugin_filter = config.get("plugin_filter", [])
|
||||
|
||||
# 复用现有的插件事件分发机制
|
||||
# 通过 plugin_connector 将事件发送给 Plugin Runtime
|
||||
await self.ap.plugin_connector.emit_event(
|
||||
event=event,
|
||||
adapter=adapter,
|
||||
plugin_filter=plugin_filter,
|
||||
)
|
||||
```
|
||||
|
||||
## 6. use_pipeline_uuid 迁移
|
||||
|
||||
### 6.1 自动迁移
|
||||
|
||||
数据库迁移脚本将现有的 `use_pipeline_uuid` 自动转换为 `event_handlers`:
|
||||
|
||||
这里迁移的只有 Bot 路由字段:binding 仍指向原 Pipeline,不会新建 Agent,也不会复制 Pipeline 内嵌的 runner 配置。
|
||||
|
||||
```python
|
||||
# 迁移逻辑
|
||||
for bot in all_bots:
|
||||
if bot.use_pipeline_uuid and not bot.event_handlers:
|
||||
bot.event_handlers = [
|
||||
{
|
||||
"event_type": "message.received",
|
||||
"handler_type": "pipeline",
|
||||
"handler_config": {
|
||||
"pipeline_uuid": bot.use_pipeline_uuid
|
||||
},
|
||||
"enabled": True,
|
||||
"priority": 10,
|
||||
"description": "Auto-migrated from use_pipeline_uuid"
|
||||
},
|
||||
{
|
||||
"event_type": "*",
|
||||
"handler_type": "plugin",
|
||||
"handler_config": {},
|
||||
"enabled": True,
|
||||
"priority": -100,
|
||||
"description": "Default plugin handler"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 6.2 过渡期兼容
|
||||
|
||||
在过渡期内,如果 `event_handlers` 为空且 `use_pipeline_uuid` 非空,EventRouter 自动回退到旧行为:
|
||||
|
||||
```python
|
||||
# EventRouter.route() 中的兼容逻辑
|
||||
if not event_handlers and bot.bot_entity.use_pipeline_uuid:
|
||||
# 回退:消息事件走 Pipeline,其他事件走 Plugin
|
||||
if isinstance(event, MessageReceivedEvent):
|
||||
await self.handlers["pipeline"].handle(
|
||||
event, adapter,
|
||||
{"pipeline_uuid": bot.bot_entity.use_pipeline_uuid}
|
||||
)
|
||||
else:
|
||||
await self.handlers["plugin"].handle(event, adapter, {})
|
||||
return
|
||||
```
|
||||
|
||||
## 7. WebUI 编排面板数据模型
|
||||
|
||||
### 7.1 交互设计概要
|
||||
|
||||
在 WebUI 的 Bot 管理页面,新增"事件处理器"标签页(或区域),呈现为一个**规则列表**:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 事件处理器 [+ 添加规则] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─ 规则 1 ─────────────────────────────────── [启用] [删除] ─┐ │
|
||||
│ │ 事件类型: [message.received ▾] │ │
|
||||
│ │ 处理器: [Pipeline ▾] │ │
|
||||
│ │ Pipeline: [默认流水线 ▾] │ │
|
||||
│ │ 优先级: [10] │ │
|
||||
│ │ 描述: 消息事件使用默认流水线处理 │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ 规则 2 ─────────────────────────────────── [启用] [删除] ─┐ │
|
||||
│ │ 事件类型: [group.member_joined ▾] │ │
|
||||
│ │ 处理器: [Agent ▾] │ │
|
||||
│ │ Runner: [local-agent ▾] │ │
|
||||
│ │ 模型: [gpt-4o-mini ▾] │ │
|
||||
│ │ Prompt: [有新成员加入...] │ │
|
||||
│ │ 优先级: [0] │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ 规则 3 (兜底) ──────────────────────────── [启用] [删除] ─┐ │
|
||||
│ │ 事件类型: [* ▾] │ │
|
||||
│ │ 处理器: [Plugin ▾] │ │
|
||||
│ │ 优先级: [-100] │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 7.2 前端数据结构
|
||||
|
||||
```typescript
|
||||
interface EventHandlerRule {
|
||||
event_type: string; // 下拉选择,选项从适配器 manifest 的 supported_events 获取
|
||||
handler_type: string; // "pipeline" | "agent" | "webhook" | "plugin"
|
||||
handler_config: Record<string, any>; // 根据 handler_type 动态渲染不同的配置表单
|
||||
enabled: boolean;
|
||||
priority: number;
|
||||
description: string;
|
||||
}
|
||||
|
||||
// Bot 编辑接口扩展
|
||||
interface BotConfig {
|
||||
uuid: string;
|
||||
name: string;
|
||||
adapter: string;
|
||||
adapter_config: Record<string, any>;
|
||||
enable: boolean;
|
||||
event_handlers: EventHandlerRule[]; // 新增
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 事件类型下拉选项
|
||||
|
||||
从 Bot 关联的适配器 manifest 中获取 `supported_events`,加上通配符选项:
|
||||
|
||||
```
|
||||
- message.received
|
||||
- message.edited
|
||||
- message.deleted
|
||||
- message.reaction
|
||||
- feedback.received
|
||||
- group.member_joined
|
||||
- group.member_left
|
||||
- group.member_banned
|
||||
- group.info_updated
|
||||
- friend.request_received
|
||||
- friend.added
|
||||
- bot.invited_to_group
|
||||
- bot.removed_from_group
|
||||
- bot.muted
|
||||
- bot.unmuted
|
||||
- platform.specific
|
||||
─────────────────
|
||||
- message.* (所有消息事件)
|
||||
- feedback.* (所有反馈事件)
|
||||
- group.* (所有群组事件)
|
||||
- friend.* (所有好友事件)
|
||||
- bot.* (所有 Bot 事件)
|
||||
- * (所有事件)
|
||||
```
|
||||
|
||||
### 7.4 HTTP API
|
||||
|
||||
```
|
||||
GET /api/v1/bots/{uuid}/event-handlers 获取 Bot 的事件处理器配置
|
||||
PUT /api/v1/bots/{uuid}/event-handlers 更新 Bot 的事件处理器配置
|
||||
GET /api/v1/adapters/{name}/supported-events 获取适配器支持的事件类型
|
||||
GET /api/v1/adapters/{name}/supported-apis 获取适配器支持的 API
|
||||
```
|
||||
详见 [07-agent-orchestration.md](./07-agent-orchestration.md) 与 [08-agent-page-and-event-orchestration.md](./08-agent-page-and-event-orchestration.md)。
|
||||
|
||||
@@ -1,433 +1,145 @@
|
||||
# 分阶段迁移计划
|
||||
# EBA 分阶段实施计划
|
||||
|
||||
> **2026-06 方向修订**:Phase 3 的「四种 Handler 框架」与 Phase 5 的编排面板形态,按 [07-agent-orchestration.md](./07-agent-orchestration.md) 调整为「事件 → 处理器」统一路由。EventRouter 通过 `target_type` 在同级 Pipeline / Agent 间选择;二者分别保留自己的实体、配置和执行链。阶段划分、依赖关系与验收标准按 Processor 模型解读;发布节奏见 07 §5「发布火车」。
|
||||
> 更新:2026-07-12。文件名沿用早期设计,但这里的“迁移”仅指代码架构逐步接入 EBA,不代表 LangBot 3.x 数据库或配置升级。
|
||||
|
||||
## 1. 概述
|
||||
## 1. 发布边界
|
||||
|
||||
EBA 架构涉及 langbot-plugin-sdk、LangBot 后端、LangBot 前端、文档和示例插件等多个仓库的改动。为降低风险、保证系统稳定性,采用分阶段渐进式迁移策略。
|
||||
EBA 跨越 SDK、平台适配器、LangBot Host、WebUI 与插件生态,按可验证阶段落地。当前发布遵守以下硬边界:
|
||||
|
||||
### 1.1 阶段总览
|
||||
- LangBot 4.x 不支持从 3.x 数据库或配置升级;不保留 legacy migration chain、旧 JSON 模板或旧 Runner 字段读取。
|
||||
- Pipeline 与 Agent 平级且长期并存,分别保留持久化模型与执行链。
|
||||
- 现有 Pipeline 不迁移为 Agent,Pipeline 内的 runner config 不复制到 Agent。
|
||||
- 用户需要 Agent 时新建独立 Agent并选择已安装的 AgentRunner。
|
||||
- Host 不按 LocalAgent id 做运行时、Box 或 WebUI 特判。
|
||||
- AgentRunner 的 SDK/Python 与 scoped MCP bridge 回调共享 Host 授权与事件 session 规则。
|
||||
|
||||
| 阶段 | 名称 | 范围 | 依赖 |
|
||||
|------|------|------|------|
|
||||
| Phase 1 | SDK 实体层 | langbot-plugin-sdk | 无 |
|
||||
| Phase 2 | 适配器重构 | LangBot 后端 | Phase 1 |
|
||||
| Phase 3 | 核心系统 | LangBot 后端 | Phase 2 |
|
||||
| Phase 4 | 插件 SDK 集成 | langbot-plugin-sdk + LangBot | Phase 3 |
|
||||
| Phase 5 | WebUI 编排面板 | LangBot 前端 | Phase 3 |
|
||||
| Phase 6 | 文档与示例 | langbot-wiki + langbot-plugin-demo | Phase 4, 5 |
|
||||
## 2. 阶段总览
|
||||
|
||||
### 1.2 核心原则
|
||||
| 阶段 | 目标 | 主要仓库 | 完成条件 |
|
||||
| --- | --- | --- | --- |
|
||||
| P0 | SDK 事件、能力与 AgentRunner 协议 | `langbot-plugin-sdk` | typed entities、manifest、proxy、runtime action 通过测试 |
|
||||
| P1 | 平台适配器 EBA 化 | LangBot + SDK | 事件转换、能力声明、通用/透传 API 通过 adapter checklist |
|
||||
| P2 | Host 观察者与响应者路由 | LangBot backend | observer 广播 + Pipeline/Agent/discard 单目标仲裁可运行 |
|
||||
| P3 | 独立 Agent 与 Runner 注册 | LangBot backend + plugins | Agent CRUD、registry、run authorization、delivery 可运行 |
|
||||
| P4 | WebUI 处理器与事件编排 | LangBot web | Agent/Pipeline 聚合入口和 Bot binding 编辑器可用 |
|
||||
| P5 | 发布门禁与文档 | LangBot skills/docs + runner plugins | 单测、UI E2E、真实 adapter smoke 和插件预检通过 |
|
||||
|
||||
- **每个阶段结束后系统可运行**:任何阶段完成后,现有功能不受影响
|
||||
- **向后兼容贯穿全程**:旧接口在整个迁移期间保持可用
|
||||
- **先 SDK 后实现**:先定义好接口和模型,再做具体实现
|
||||
- **先核心适配器后边缘**:优先迁移用户量大的适配器
|
||||
## 3. P0:SDK 契约
|
||||
|
||||
---
|
||||
### 工作项
|
||||
|
||||
## 2. Phase 1:SDK 实体层
|
||||
- 定义规范化平台事件、actor/subject/conversation/delivery context。
|
||||
- 定义 adapter `supported_events`、`supported_apis` 与平台透传 API。
|
||||
- 定义 AgentRunner manifest、run context/result、resource handles 和 pull/callback API。
|
||||
- 提供 `AgentRunAPIProxy` 与 SDK-owned scoped MCP bridge。
|
||||
- 保持协议传输与权限校验可测试,不把 Host 私有 Query 对象暴露给插件。
|
||||
|
||||
**目标**:在 langbot-plugin-sdk 中定义新的事件体系、通用实体、API 接口和适配器基类。
|
||||
### 验收
|
||||
|
||||
**仓库**:`langbot-plugin-sdk`
|
||||
- stdio/WebSocket runtime 对 typed action 的序列化一致。
|
||||
- 无 `run_id` 或越权资源调用被拒绝。
|
||||
- Python proxy 与 MCP bridge 对同一 Host tool 呈现一致结果/错误形状。
|
||||
|
||||
### 2.1 任务清单
|
||||
## 4. P1:平台适配器
|
||||
|
||||
| # | 任务 | 文件/模块 | 说明 |
|
||||
|---|------|----------|------|
|
||||
| 1.1 | 定义通用事件基类层次 | `api/entities/builtin/platform/events.py` | 新增 `MessageReceivedEvent`, `MessageEditedEvent`, `GroupMemberJoinedEvent` 等,保留现有 `FriendMessage`/`GroupMessage` |
|
||||
| 1.2 | 定义平台特有事件基类 | `api/entities/builtin/platform/events.py` | 新增 `PlatformSpecificEvent` |
|
||||
| 1.3 | 扩展通用实体 | `api/entities/builtin/platform/entities.py` | 新增 `User`(统一 Friend/GroupMember 的基础)、`Channel` 等,保留现有实体 |
|
||||
| 1.4 | 清理消息组件 | `api/entities/builtin/platform/message.py` | 将 `WeChatMiniPrograms` 等 WeChat 特有组件标记为 platform-specific,不再作为通用组件 |
|
||||
| 1.5 | 定义新适配器基类 | `api/definition/abstract/platform/adapter.py` | 新增 `AbstractPlatformAdapter`(继承现有 `AbstractMessagePlatformAdapter` 并扩展通用 API 方法),保留旧基类 |
|
||||
| 1.6 | 定义 API 能力声明 | `api/definition/abstract/platform/capabilities.py`(新文件) | `AdapterCapabilities` 数据类,声明适配器支持的事件和 API |
|
||||
| 1.7 | 定义 `NotSupportedError` | `api/entities/builtin/platform/errors.py`(新文件) | 可选 API 未实现时抛出的异常 |
|
||||
每个适配器按自己的能力增量接入,而不是要求所有平台一次性支持全部事件。
|
||||
|
||||
### 2.2 关键设计约束
|
||||
### 单适配器步骤
|
||||
|
||||
- 所有新增定义以**新增文件或新增类**的方式引入,**不修改**现有类的字段和方法签名
|
||||
- 现有 `AbstractMessagePlatformAdapter` 保留不动,新基类 `AbstractPlatformAdapter` 继承它
|
||||
- 新事件类与旧事件类并存,通过 `event_type` 字段(命名空间字符串)区分
|
||||
1. 将原生 SDK callback 转换为规范化事件。
|
||||
2. 声明实际支持的事件与 API,不把缺失能力伪装为成功。
|
||||
3. 实现 send/reply/edit/delete/group/user 等适用 API 与平台透传。
|
||||
4. 对消息链、媒体、reply target 和错误语义写单元测试。
|
||||
5. 按 `adapters/acceptance-checklist.md` 记录真实平台 probe。
|
||||
|
||||
### 2.3 验收标准
|
||||
### 验收
|
||||
|
||||
- [ ] 所有新增类可正常 import 且通过类型检查
|
||||
- [ ] 现有 `FriendMessage`, `GroupMessage`, `AbstractMessagePlatformAdapter` 等类行为不变
|
||||
- [ ] 新增单元测试覆盖事件序列化/反序列化、实体构造
|
||||
- [ ] SDK 版本号 minor bump(如 `0.x.0` → `0.x+1.0`)
|
||||
- `message.received` 保持正常收发。
|
||||
- 新事件不会重复转换或产生循环合成事件。
|
||||
- `supported_apis` 与实际调用能力一致。
|
||||
|
||||
---
|
||||
## 5. P2:Host 路由
|
||||
|
||||
## 3. Phase 2:适配器重构
|
||||
### 执行顺序
|
||||
|
||||
**目标**:将现有单文件适配器迁移到独立目录结构,实现新事件监听和通用 API。
|
||||
|
||||
**仓库**:`LangBot`(后端)
|
||||
|
||||
### 3.1 适配器迁移优先级
|
||||
|
||||
根据用户量和代表性,建议按以下顺序迁移:
|
||||
|
||||
| 优先级 | 适配器 | 理由 |
|
||||
|--------|--------|------|
|
||||
| P0 | **Telegram** | 用户量大,API 最完善,适合作为参考实现 |
|
||||
| P0 | **Discord** | 国际用户主要平台,事件类型丰富 |
|
||||
| P1 | **aiocqhttp**(OneBot v11) | 国内 QQ 用户主要适配器 |
|
||||
| P1 | **Satori** | 通用协议适配器,覆盖多个平台 |
|
||||
| P2 | **Lark** / **DingTalk** / **Slack** | 企业平台,用户量中等 |
|
||||
| P2 | **qqofficial** / **WeChat 系列** | 国内用户 |
|
||||
| P3 | **Kook** / **LINE** / **WeCom 系列** | 用户量较小 |
|
||||
| P3 | **WebSocket** | 内置适配器,相对简单 |
|
||||
| P4 | **legacy/*** | 遗留适配器,按需决定是否迁移或废弃 |
|
||||
|
||||
### 3.2 单个适配器迁移步骤(以 Telegram 为例)
|
||||
|
||||
| # | 任务 | 说明 |
|
||||
|---|------|------|
|
||||
| 2.1 | 创建目录结构 | `pkg/platform/adapters/telegram/` 下创建 `__init__.py`, `adapter.py`, `event_converter.py`, `message_converter.py`, `api_impl.py`, `types.py`, `manifest.yaml` |
|
||||
| 2.2 | 迁移消息转换器 | 将 `TelegramMessageConverter` 从 `sources/telegram.py` 搬到 `adapters/telegram/message_converter.py`,逻辑不变 |
|
||||
| 2.3 | 重写事件转换器 | 新的 `TelegramEventConverter` 支持将 Telegram Update 转换为所有通用事件类型(不只是消息),不支持的事件转为 `PlatformSpecificEvent` |
|
||||
| 2.4 | 实现通用 API | 在 `api_impl.py` 中实现 `edit_message`, `delete_message`, `get_group_info` 等 Telegram 支持的通用 API |
|
||||
| 2.5 | 实现透传 API | 在 `adapter.py` 中实现 `call_platform_api`,将 action 映射到 Telegram Bot API 调用 |
|
||||
| 2.6 | 声明能力 | 在 `manifest.yaml` 或适配器类中声明支持的事件和 API 列表 |
|
||||
| 2.7 | 新建 Adapter 主类 | `TelegramAdapter` 继承 `AbstractPlatformAdapter`(新基类),委托各模块实现 |
|
||||
| 2.8 | 更新 manifest.yaml | 更新 `execution.python.path` 指向新位置 |
|
||||
| 2.9 | 验证 | 确保新适配器通过现有消息收发流程的测试 |
|
||||
|
||||
### 3.3 基础设施任务
|
||||
|
||||
| # | 任务 | 说明 |
|
||||
|---|------|------|
|
||||
| 2.A | 创建 `adapters/_base/` | 将 SDK 中新基类的运行时辅助代码放在此处(如事件分发辅助函数) |
|
||||
| 2.B | 更新 ComponentDiscovery | 使 `discover_blueprint` 支持扫描 `adapters/` 子目录中的 YAML |
|
||||
| 2.C | 更新 `templates/components.yaml` | 将 `fromDirs` 从 `pkg/platform/sources/` 改为 `pkg/platform/adapters/`(过渡期两个都扫描) |
|
||||
| 2.D | 保留旧 sources/ | 过渡期不删除旧文件,通过 manifest 的 `deprecated: true` 标记 |
|
||||
|
||||
### 3.4 验收标准
|
||||
|
||||
- [ ] 已迁移的适配器在新目录结构下正常启动和收发消息
|
||||
- [ ] 新事件(如 `message.edited`)在支持的平台上正确触发
|
||||
- [ ] 通用 API(如 `edit_message`)在支持的平台上正确执行
|
||||
- [ ] 未迁移的适配器(仍在 `sources/`)继续正常工作
|
||||
- [ ] ComponentDiscovery 同时扫描新旧目录
|
||||
|
||||
---
|
||||
|
||||
## 4. Phase 3:核心系统
|
||||
|
||||
**目标**:实现 EventBus、EventRouter 和事件处理器框架,将事件从适配器分发到不同的处理器。
|
||||
|
||||
**仓库**:`LangBot`(后端)
|
||||
|
||||
### 4.1 任务清单
|
||||
|
||||
| # | 任务 | 文件/模块 | 说明 |
|
||||
|---|------|----------|------|
|
||||
| 3.1 | 实现 EventBus | `pkg/platform/event_bus.py`(新文件) | 事件总线:接收适配器事件,进行日志记录,分发给 EventRouter |
|
||||
| 3.2 | 实现 EventRouter | `pkg/platform/event_router.py`(新文件) | 事件路由引擎:读取 Bot 的 `event_handlers` 配置,匹配事件类型,分发到对应 Handler |
|
||||
| 3.3 | 实现 PipelineHandler | `pkg/platform/handlers/pipeline_handler.py` | 将 `message.received` 事件转为现有 Query,进入 Pipeline 流水线 |
|
||||
| 3.4 | 实现 AgentHandler | `pkg/platform/handlers/agent_handler.py` | 直接调用 RequestRunner 处理事件,不经过 Pipeline 多 Stage 流程 |
|
||||
| 3.5 | 实现 WebhookHandler | `pkg/platform/handlers/webhook_handler.py` | 将事件 POST 到外部 URL,解析响应执行动作(重构现有 WebhookPusher) |
|
||||
| 3.6 | 实现 PluginHandler | `pkg/platform/handlers/plugin_handler.py` | 将事件分发给插件 EventListener(复用现有 plugin_connector 机制) |
|
||||
| 3.7 | Bot 实体扩展 | `pkg/entity/persistence/bot.py` | 新增 `event_handlers` JSON 字段 |
|
||||
| 3.8 | 数据库迁移 | `pkg/persistence/migrations/` | 新增迁移脚本:添加 `event_handlers` 列,将现有 `use_pipeline_uuid` 数据迁移为 `event_handlers` 格式 |
|
||||
| 3.9 | 重构 RuntimeBot | `pkg/platform/botmgr.py` | 将 `initialize()` 中硬编码的 `on_friend_message`/`on_group_message` 回调替换为通过 EventBus 分发所有事件 |
|
||||
| 3.10 | 重构 MessageAggregator | `pkg/pipeline/aggregator.py` | 从 RuntimeBot 解耦,作为 PipelineHandler 的内部机制(只对 `message.received` 事件生效) |
|
||||
| 3.11 | Agent Handler 中 RequestRunner 解耦 | `pkg/provider/runner.py` + handlers | RequestRunner 需要能独立于 Pipeline Stage 运行,为 Agent Handler 提供轻量调用路径 |
|
||||
| 3.12 | HTTP API 扩展 | `pkg/api/http/controller/` | 新增/更新 Bot API 端点以支持 `event_handlers` 的 CRUD |
|
||||
|
||||
### 4.2 数据迁移策略
|
||||
|
||||
现有 Bot 表有 `use_pipeline_uuid` 字段,需要自动迁移为 `event_handlers`:
|
||||
|
||||
该步骤只改写 Bot 的路由表示,仍通过原 UUID 指向原 Pipeline;不得创建独立 Agent,也不得复制 Pipeline 内嵌的 runner 配置。用户需要 Agent 时自行新增并绑定。
|
||||
|
||||
```python
|
||||
# 迁移逻辑伪代码
|
||||
for bot in all_bots:
|
||||
if bot.use_pipeline_uuid:
|
||||
bot.event_handlers = [
|
||||
{
|
||||
"event_type": "message.received",
|
||||
"handler_type": "pipeline",
|
||||
"handler_config": {
|
||||
"pipeline_uuid": bot.use_pipeline_uuid
|
||||
}
|
||||
}
|
||||
]
|
||||
else:
|
||||
bot.event_handlers = []
|
||||
```text
|
||||
adapter event
|
||||
-> EventBus observer broadcast
|
||||
-> EventRouter match event_bindings
|
||||
-> one target: Pipeline | Agent | discard
|
||||
-> Host delivery
|
||||
```
|
||||
|
||||
### 4.3 RuntimeBot 重构要点
|
||||
### 约束
|
||||
|
||||
当前 `RuntimeBot.initialize()` 硬编码注册两个回调:
|
||||
- Plugin EventListener 是 observer,不作为 priority fallback。
|
||||
- Pipeline 只处理消息事件并复用完整 Stage 链。
|
||||
- Agent 使用独立 Agent 配置和 AgentRunner Host orchestrator。
|
||||
- edit/reaction 等事件的 observer 副作用能力按事件和 adapter 能力过滤。
|
||||
- dry-run 与合成派发必须使用同一匹配器,避免 UI 预览与真实路由漂移。
|
||||
|
||||
```python
|
||||
# 现有代码 (botmgr.py)
|
||||
self.adapter.register_listener(FriendMessage, on_friend_message)
|
||||
self.adapter.register_listener(GroupMessage, on_group_message)
|
||||
```
|
||||
### 验收
|
||||
|
||||
重构后改为注册通用事件回调:
|
||||
- 精确、namespace wildcard、全局 wildcard、filters 与 priority 有单元覆盖。
|
||||
- 同一事件最多一个响应目标,但 observer 仍能收到事件。
|
||||
- Pipeline 与 Agent 可以在同一个 Bot 的不同 binding 中同时生效。
|
||||
|
||||
```python
|
||||
# 新代码
|
||||
async def on_event(event: Event, adapter: AbstractPlatformAdapter):
|
||||
await self.event_bus.emit(
|
||||
bot_uuid=self.bot_entity.uuid,
|
||||
event=event,
|
||||
adapter=adapter,
|
||||
)
|
||||
## 6. P3:独立 Agent 与 AgentRunner
|
||||
|
||||
# 注册所有事件类型的统一回调
|
||||
self.adapter.register_listener(Event, on_event)
|
||||
```
|
||||
### 工作项
|
||||
|
||||
EventBus 接收事件后,调用 EventRouter 按配置分发。
|
||||
- `agents` 只保存 Agent;Pipeline 继续使用自己的表和 API。
|
||||
- Agent config 使用 `runner.id` 与 `runner_config[runner_id]`。
|
||||
- registry 只展示已安装、有效的插件 AgentRunner。
|
||||
- Host 构造 run-scoped resources、state、delivery 与 event log/transcript。
|
||||
- SDK/Python `call_tool` 和 scoped MCP bridge 都回到同一个 Host ToolManager。
|
||||
- Box session 由 Host 将 instance/workspace/bot/adapter/target/thread scope 规范化并哈希为固定长度 `lb-box-<sha256>`;同 scope 稳定、不同 scope 隔离、缺少 identity 时 fail closed。
|
||||
|
||||
### 4.4 事件处理器执行流程
|
||||
### 验收
|
||||
|
||||
```
|
||||
EventBus.emit(bot_uuid, event, adapter)
|
||||
│
|
||||
▼
|
||||
EventRouter.route(bot_uuid, event)
|
||||
│ 查询 bot.event_handlers 配置
|
||||
│ 匹配 event_type(精确匹配 > 通配符 *)
|
||||
▼
|
||||
匹配到的 Handler(s)
|
||||
│
|
||||
├── PipelineHandler.handle(event, adapter)
|
||||
│ │ 仅支持 message.received
|
||||
│ │ 构造 Query → MessageAggregator → QueryPool → Pipeline
|
||||
│ └── 沿用现有完整流水线机制
|
||||
│
|
||||
├── AgentHandler.handle(event, adapter)
|
||||
│ │ 根据 handler_config 选择 RequestRunner
|
||||
│ │ 直接调用 runner.run() 处理事件
|
||||
│ └── 将结果通过 adapter API 回复
|
||||
│
|
||||
├── WebhookHandler.handle(event, adapter)
|
||||
│ │ 序列化事件为 JSON
|
||||
│ │ POST 到 handler_config.url
|
||||
│ └── 解析响应,执行动作(回复消息、调用 API 等)
|
||||
│
|
||||
└── PluginHandler.handle(event, adapter)
|
||||
│ 通过 plugin_connector 分发给插件
|
||||
└── 插件 EventListener 处理
|
||||
```
|
||||
- 安装/卸载 Runner 后 metadata 与表单选项同步。
|
||||
- Runner 无法调用未授权 model/tool/knowledge/state。
|
||||
- 两种 Host callback transport 不能覆盖 sandbox session id。
|
||||
- LocalAgent、ACP/ClaudeCode/Codex 与外部服务 Runner 不需要 Host id 特判。
|
||||
|
||||
### 4.5 验收标准
|
||||
## 7. P4:WebUI
|
||||
|
||||
- [ ] `message.received` 事件通过 PipelineHandler 正确进入现有 Pipeline(与旧行为一致)
|
||||
- [ ] 新增事件(如 `group.member_joined`)能通过 PluginHandler 分发给插件
|
||||
- [ ] AgentHandler 能直接调用 RequestRunner(至少 `local-agent`)处理事件并回复
|
||||
- [ ] WebhookHandler 能将事件 POST 到外部 URL
|
||||
- [ ] 数据库迁移正确执行,`use_pipeline_uuid` 数据迁移到 `event_handlers`
|
||||
- [ ] 现有 Bot 在不修改配置的情况下行为不变(自动迁移保证)
|
||||
### 工作项
|
||||
|
||||
---
|
||||
- `/home/agents` 聚合显示 Agent 与 Pipeline,并明确类型。
|
||||
- 创建时选择 Agent 或 Pipeline,编辑时进入各自表单。
|
||||
- Agent 表单读取动态 Runner metadata,保存当前 `runner` / `runner_config` 形状。
|
||||
- Bot 事件编排器编辑 `event_pattern`、target、filters、priority 与 enabled。
|
||||
- 非消息事件过滤 Pipeline;Agent 按声明事件能力过滤。
|
||||
|
||||
## 5. Phase 4:插件 SDK 集成
|
||||
### 验收
|
||||
|
||||
**目标**:将新事件和 API 通过插件 SDK 暴露给插件开发者,同时实现兼容层。
|
||||
- 页面不出现 LocalAgent 专属 banner、变量隐藏或 Box/Pipeline 注入逻辑。
|
||||
- 空 Runner 市场状态给出可安装 AgentRunner 的正常路径。
|
||||
- Pipeline Debug Chat/Monitoring 与 Agent 运行日志分别可用。
|
||||
|
||||
**仓库**:`langbot-plugin-sdk` + `LangBot`
|
||||
## 8. P5:发布门禁
|
||||
|
||||
### 5.1 任务清单
|
||||
### 自动化
|
||||
|
||||
| # | 任务 | 说明 |
|
||||
|---|------|------|
|
||||
| 4.1 | 新增插件事件包装 | 在 `api/entities/events.py` 中为每个通用事件新增插件级事件类(如 `MessageEditedReceived`, `MemberJoinedReceived`) |
|
||||
| 4.2 | 兼容层实现 | `PersonMessageReceived` / `GroupMessageReceived` 由新的 `MessageReceivedEvent` 自动生成,旧事件作为新事件的 alias |
|
||||
| 4.3 | 新 API 暴露 | 在 `LangBotAPIProxy` 中新增方法:`edit_message`, `delete_message`, `get_group_info`, `get_user_info`, `call_platform_api` 等 |
|
||||
| 4.4 | 通信协议扩展 | 在 `entities/io/actions/enums.py` 中新增 action 枚举(如 `EDIT_MESSAGE`, `DELETE_MESSAGE`, `GET_GROUP_INFO`, `CALL_PLATFORM_API`) |
|
||||
| 4.5 | Runtime Handler 扩展 | 在 PluginConnectionHandler / ControlConnectionHandler 中添加新 action 的处理逻辑 |
|
||||
| 4.6 | EventListener 扩展 | 确保 `@handler()` 装饰器支持注册新事件类型 |
|
||||
| 4.7 | QueryBasedAPI 扩展 | 在 `QueryBasedAPIProxy` 中新增事件上下文相关的 API(如 `get_event_source_adapter`) |
|
||||
- LangBot backend unit/integration tests 与 Ruff。
|
||||
- SDK AgentRunner/proxy/MCP bridge tests。
|
||||
- Web lint/build 与关键 Playwright cases。
|
||||
- `skills/bin/lbs validate`、`skills/bin/lbs index --check`。
|
||||
- LocalAgent 与其他官方 Runner plugin package/test gate。
|
||||
|
||||
### 5.2 兼容层详细设计
|
||||
### 真实环境
|
||||
|
||||
```
|
||||
新事件系统 旧事件系统(兼容层)
|
||||
───────────── ─────────────────
|
||||
MessageReceivedEvent ┌→ PersonMessageReceived (chat_type == "private")
|
||||
(chat_type: "private"|"group") ┤
|
||||
└→ GroupMessageReceived (chat_type == "group")
|
||||
```
|
||||
- 至少一个消息事件走 Pipeline。
|
||||
- 至少一个非消息事件走独立 Agent 并执行平台动作。
|
||||
- SDK/Python 和 MCP bridge 各完成一次受权工具调用,并证明二者都进入同一个 `PluginToRuntimeAction.CALL_TOOL` Host handler。
|
||||
- Box 可用/不可用的降级路径可观察且无 Runner 特判。
|
||||
|
||||
**实现方式**:在 RuntimeEventDispatcher 中,当分发 `MessageReceivedEvent` 给插件时,同时生成对应的旧事件类实例。插件可以用新事件类或旧事件类注册 handler,都能收到。
|
||||
## 9. 非目标
|
||||
|
||||
### 5.3 验收标准
|
||||
|
||||
- [ ] 现有插件(使用旧事件和 API)无需修改即可运行
|
||||
- [ ] 新插件可以使用新事件类型(如 `MemberJoinedReceived`)注册 handler
|
||||
- [ ] 新 API(如 `edit_message`)可通过 `self.edit_message()` 或 `event_context.edit_message()` 调用
|
||||
- [ ] 透传 API `call_platform_api` 可正常调用适配器特有功能
|
||||
- [ ] 所有新 action 的通信协议正确工作(stdio / WebSocket)
|
||||
|
||||
---
|
||||
|
||||
## 6. Phase 5:WebUI 编排面板
|
||||
|
||||
**目标**:在 WebUI 的 Bot 管理页面实现事件处理器的可视化编排。
|
||||
|
||||
**仓库**:`LangBot`(前端 `web/`)
|
||||
|
||||
### 6.1 任务清单
|
||||
|
||||
| # | 任务 | 说明 |
|
||||
|---|------|------|
|
||||
| 5.1 | Bot 编辑页面扩展 | 在 Bot 编辑页面新增「事件处理」面板 |
|
||||
| 5.2 | 事件处理器列表组件 | 可视化展示当前 Bot 的 `event_handlers` 列表,支持增删改排序 |
|
||||
| 5.3 | 事件类型选择器 | 下拉选择事件类型(命名空间分组展示),支持通配符 `*` |
|
||||
| 5.4 | Handler 类型选择与配置 | 选择 handler 类型后展示对应的配置表单(Pipeline 选择器、Runner 选择器、Webhook URL 等) |
|
||||
| 5.5 | Pipeline Handler 配置 | 复用现有的 Pipeline 选择 UI(从现有 `use_pipeline_uuid` 选择器迁移) |
|
||||
| 5.6 | Agent Handler 配置 | Runner 选择器(local-agent / dify / n8n / coze 等)+ Runner 参数配置表单 |
|
||||
| 5.7 | Webhook Handler 配置 | URL 输入、认证方式选择、Header 配置 |
|
||||
| 5.8 | Plugin Handler 配置 | 通常无需额外配置,分发给所有匹配的插件 EventListener |
|
||||
| 5.9 | HTTP API 对接 | 前端调用后端 API 保存/读取 `event_handlers` 配置 |
|
||||
| 5.10 | 迁移提示 | 对于从旧版本升级的用户,如果检测到 `use_pipeline_uuid` 已自动迁移,展示提示说明 |
|
||||
|
||||
### 6.2 UI 交互设计概要
|
||||
|
||||
```
|
||||
┌─ Bot 编辑页面 ─────────────────────────────────────┐
|
||||
│ │
|
||||
│ 基本信息 │ 适配器配置 │ ★ 事件处理 │ │
|
||||
│ │
|
||||
│ ┌─ 事件处理器列表 ────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ ① message.received → Pipeline: "主流水线" │ │
|
||||
│ │ [编辑] [删除] │ │
|
||||
│ │ │ │
|
||||
│ │ ② group.member_joined → Agent: local-agent │ │
|
||||
│ │ [编辑] [删除] │ │
|
||||
│ │ │ │
|
||||
│ │ ③ * (默认) → Plugin │ │
|
||||
│ │ [编辑] [删除] │ │
|
||||
│ │ │ │
|
||||
│ │ [+ 添加事件处理器] │ │
|
||||
│ │ │ │
|
||||
│ └──────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [保存] [取消] │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 6.3 验收标准
|
||||
|
||||
- [ ] 用户可以在 WebUI 上为 Bot 添加/编辑/删除事件处理器
|
||||
- [ ] 四种 Handler 类型均有对应的配置表单
|
||||
- [ ] 配置保存后正确写入数据库 `event_handlers` 字段
|
||||
- [ ] 旧版本升级后,自动迁移的配置在 UI 上正确展示
|
||||
- [ ] Pipeline Handler 的行为与旧的 `use_pipeline_uuid` 完全一致
|
||||
|
||||
---
|
||||
|
||||
## 7. Phase 6:文档与示例
|
||||
|
||||
**目标**:更新所有面向开发者的文档和示例。
|
||||
|
||||
**仓库**:`langbot-wiki`, `langbot-plugin-demo`
|
||||
|
||||
### 7.1 任务清单
|
||||
|
||||
| # | 任务 | 仓库 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 6.1 | EBA 架构概览文档 | langbot-wiki | 面向用户的新架构说明 |
|
||||
| 6.2 | 适配器开发指南更新 | langbot-wiki | 如何开发一个新的适配器(新目录结构、新基类、事件转换等) |
|
||||
| 6.3 | 插件开发指南更新 | langbot-wiki | 新事件类型、新 API 的使用说明 |
|
||||
| 6.4 | 插件迁移指南 | langbot-wiki | 现有插件如何迁移到新事件/API(如果需要使用新能力) |
|
||||
| 6.5 | 事件处理器配置指南 | langbot-wiki | WebUI 上如何配置事件处理器 |
|
||||
| 6.6 | 示例插件更新 | langbot-plugin-demo | HelloPlugin 增加新事件监听示例、新 API 调用示例 |
|
||||
| 6.7 | 新示例插件 | langbot-plugin-demo | 新建一个示例展示非消息事件处理(如入群欢迎) |
|
||||
|
||||
---
|
||||
|
||||
## 8. 风险评估与缓解
|
||||
|
||||
### 8.1 技术风险
|
||||
|
||||
| 风险 | 影响 | 概率 | 缓解措施 |
|
||||
|------|------|------|----------|
|
||||
| 适配器迁移中断现有功能 | 高 | 中 | 新旧目录并存,ComponentDiscovery 同时扫描两个目录,逐个适配器迁移验证 |
|
||||
| 事件模型不兼容导致插件崩溃 | 高 | 低 | 兼容层保证旧事件类型继续工作,新增类不修改旧类 |
|
||||
| 数据库迁移失败 | 高 | 低 | 迁移脚本做前置校验,`use_pipeline_uuid` 在过渡期保留不删除 |
|
||||
| RequestRunner 解耦破坏 Pipeline | 高 | 中 | Agent Handler 调用 Runner 的路径独立于 Pipeline,不修改现有 Pipeline Stage 中的 Runner 调用逻辑 |
|
||||
| 性能回退(EventBus 额外开销) | 中 | 低 | EventBus 在进程内同步分发,无额外序列化/网络开销 |
|
||||
| 各平台事件差异大难以统一 | 中 | 中 | 通用事件只抽象最大公约数字段,差异部分保留在 `source_platform_object`;不支持的事件走 `PlatformSpecificEvent` |
|
||||
|
||||
### 8.2 兼容性风险
|
||||
|
||||
| 风险 | 缓解措施 |
|
||||
|------|----------|
|
||||
| 现有插件使用旧事件类 | 兼容层自动将新事件转为旧事件分发,两种事件类都能注册 handler |
|
||||
| 现有插件调用 `reply()` / `send_message()` | 这两个 API 保持不变,只是底层实现可能微调 |
|
||||
| 第三方基于 `AbstractMessagePlatformAdapter` 开发的适配器 | 旧基类保留,新基类继承旧基类,第三方适配器无需立即迁移 |
|
||||
| 用户自定义 Pipeline 配置 | Pipeline 机制完整保留,PipelineHandler 只是入口变了(从 RuntimeBot 硬编码变为 EventRouter 配置) |
|
||||
|
||||
### 8.3 回滚策略
|
||||
|
||||
每个 Phase 独立可回滚:
|
||||
|
||||
- **Phase 1**(SDK 新增类):删除新增文件,回退 SDK 版本号
|
||||
- **Phase 2**(适配器目录):恢复 `components.yaml` 的 `fromDirs` 指向旧目录,旧 sources/ 未删除
|
||||
- **Phase 3**(核心系统):回退数据库迁移,恢复 RuntimeBot 旧的硬编码回调
|
||||
- **Phase 4**(插件集成):回退 SDK 版本,插件使用旧版 SDK
|
||||
- **Phase 5**(WebUI):前端回退,Bot 编辑页面隐藏事件处理面板
|
||||
|
||||
---
|
||||
|
||||
## 9. 里程碑与时间线建议
|
||||
|
||||
| 里程碑 | 阶段 | 预期产出 |
|
||||
|--------|------|----------|
|
||||
| M1 | Phase 1 完成 | SDK 新版本发布,包含新事件/实体/基类定义 |
|
||||
| M2 | Phase 2 首批适配器(Telegram + Discord) | 两个参考实现,验证目录结构和事件/API 体系 |
|
||||
| M3 | Phase 3 核心系统 | EventBus + EventRouter + 四种 Handler 可用 |
|
||||
| M4 | Phase 2 剩余适配器 | 所有活跃适配器迁移完成 |
|
||||
| M5 | Phase 4 插件集成 | 新 SDK 发布,插件可使用新事件和 API |
|
||||
| M6 | Phase 5 WebUI | 事件处理器编排面板上线 |
|
||||
| M7 | Phase 6 文档 | 开发者文档和示例更新完毕 |
|
||||
|
||||
建议 M1-M3 作为第一个大版本发布(如 v5.0),M4-M7 在后续小版本迭代中完成。
|
||||
|
||||
---
|
||||
|
||||
## 10. 开发指引
|
||||
|
||||
### 10.1 分支策略
|
||||
|
||||
建议在主仓库创建 `feature/eba` 长期特性分支,各 Phase 在子分支上开发后合入特性分支:
|
||||
|
||||
```
|
||||
main
|
||||
└── feature/eba
|
||||
├── feature/eba-sdk-entities (Phase 1)
|
||||
├── feature/eba-adapter-telegram (Phase 2)
|
||||
├── feature/eba-adapter-discord (Phase 2)
|
||||
├── feature/eba-core-system (Phase 3)
|
||||
├── feature/eba-plugin-sdk (Phase 4)
|
||||
└── feature/eba-webui (Phase 5)
|
||||
```
|
||||
|
||||
### 10.2 测试策略
|
||||
|
||||
| 层次 | 测试内容 | 工具 |
|
||||
|------|----------|------|
|
||||
| 单元测试 | 事件序列化/反序列化、实体构造、API 调用 mock | pytest |
|
||||
| 集成测试 | EventBus → EventRouter → Handler 全链路 | pytest + asyncio |
|
||||
| 适配器测试 | 各适配器的事件转换、消息转换、API 调用 | pytest + mock SDK |
|
||||
| 端到端测试 | 从模拟平台事件到完整处理流程 | staging 环境 |
|
||||
| 插件兼容性测试 | 旧插件在新系统下的行为 | langbot-plugin-demo |
|
||||
|
||||
### 10.3 代码审查关注点
|
||||
|
||||
- 新增代码是否影响现有行为
|
||||
- 兼容层是否正确映射所有旧事件/API 场景
|
||||
- 数据库迁移是否可逆
|
||||
- 新 API 的错误处理(`NotSupportedError`)是否一致
|
||||
- 事件模型的序列化在 stdio/WebSocket 通信中是否正确
|
||||
- 不把 Pipeline 改名或包装成 Agent。
|
||||
- 不自动把 Pipeline 内 runner 配置迁移成 Agent。
|
||||
- 不为 3.x 保留数据库迁移、旧模板或配置 fallback。
|
||||
- 不要求所有 Runner 经 MCP;本地 Python Runner 可以直接使用 SDK。
|
||||
- 不允许 Runner 自定义 Box session scope。
|
||||
- 不在首版实现多 Agent 串并联;多步骤编排留给后续 workflow。
|
||||
|
||||
Reference in New Issue
Block a user