# 分阶段迁移计划

> **2026-06 方向修订**：Phase 3 的「四种 Handler 框架」与 Phase 5 的编排面板形态，按 [07-agent-orchestration.md](./07-agent-orchestration.md) 调整为「事件 → Agent」统一编排（EventRouter + Agent 实体 + 绑定模型 + SDK Agent 组件契约）。阶段划分、依赖关系与验收标准仍然适用，按 Agent 模型重新解读即可；发布节奏见 07 §5「发布火车」。

## 1. 概述

EBA 架构涉及 langbot-plugin-sdk、LangBot 后端、LangBot 前端、文档和示例插件等多个仓库的改动。为降低风险、保证系统稳定性，采用分阶段渐进式迁移策略。

### 1.1 阶段总览

| 阶段 | 名称 | 范围 | 依赖 |
|------|------|------|------|
| 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 |

### 1.2 核心原则

- **每个阶段结束后系统可运行**：任何阶段完成后，现有功能不受影响
- **向后兼容贯穿全程**：旧接口在整个迁移期间保持可用
- **先 SDK 后实现**：先定义好接口和模型，再做具体实现
- **先核心适配器后边缘**：优先迁移用户量大的适配器

---

## 2. Phase 1：SDK 实体层

**目标**：在 langbot-plugin-sdk 中定义新的事件体系、通用实体、API 接口和适配器基类。

**仓库**：`langbot-plugin-sdk`

### 2.1 任务清单

| # | 任务 | 文件/模块 | 说明 |
|---|------|----------|------|
| 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` 字段（命名空间字符串）区分

### 2.3 验收标准

- [ ] 所有新增类可正常 import 且通过类型检查
- [ ] 现有 `FriendMessage`, `GroupMessage`, `AbstractMessagePlatformAdapter` 等类行为不变
- [ ] 新增单元测试覆盖事件序列化/反序列化、实体构造
- [ ] SDK 版本号 minor bump（如 `0.x.0` → `0.x+1.0`）

---

## 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`：

```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 = []
```

### 4.3 RuntimeBot 重构要点

当前 `RuntimeBot.initialize()` 硬编码注册两个回调：

```python
# 现有代码 (botmgr.py)
self.adapter.register_listener(FriendMessage, on_friend_message)
self.adapter.register_listener(GroupMessage, on_group_message)
```

重构后改为注册通用事件回调：

```python
# 新代码
async def on_event(event: Event, adapter: AbstractPlatformAdapter):
    await self.event_bus.emit(
        bot_uuid=self.bot_entity.uuid,
        event=event,
        adapter=adapter,
    )

# 注册所有事件类型的统一回调
self.adapter.register_listener(Event, on_event)
```

EventBus 接收事件后，调用 EventRouter 按配置分发。

### 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 处理
```

### 4.5 验收标准

- [ ] `message.received` 事件通过 PipelineHandler 正确进入现有 Pipeline（与旧行为一致）
- [ ] 新增事件（如 `group.member_joined`）能通过 PluginHandler 分发给插件
- [ ] AgentHandler 能直接调用 RequestRunner（至少 `local-agent`）处理事件并回复
- [ ] WebhookHandler 能将事件 POST 到外部 URL
- [ ] 数据库迁移正确执行，`use_pipeline_uuid` 数据迁移到 `event_handlers`
- [ ] 现有 Bot 在不修改配置的情况下行为不变（自动迁移保证）

---

## 5. Phase 4：插件 SDK 集成

**目标**：将新事件和 API 通过插件 SDK 暴露给插件开发者，同时实现兼容层。

**仓库**：`langbot-plugin-sdk` + `LangBot`

### 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`） |

### 5.2 兼容层详细设计

```
新事件系统                         旧事件系统（兼容层）
─────────────                    ─────────────────
MessageReceivedEvent             ┌→ PersonMessageReceived (chat_type == "private")
  (chat_type: "private"|"group") ┤
                                 └→ GroupMessageReceived  (chat_type == "group")
```

**实现方式**：在 RuntimeEventDispatcher 中，当分发 `MessageReceivedEvent` 给插件时，同时生成对应的旧事件类实例。插件可以用新事件类或旧事件类注册 handler，都能收到。

### 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 通信中是否正确
