.aionui/FEATURE_CHANNELS.md
本文档记录个人助手功能的完整开发方案,包括架构设计、插件系统、交互设计等。
触发: 用户通过手机 IM 工具(如 Telegram)发送消息
过程: 平台机器人接收消息 → 转发给 Aion Agent → LLM 处理
结果: 处理完成后通过相同平台推送结果给用户
┌─────────────────────────────────────────────────────────────┐
│ ChannelManager (单例) │
│ (统一管理所有组件) │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │PluginManager│ │SessionManager│ │PairingService│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────────────────────┐ │
│ │ActionExecutor│ │ChannelMessageService │ │
│ └─────────────┘ └─────────────────────────────┘ │
└────────────────────┼────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Layer 1: Plugin │
│ (平台适配层) │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ │
│ │ Telegram │ │ Lark │ ... (Slack, Discord 待实现) │
│ │ Plugin │ │ Plugin │ │
│ └────┬─────┘ └────┬─────┘ │
│ └────────────┴────────────┘ │
│ │ │
│ 职责: 接收平台消息/回调 → 转换为统一格式 → 发送响应 │
│ 不关心: Agent 类型、业务逻辑 │
└────────────────────┼────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Layer 2: Gateway │
│ (业务逻辑层) │
├─────────────────────────────────────────────────────────────┤
│ ActionExecutor: 系统 Action 处理、对话路由 │
│ SessionManager: 会话管理、用户授权 │
│ PairingService: 配对码生成和验证 │
│ ChannelMessageService: 消息流式处理 │
│ │
│ 职责: 系统 Action 处理、对话路由、会话管理、权限控制 │
│ 不关心: 平台细节、Agent 实现细节 │
└────────────────────┼────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Layer 3: Agent │
│ (AI 处理层) │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Gemini │ │ ACP │ │ Codex │ │
│ │ Agent │ │ Agent │ │ Agent │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 职责: 与 AI 服务通信、管理对话上下文、返回统一响应 │
│ 不关心: 消息来源平台、系统级操作 │
└─────────────────────────────────────────────────────────────┘
入站流程:
平台消息 → Plugin(转换) → ActionExecutor(路由) → Agent(处理)
详细流程:
1. Plugin 接收平台消息 → toUnifiedIncomingMessage()
2. PluginManager 调用 messageHandler → ActionExecutor.handleMessage()
3. ActionExecutor 根据 Action 类型路由:
- Platform Action → Plugin 自行处理
- System Action → SystemActions 处理
- Chat Action → ChannelMessageService → Agent
出站流程:
Agent 响应 → ChannelEventBus → ChannelMessageService → ActionExecutor → Plugin(转换) → 平台发送
详细流程:
1. Agent Worker 发送消息 → ChannelEventBus.emitAgentMessage()
2. ChannelMessageService 监听事件 → handleAgentMessage()
3. transformMessage + composeMessage → StreamCallback
4. ActionExecutor 调用 context.sendMessage/editMessage()
5. Plugin 转换消息格式 → sendMessage/editMessage()
| 插件负责 | 插件不负责 |
|---|---|
| 连接平台 API | Agent 调度和执行 |
| 接收消息 → 转换为统一格式 | 会话管理和持久化 |
| 统一格式 → 转换为平台消息 | 用户认证和权限控制 |
| 处理平台特有命令 | 消息路由决策 |
| 流式消息更新(编辑已发送消息) |
created → initializing → ready → starting → running → stopping → stopped
↓ ↓ ↓
error ←←←←←←←←←←←←←←←←←←←←←←←←←←←←
| 状态 | 说明 |
|---|---|
created | 插件实例已创建 |
initializing | 正在验证配置和初始化 |
ready | 初始化完成,等待启动 |
starting | 正在连接平台 |
running | 正常运行中 |
stopping | 正在断开连接 |
stopped | 已停止 |
error | 发生错误 |
| 接口方法 | 方向 | 说明 |
|---|---|---|
initialize(config) | PluginManager → Plugin | 初始化插件配置 |
start() | PluginManager → Plugin | 启动平台连接 |
stop() | PluginManager → Plugin | 停止平台连接 |
sendMessage(...) | ActionExecutor → Plugin | 发送消息到平台 |
editMessage(...) | ActionExecutor → Plugin | 编辑已发送消息(流式更新) |
getStatus() | PluginManager → Plugin | 获取插件状态 |
getActiveUserCount() | PluginManager → Plugin | 获取活跃用户数 |
getBotInfo() | PluginManager → Plugin | 获取 Bot 信息 |
onInitialize() | 子类实现 | 平台特定的初始化逻辑 |
onStart() | 子类实现 | 平台特定的启动逻辑 |
onStop() | 子类实现 | 平台特定的停止逻辑 |
入站消息(平台 → 系统) - IUnifiedIncomingMessage
| 字段 | 说明 |
|---|---|
id | 系统生成的唯一 ID |
platform | 来源平台(telegram/lark/slack/discord) |
chatId | 聊天 ID |
user | 用户信息(id、username、displayName) |
content | 消息内容(type、text、attachments) |
timestamp | 时间戳 |
replyToMessageId | 回复的消息 ID(可选) |
action | Action 信息(按钮回调时) |
raw | 平台原始消息(可选) |
出站消息(系统 → 平台) - IUnifiedOutgoingMessage
| 字段 | 说明 |
|---|---|
type | 消息类型(text/image/file/buttons) |
text | 文本内容 |
parseMode | 解析模式(HTML/Markdown/MarkdownV2) |
buttons | Inline 按钮组(可选) |
keyboard | Reply Keyboard(可选) |
replyMarkup | 平台特定 Markup(可选,如 Lark Card) |
replyToMessageId | 回复的消息 ID(可选) |
imageUrl | 图片 URL(image 类型) |
fileUrl | 文件 URL(file 类型) |
fileName | 文件名(file 类型) |
silent | 静默发送(可选) |
src/channels/plugins/[platform]/ 目录[Platform]Plugin 继承 BasePlugin[Platform]Adapter 处理消息转换(toUnifiedIncomingMessage, to[Platform]SendParams)ChannelManager 构造函数中注册插件:registerPlugin('platform', PlatformPlugin)types.ts 中添加平台类型到 PluginType| 项目 | 选择 | 说明 |
|---|---|---|
| Bot 库 | grammY | Clawdbot 使用,API 优雅 |
| 运行模式 | Polling(长轮询) | 自动重连机制 |
| 项目 | 选择 | 说明 |
|---|---|---|
| Bot 库 | grammY | Clawdbot 使用,API 优雅 |
| 运行模式 | Polling(开发)/ Webhook(生产) | 可配置 |
┌─────────────────────────────────────────────────────────────┐
│ Step 1: 创建 Bot │
│ 用户在 Telegram 中 @BotFather → /newbot → 获取 Token │
├─────────────────────────────────────────────────────────────┤
│ Step 2: 配置 Token │
│ AionUi 设置页面 → 粘贴 Token → 验证 → 保存 │
├─────────────────────────────────────────────────────────────┤
│ Step 3: 启动 Bot │
│ 开启开关 → Bot 开始监听 │
├─────────────────────────────────────────────────────────────┤
│ Step 4: 用户配对(见下方安全机制) │
└─────────────────────────────────────────────────────────────┘
| 配置项 | 类型 | 说明 |
|---|---|---|
| Bot Token | string | 从 @BotFather 获取 |
| 运行模式 | polling / webhook | Polling 适合开发 |
| Webhook URL | string | 仅 webhook 模式需要 |
| 配对模式 | boolean | 是否需要配对码授权 |
| 速率限制 | number | 每分钟最大消息数 |
| 群组 @提及 | boolean | 群组中是否需要 @bot 才响应 |
| 默认 Agent | gemini | MVP 阶段固定 Gemini |
核心原则: 批准操作在用户本地设备完成,而非在 Telegram 中完成
┌─────────────────────────────────────────────────────────────┐
│ ① 用户在 Telegram 中发起 │
│ 用户 → @YourBot: /start 或任意消息 │
├─────────────────────────────────────────────────────────────┤
│ ② Bot 返回配对请求 │
│ Bot → 用户: │
│ "👋 欢迎使用 Aion 助手! │
│ 您的配对码: ABC123 │
│ 请在 AionUi 中批准此配对: │
│ 设置 → Telegram → 待批准请求 → [批准]" │
├─────────────────────────────────────────────────────────────┤
│ ③ AionUi 显示待批准请求 │
│ 设置页面展示: 用户名、配对码、请求时间、[批准]/[拒绝] │
├─────────────────────────────────────────────────────────────┤
│ ④ 用户在 AionUi 点击 [批准] │
├─────────────────────────────────────────────────────────────┤
│ ⑤ Bot 通知配对成功 │
│ Bot → 用户: "✅ 配对成功!现在可以开始对话了" │
└─────────────────────────────────────────────────────────────┘
安全措施
| 机制 | 说明 |
|---|---|
| 配对码认证 | 6位随机码,10分钟有效 |
| 本地批准 | 必须在 AionUi 中批准,非 Telegram 中 |
| 用户白名单 | 仅授权用户可使用 |
| 速率限制 | 防止滥用 |
| Token 加密存储 | 使用 bcrypt 加密 |
入站转换(Telegram → 统一格式)
| Telegram 消息类型 | 统一消息 content.type |
|---|---|
message:text | text 或 command(以 / 开头) |
message:photo | image |
message:document | file |
message:voice | audio |
出站转换(统一格式 → Telegram)
| 统一消息 type | Telegram API |
|---|---|
text | sendMessage |
image | sendPhoto |
file | sendDocument |
buttons | sendMessage + inline_keyboard |
特殊处理
| 场景 | 处理方式 |
|---|---|
| 流式响应 | 使用 editMessageText 更新消息,添加 ▌ 光标 |
| Markdown | 转义特殊字符,使用 parse_mode: Markdown |
| @提及移除 | 清理消息中的 @bot_username |
| 群组过滤 | 检查是否包含 @提及(可配置) |
| 项目 | 选择 | 说明 |
|---|---|---|
| SDK | @larksuiteoapi/node-sdk | 官方 SDK |
| 运行模式 | WebSocket 长连接 | 无需公网 URL |
| 域 | Feishu(可配置为 Lark 国际版) | 默认使用飞书域 |
┌─────────────────────────────────────────────────────────────┐
│ Step 1: 创建应用 │
│ 在飞书开放平台创建企业自建应用 → 获取 App ID 和 App Secret │
├─────────────────────────────────────────────────────────────┤
│ Step 2: 配置权限 │
│ 应用权限管理 → 开通"获取与发送单聊、群组消息"权限 │
├─────────────────────────────────────────────────────────────┤
│ Step 3: 配置事件订阅 │
│ 事件订阅 → 订阅"接收消息"事件 → 配置加密密钥(可选) │
├─────────────────────────────────────────────────────────────┤
│ Step 4: 配置凭证 │
│ AionUi 设置页面 → 粘贴 App ID、App Secret → 验证 → 保存 │
├─────────────────────────────────────────────────────────────┤
│ Step 5: 启动 Bot │
│ 开启开关 → Bot 通过 WebSocket 连接开始监听 │
├─────────────────────────────────────────────────────────────┤
│ Step 6: 用户配对(见下方安全机制) │
└─────────────────────────────────────────────────────────────┘
| 配置项 | 类型 | 说明 |
|---|---|---|
| App ID | string | 从飞书开放平台获取 |
| App Secret | string | 从飞书开放平台获取 |
| Encrypt Key | string | 事件加密密钥(可选) |
| Verification Token | string | 事件验证 Token(可选) |
| 配对模式 | boolean | 是否需要配对码授权 |
| 速率限制 | number | 每分钟最大消息数 |
| 默认 Agent | gemini | MVP 阶段固定 Gemini |
与 Telegram 相同,采用本地批准模式。配对码通过 Lark 消息发送给用户,用户在 AionUi 中批准。
入站转换(Lark → 统一格式)
| Lark 消息类型 | 统一消息 content.type |
|---|---|
message:text | text 或 command(以 / 开头) |
message:image | photo |
message:file | document |
message:audio | audio |
| Card Action | action(通过 extractCardAction) |
出站转换(统一格式 → Lark)
| 统一消息 type | Lark API |
|---|---|
text | im.message.create |
buttons | im.message.create + Card |
| Interactive Card | 使用 Lark Card 格式 |
特殊处理
| 场景 | 处理方式 |
|---|---|
| 流式响应 | 使用 im.message.update 更新消息 |
| HTML 转 Markdown | convertHtmlToLarkMarkdown() 转换 HTML 为 Lark Markdown |
| Card 交互 | 使用 Lark Card 格式,支持按钮、确认等 |
| 事件去重 | 5 分钟事件缓存,防止重复处理 |
按钮优先,命令保留:普通用户通过按钮操作,高级用户可使用命令
| 类型 | 说明 | 适用场景 |
|---|---|---|
| Inline Keyboard | 消息下方的按钮 | 操作确认、选项选择 |
| Reply Keyboard | 替换输入法键盘 | 常用操作快捷入口 |
| Menu Button | 聊天输入框左侧 | 固定功能入口 |
场景 1: 首次使用/配对
Bot 消息:
┌─────────────────────────────────────────┐
│ 👋 欢迎使用 Aion 助手! │
│ │
│ 🔑 配对码: ABC123 │
│ 请在 AionUi 设置中批准此配对 │
│ │
│ [📖 使用指南] [❓ 获取帮助] │
└─────────────────────────────────────────┘
场景 2: 配对成功后(Reply Keyboard 常驻)
┌─────────────────────────────────────────┐
│ ... 对话内容 ... │
├─────────────────────────────────────────┤
│ Reply Keyboard (常驻快捷操作) │
│ [🆕 新对话] [📊 状态] [❓ 帮助] │
├─────────────────────────────────────────┤
│ [输入消息...] [发送] │
└─────────────────────────────────────────┘
场景 3: AI 回复带操作按钮
Bot 消息:
┌─────────────────────────────────────────┐
│ 这是一个快速排序的实现: │
│ │
│ ```python │
│ def quicksort(arr): │
│ ... │
│ ``` │
│ │
│ [📋 复制] [🔄 重新生成] [💬 继续] │
└─────────────────────────────────────────┘
场景 4: 设置页面(卡片式选择)
Bot 消息:
┌─────────────────────────────────────────┐
│ ⚙️ 设置 │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ 🤖 AI 模型 │ │
│ │ 当前: Gemini 1.5 Pro │ │
│ └─────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ 💬 对话风格 │ │
│ │ 当前: 专业 │ │
│ └─────────────────────────────────────┘ │
│ │
│ [← 返回] │
└─────────────────────────────────────────┘
| 命令(隐藏保留) | 按钮(用户可见) |
|---|---|
/start | 自动触发 |
/new | 🆕 新对话 |
/status | 📊 状态 |
/help | ❓ 帮助 |
命令和按钮回调采用统一处理,避免重复逻辑,便于多平台扩展
| 类型 | 说明 | 处理方 |
|---|---|---|
| 平台 Action | 平台特有操作(认证、配对等) | Plugin 内部处理 |
| 系统 Action | 平台无关的系统级操作 | Gateway ActionHandler |
| 对话 Action | 需要 Agent 处理的消息 | AgentRouter → Agent |
用户输入
│
├─→ 平台 Action → Plugin 自行处理(不进入 Gateway)
│ 例: Telegram 配对、Slack OAuth、Discord 邀请
│
├─→ 系统 Action → Gateway ActionHandler → 统一处理
│ 例: 会话管理、设置、帮助
│
└─→ 对话 Action → AgentRouter → Gemini/ACP/Codex
| 分类 | Action | 说明 |
|---|---|---|
| 会话管理 | session.new | 创建新会话 |
session.status | 查看当前状态 | |
session.list | 会话列表(扩展) | |
session.switch | 切换会话(扩展) | |
| 设置操作 | settings.show | 显示设置菜单 |
settings.model.list | 显示模型列表 | |
settings.model.select | 选择模型 | |
settings.agent.select | 切换 Agent(扩展) | |
| 帮助信息 | help.show | 显示帮助 |
| 导航 | nav.back | 返回上一级 |
nav.cancel | 取消当前操作 |
| 平台 | Action | 说明 |
|---|---|---|
| Telegram | pairing.show | 显示配对码 |
pairing.refresh | 刷新配对码 | |
| Slack | oauth.start | 发起 OAuth 授权 |
oauth.callback | OAuth 回调处理 | |
| Discord | invite.generate | 生成邀请链接 |
注意: 平台 Action 由各 Plugin 内部处理,不经过 Gateway ActionHandler
| 分类 | Action | 说明 | 路由到 |
|---|---|---|---|
| 发送消息 | chat.send | 用户发送新消息 | 当前会话 Agent |
| 消息操作 | chat.regenerate | 重新生成回答 | 当前会话 Agent |
chat.continue | 继续生成 | 当前会话 Agent | |
chat.stop | 停止生成 | 当前会话 Agent |
UnifiedAction {
action: string // Action 类型
params?: object // 可选参数
context: {
platform: string // 来源平台
userId: string // 用户 ID
chatId: string // 聊天 ID
messageId?: string // 触发消息 ID
sessionId?: string // 当前会话 ID
}
}
格式: action:param1=value1,param2=value2
示例:
• "session.new"
• "settings.model.select:id=gemini-pro"
• "chat.regenerate:msg=abc123"
ActionResponse {
text?: string // 文本内容
parseMode?: 'plain' | 'markdown' // 解析模式
buttons?: ActionButton[][] // Inline 按钮
keyboard?: ActionButton[][] // Reply Keyboard
behavior: 'send' | 'edit' | 'answer' // 响应行为
toast?: string // Toast 提示
}
Session {
id: string // 会话 ID
platform: string // 来源平台
userId: string // 用户 ID
chatId: string // 聊天 ID
// Agent 配置
agentType: string // gemini / acp / codex
agentConfig: {
modelId?: string // 模型 ID
}
// 会话状态
status: string // active / idle / error
context: object // Agent 会话上下文
// 元数据
createdAt: number
lastActiveAt: number
}
| 项目 | MVP 实现 |
|---|---|
| 会话模式 | 单活跃会话 |
| 新建会话 | 点击 🆕 按钮清空上下文 |
| 会话存储 | 独立于 AionUi GUI 会话 |
| Agent | 固定 Gemini |
| Model | 使用 AionUi 默认配置 |
| 项目 | 扩展内容 |
|---|---|
| 多会话 | 支持 session.list / session.switch |
| Agent 切换 | 支持 settings.agent.select |
| Model 切换 | 支持动态选择模型 |
| 会话同步 | Telegram 会话与 AionUi 会话关联 |
┌─────────────────────────────────────────────────────────────────┐
│ Agent Worker (Gemini/ACP/Codex) │
│ (Agent Worker 进程) │
├─────────────────────────────────────────────────────────────────┤
│ 发送消息事件到 IPC Bridge │
└───────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ChannelEventBus │
│ (全局事件总线 - 单例) │
├─────────────────────────────────────────────────────────────────┤
│ emitAgentMessage(conversationId, data) │
│ onAgentMessage(handler) → () => void (cleanup) │
│ │
│ 事件类型: 'channel.agent.message' │
│ 数据结构: IAgentMessageEvent { ...IResponseMessage, conv_id } │
└───────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ChannelMessageService │
│ (消息服务 - 单例) │
├─────────────────────────────────────────────────────────────────┤
│ initialize() { │
│ // 服务初始化时注册全局事件监听 │
│ channelEventBus.onAgentMessage(this.handleAgentMessage); │
│ } │
│ │
│ handleAgentMessage(event) { │
│ // 处理特殊事件: start, finish, error │
│ // 使用 transformMessage + composeMessage 合并消息 │
│ // 回调通知: callback(TMessage, isInsert) │
│ } │
│ │
│ sendMessage(sessionId, conversationId, text, callback) { │
│ // 仅发送消息,不处理监听 │
│ // 通过 WorkerManage 调用 Agent Task │
│ } │
│ │
│ 内部状态: │
│ activeStreams: Map<conversationId, IStreamState> │
│ messageListMap: Map<conversationId, TMessage[]> │
└───────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ActionExecutor │
│ (业务执行器) │
├─────────────────────────────────────────────────────────────────┤
│ handleChatMessage(context, text) { │
│ messageService.sendMessage( │
│ sessionId, conversationId, text, │
│ (message: TMessage, isInsert: boolean) => { │
│ const outgoing = convertTMessageToOutgoing(message, platform); │
│ if (isInsert) context.sendMessage(outgoing); │
│ else context.editMessage(msgId, outgoing); │
│ } │
│ ); │
│ } │
│ │
│ convertTMessageToOutgoing(message, platform) { │
│ // TMessage → IUnifiedOutgoingMessage │
│ // 根据平台格式化文本(HTML/Markdown) │
│ // text → 显示内容 │
│ // tips → 带图标提示 │
│ // tool_group → 工具状态列表 │
│ } │
└───────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Plugin (Telegram/Lark) │
│ (平台插件) │
├─────────────────────────────────────────────────────────────────┤
│ sendMessage(chatId, message: IUnifiedOutgoingMessage) │
│ editMessage(chatId, messageId, message: IUnifiedOutgoingMessage)│
└─────────────────────────────────────────────────────────────────┘
| 事件类型 | 来源 | 处理方式 |
|---|---|---|
start | Agent 开始响应 | 重置消息列表 |
content | 流式文本块 | transformMessage → composeMessage → callback |
tool_group | 工具调用状态 | 合并到现有 tool_group 或新增 |
finish/finished | 响应完成 | resolve promise,清理状态 |
error | 发生错误 | reject promise,清理状态 |
thought | 思考过程 | 忽略(transformMessage 返回 undefined) |
| 消息类型 | 合并规则 |
|---|---|
text | 同 msg_id 累加内容,不同 msg_id 新增 |
tool_group | 按 callId 合并工具状态更新 |
tool_call | 按 callId 合并 |
tips | 直接新增 |
type StreamCallback = (chunk: TMessage, isInsert: boolean) => void;
// isInsert = true: 新消息,调用 sendMessage 发送新消息
// isInsert = false: 更新消息,调用 editMessage 编辑现有消息
| 参数 | 值 | 说明 |
|---|---|---|
| UPDATE_THROTTLE_MS | 500ms | 消息编辑最小间隔 |
| 发送新消息 | 无限制 | isInsert=true 时立即发送 |
| 编辑消息 | 节流 | isInsert=false 时应用节流 |
事件监听与消息发送分离
initialize())sendMessage() 仅负责发送消息,不处理监听全局事件总线解耦
ChannelMessageService 不直接与 Agent Task 交互ChannelEventBus 全局事件总线解耦统一消息格式
TMessage 统一消息格式IUnifiedOutgoingMessage| 能力 | 说明 |
|---|---|
sendMessage | 发送消息并获取响应 |
streamMessage | 流式发送消息 |
regenerate | 重新生成上一条回复 |
continue | 继续生成 |
stop | 停止当前生成 |
getContext | 获取会话上下文 |
clearContext | 清空会话上下文 |
AgentResponse {
type: 'text' | 'stream_start' | 'stream_chunk' | 'stream_end' | 'error'
text?: string
chunk?: string
error?: { code: string, message: string }
metadata?: {
model?: string
tokensUsed?: number
duration?: number
}
suggestedActions?: ActionButton[]
}
src/channels/
├── core/ # 核心模块
│ ├── ChannelManager.ts # 统一管理器(单例)
│ └── SessionManager.ts # 会话管理
│
├── gateway/ # 网关层
│ ├── PluginManager.ts # 插件生命周期管理
│ └── ActionExecutor.ts # Action 执行器(路由、消息处理)
│
├── actions/ # Action 处理(平台无关)
│ ├── types.ts # Action/Response 类型定义
│ ├── SystemActions.ts # 系统 Action(会话、设置、帮助)
│ ├── ChatActions.ts # 对话 Action(发送、重新生成等)
│ └── PlatformActions.ts # 平台 Action(配对等)
│
├── agent/ # Agent 集成
│ ├── ChannelEventBus.ts # 全局事件总线
│ └── ChannelMessageService.ts # 消息流式处理服务
│
├── pairing/ # 配对服务
│ └── PairingService.ts # 配对码生成和验证(平台无关)
│
├── plugins/ # 插件目录
│ ├── BasePlugin.ts # 插件抽象基类
│ ├── telegram/
│ │ ├── TelegramPlugin.ts # Telegram 插件
│ │ ├── TelegramAdapter.ts # 消息适配器
│ │ └── TelegramKeyboards.ts # 键盘组件
│ └── lark/
│ ├── LarkPlugin.ts # Lark 插件
│ ├── LarkAdapter.ts # 消息适配器
│ └── LarkCards.ts # Card 组件
│
├── utils/ # 工具函数
│ └── credentialCrypto.ts # 凭证加密
│
└── types.ts # 类型定义
| 表名 | 用途 |
|---|---|
assistant_plugins | 插件配置(Token、模式等) |
assistant_users | 已授权用户列表 |
assistant_sessions | 用户会话关联 |
assistant_pairing_codes | 待批准的配对请求 |
| 依赖包 | 用途 | 说明 |
|---|---|---|
grammy | Telegram Bot | Clawdbot 使用,API 优雅 |
@larksuiteoapi/node-sdk | Lark/Feishu Bot | 官方 SDK |
@slack/bolt | Slack Bot(待实现) | 官方 SDK |
discord.js | Discord Bot(待实现) | 官方 SDK |
| 阶段 | 内容 | 状态 |
|---|---|---|
| Phase 1 | Telegram + Lark 接入 | ✅ 已完成 |
| Phase 2 | 多会话管理、会话切换 | 🔄 待实现 |
| Phase 3 | Agent 切换(已支持,需 UI) | 🔄 部分完成 |
| Phase 4 | Model 动态切换 | 🔄 待实现 |
| Phase 5 | Slack 平台接入 | 🔄 待实现 |
| Phase 6 | Discord 平台接入 | 🔄 待实现 |
| Phase 7 | 速率限制 | 🔄 待实现 |
| Phase 8 | 会话与 AionUi 同步 | 🔄 待实现 |
| Phase 9 | Headless 独立服务模式 | 🔄 待实现 |
1. ChannelManager.getInstance().initialize()
├─ 初始化 PluginManager
├─ 初始化 SessionManager
├─ 初始化 PairingService
├─ 初始化 ActionExecutor
└─ 初始化 ChannelMessageService
2. 加载数据库中的插件配置
3. 为每个启用的插件调用 initialize() 和 start()
1. Plugin 接收平台消息
└─ toUnifiedIncomingMessage() 转换
2. PluginManager 调用 messageHandler
└─ ActionExecutor.handleMessage()
3. ActionExecutor 路由 Action
├─ Platform Action → PlatformActions
├─ System Action → SystemActions
└─ Chat Action → ChannelMessageService
4. ChannelMessageService.sendMessage()
└─ 通过 WorkerManage 调用 Agent Task
5. Agent 响应 → ChannelEventBus
└─ ChannelMessageService.handleAgentMessage()
└─ StreamCallback → ActionExecutor
└─ Plugin.sendMessage/editMessage()
Telegram
Lark/Feishu