ソースを参照

docs: Bot 工作组设计(多岗位机器人、组长分派任务、Bot API、Bot Playground)

- 13-bot-teams:工作组组成规则与生命周期、唤醒规则、任务与子任务、协作工具、限额、数据模型、Bot API、Bot Playground、分期
- ADR-0023:协调者模式,每个机器人在每个工作组一个独立会话
- ADR-0024:Bot API 使用 /bot/v1 与独立的 Bot Key(bk_),后台 Cookie 两边都接受
- 索引、术语、路线图(M4)同步

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Jerry Liang 1 週間 前
親
コミット
27b2c4fd41

+ 7 - 1
docs/README.md

@@ -22,7 +22,8 @@ docs/
 │  ├─ 09-admin-ui.md          管理后台与 Playground(含视觉规范)
 │  ├─ 10-deployment.md        部署与运维
 │  ├─ 11-roadmap.md           里程碑与待决事项
-│  └─ 12-custom-skills.md     自定义技能(导入或在后台编写,两个引擎共用)
+│  ├─ 12-custom-skills.md     自定义技能(导入或在后台编写,两个引擎共用)
+│  └─ 13-bot-teams.md         Bot 工作组:多岗位机器人、组长分派任务、Bot API(设计中)
 ├─ adr/                       架构决策记录(一事一档,只追加不改写;推翻时新增一条并标注 Superseded)
 └─ research/                  调研材料(选型依据、参考实现分析)
 ```
@@ -53,6 +54,8 @@ docs/
 | [0020](adr/0020-codex-fork-on-config-change.md) | Codex 会话配置变化时分叉 | Accepted |
 | [0021](adr/0021-third-party-mcp-via-gateway.md) | 第三方 MCP 服务经 MCP Gateway 转接 | Accepted |
 | [0022](adr/0022-managed-skill-dirs-readable-in-sandbox.md) | 服务管理的技能目录在沙箱中只读可见;Codex 的禁止规则绕开可读路径 | Accepted |
+| [0023](adr/0023-bot-teams-collaboration-model.md) | Bot 工作组:协调者模式,每个机器人一个独立会话 | Proposed |
+| [0024](adr/0024-bot-api-separate-keys.md) | Bot API 使用独立路径和独立的 Bot Key | Proposed |
 
 ## 调研
 
@@ -73,4 +76,7 @@ docs/
 | Profile | Agent 预设:提示词、模型、工具、连接器、权限模式的组合 |
 | Connector / 连接器 | (暂缓)一个内部平台的数据接入定义,通过 MCP Gateway 暴露为工具 |
 | Knowledge Root / 资料库 | 在后台登记的本地资料目录,Profile 启用后 Agent 可以访问 |
+| Bot / 机器人 | 后台配置的岗位:身份 + 关联的 Profile;分组长(lead)和组员(worker)两类(见 13) |
+| Team / 工作组 | Bot 协作的容器:1 个成员(人)+ 0–1 个组长 + 0–多个组员 |
+| Job / 任务、Task / 子任务 | 成员交给组长的复杂工作;组长分派给组员的单项工作 |
 | File Access Policy / 文件访问策略 | Profile 中的可读/可写/禁止路径配置,与全局禁止项、基线合并后生效 |

+ 29 - 0
docs/adr/0023-bot-teams-collaboration-model.md

@@ -0,0 +1,29 @@
+# ADR-0023 Bot 工作组的协作模型
+
+- 状态:Proposed · 日期:2026-10-26 · 设计见 [13-bot-teams](../design/13-bot-teams.md)
+
+## 背景
+需要在后台配置多个不同岗位的机器人。使用者把机器人拉到一起下达命令;复杂任务由一个管理机器人拆分、分派给其他机器人完成,简单工作也可以直接指定某个机器人去做。现有内核只支持"一个人对一个 Agent",引擎(Claude / Codex)的会话也都是单 Agent 的。
+
+## 决策
+- **工作组(team)是唯一的对话容器**:组成是 1 个成员(人)、0–1 个组长、0–多个组员,组长和组员加起来至少 1 个。不提供脱离工作组的机器人对话。
+- **每个"机器人 × 工作组"对应一个独立的引擎 Session**。机器人的记忆限于本工作组,不跨组。工作组的消息作为增量输入交给机器人,不让多个机器人共用一个上下文。
+- **协调者模式**:
+  - 成员把任务交给组长,组长通过子任务分派给组员
+  - 组员只通过子任务结果向组长汇报,**组员之间不互相 @,组员也不主动 @ 组长**
+  - 成员可以直接 @ 组员做单项工作,不经过组长
+- **任务依次执行**:同一工作组同一时间只有一个进行中的任务;同一任务内,不同组员的子任务可以并行。
+- **协作动作通过 MCP Gateway 内置工具完成**(`job_*`、`task_*`、`team_*`),按 Run 令牌中的角色开放;不靠解析机器人回复的文字。
+- **组长申请加入机器人需要成员审批**,复用 Gateway 内发起审批的现有流程。成员通过 API 直接增减机器人时不需要审批。
+- **审批**:设计上尽量避免触发审批;一旦触发,就在工作组里显示卡片,由成员处理。
+- **按任务设限额**(子任务数、组长轮数、成本、时长),超出就暂停任务,由成员决定继续或取消。
+
+## 考虑过的方案
+- **所有机器人共用一个会话**:引擎不支持多角色共用一个上下文,而且各机器人的技能、权限、模型不同,排除。
+- **自由群聊(机器人之间可以随意 @)**:容易出现互相接话停不下来、成本失控、难以收敛的情况,排除;协作统一走组长。
+- **机器人通过回复文字里的 @ 标记来协作**:解析不可靠,也无法做权限控制和审计,改为 Gateway 工具。
+
+## 后果
+- 引擎适配器、沙箱、Profile 不用改;新增 `apps/server/src/teams/` 模块和 8 张表,Gateway 和交互服务有少量改动
+- 多个机器人同时工作时 Run 数量成倍增加,需要关注 CLI 登录账号的速率限制;用量多的机器人建议用 API Key 类型的 Profile(ADR-0015)
+- 组长的执行质量决定复杂任务的效果,需要单独打磨组长的提示词和技能(设计文档 T1)

+ 26 - 0
docs/adr/0024-bot-api-separate-keys.md

@@ -0,0 +1,26 @@
+# ADR-0024 Bot API 与独立的 Bot Key
+
+- 状态:Proposed · 日期:2026-10-26 · 补充 ADR-0015、ADR-0019 · 设计见 [13-bot-teams](../design/13-bot-teams.md)
+
+## 背景
+Bot 工作组(ADR-0023)通过 API 对外提供。它和现有的 Agent API(`/v1`,会话、消息)是两类能力,使用方和权限范围都不同:Agent API 的 Key 按 Profile 授权,Bot 的 Key 应当按机器人授权。两者不应该互相通用。
+
+## 决策
+- **独立路径**:Bot API 统一使用 `/bot/v1/*` 前缀,与 `/v1/*` 分开。
+- **独立的 Key**:
+  - 新表 `bot_api_keys`,前缀 `bk_`(Agent Key 是 `ask_`)
+  - Key 按允许使用的机器人授权(`allowedBotIds`),不涉及 Profile
+  - 后台单独设一个"Bot Keys"页面
+- **鉴权按路径前缀只认一种 Key**:`/v1` 只接受 `ask_` 和 Agent 浏览器令牌;`/bot/v1` 只接受 `bk_` 和 Bot 浏览器令牌。拿错类型一律返回 401,不提示另一套 API 的存在。
+- **后台管理员的 Cookie 两边都接受**(与现有 Playground 调用 `/v1` 的方式一致),来源记为 `admin`。Bot Playground 因此不需要单独的后端;替身组员、逐步执行等调试功能只对来源为 `admin` 的工作组开放。
+- **浏览器令牌**:沿用 ADR-0019 的无状态 HMAC 令牌,载荷里增加 `kind`(agent / bot),两种令牌不能互换使用。Bot 浏览器令牌由 `POST /bot/v1/browser-tokens` 签发。
+- **数据隔离**:
+  - 工作组归属于创建它的 Bot Key
+  - 机器人底层的会话来源记为 `team:<id>`,Agent API 永远看不到
+  - Agent Key 创建的会话,Bot API 也看不到
+- **CORS**:沿用"设置 › 安全 › CORS 来源",同时作用于 `/v1` 和 `/bot/v1`。
+- **用量**按 Bot Key 和机器人分别统计。
+
+## 后果
+- 同一个业务平台如果同时使用两类能力,需要持有两个 Key,并分别签发浏览器令牌
+- 鉴权中间件需要按路径前缀分流;现有 `api_keys` 表和 `/v1` 的行为不变

+ 5 - 0
docs/design/11-roadmap.md

@@ -30,6 +30,11 @@
 - 工作区自动清理、回归用例批量重放
 - 网络加强(nftables 按 cgroup 拦截局域网)
 
+### M4:Bot 工作组(设计中,见 13、ADR-0023/0024)
+- 一期:机器人定义、Bot Key 与 `/bot/v1`、工作组与消息、@ 组员的单项工作、审批卡片;`BotClient`、`<TeamChat>`;Bot Playground 基本形态
+- 二期:组长、能力卡片、任务与子任务、限额与暂停、组长申请加入机器人;Playground 的替身组员、逐步执行、任务 / 输入 / 用量页签
+- 三期:`BotClient`、`<TeamChat>` 随 SDK 发布与接入示例;复制到 Playground、回归用例
+
 ### 以后(按需)
 - 内部平台连接器(设计见 08)
 - 专用系统用户(迁移步骤见 06 §5.3)

+ 358 - 0
docs/design/13-bot-teams.md

@@ -0,0 +1,358 @@
+# 13 Bot 工作组
+
+> 状态:**设计中(2026-10-26)**,尚未实施。决策见 ADR-0023(工作组协作模型)、ADR-0024(Bot API 与独立的 Bot Key)。
+
+## 1. 背景与目标
+
+现有的 AgentServer 是**单 Agent 执行内核**:Profile 定义角色,Session 保存一段对话,Run 执行一轮,MCP Gateway 提供工具,过程以事件形式记录、可回放。使用方式是"一个人对着一个 Agent"。
+
+本功能在内核之上增加**协作层**:
+
+- 后台可以配置多个不同岗位的**机器人**,每个机器人有自己的技能
+- 使用者创建**工作组**,拉入机器人后下达命令
+- 复杂任务交给**组长**,由组长拆分并分派给**组员**,直到完成
+- 使用者也可以直接 @ 某个组员,让它完成单项工作
+
+通过独立的 **Bot API** 对外提供,与现有的 Agent API(`/v1`)不共用 Key。
+
+不在范围内:
+- 多用户(工作组里只有一个使用者,见 §3)
+- 跨工作组的记忆
+- 外部 IM 平台接入:由外部桥接服务调用 Bot API 实现,见 §10
+
+## 2. 术语
+
+| 术语 | API | 含义 |
+|---|---|---|
+| 机器人 | `bot` | 后台配置的一个岗位:身份(名称、头像、岗位描述)+ 关联的 Profile(模型、技能、MCP 服务、资料库、权限) |
+| 组长 | `lead` | 类型为组长的机器人:负责拆分任务、分派、汇总,自身不带业务技能 |
+| 组员 | `worker` | 类型为组员的机器人:执行具体工作 |
+| 工作组 | `team` | 一次协作的容器:1 个成员 + 0–1 个组长 + 0–多个组员,有共享目录和消息记录 |
+| 成员 | `human` | 工作组里的人类使用者,每个工作组**有且只有一个** |
+| 任务 | `job` | 成员交给组长的一项复杂工作;同一工作组内的任务**依次执行,不并行** |
+| 子任务 | `task` | 组长分派给某个组员的单项工作 |
+| 单项工作 | `direct` | 成员直接 @ 组员发起的工作,不经过组长 |
+| Bot Key | `bk_…` | 调用 Bot API 的密钥,与 Agent API 的 `ask_…` 互不通用 |
+
+## 3. 工作组
+
+### 3.1 组成规则
+
+| 角色 | 数量 |
+|---|---|
+| 成员(人) | 恰好 1 个 |
+| 组长 | 0 或 1 个 |
+| 组员 | 0 到多个 |
+| 组长 + 组员 | **至少 1 个** |
+
+- 创建时和之后任何一次修改,都必须满足上面的规则:不能移除最后一个机器人;已有组长时不能再加第二个组长。
+- 成员只是调用方传来的显示身份 `{id, name}`,AgentServer 不做认证(认证由外部平台负责,见 §10)。
+- 所有对话都必须在工作组内进行,没有脱离工作组的"直接和机器人对话"。只想让一个机器人干活时,建一个只有这个组员的工作组即可,不需要组长。
+
+### 3.2 生命周期
+
+| 状态 | 说明 |
+|---|---|
+| 进行中(`active`) | 正常收发消息 |
+| 已暂停(`paused`) | 成员或系统(超出限额时)暂停:正在执行的 Run 被中断,新消息只记录不唤醒机器人;恢复后继续 |
+| 已关闭(`closed`) | 不再接收消息,进行中的任务被取消;历史、文件只读保留;可以**重新打开**(各机器人的引擎会话可以续接) |
+| 删除 | 永久清除消息、文件和底层会话;用量统计保留 |
+
+已关闭的工作组以后纳入 M3 的工作区自动清理(关闭超过 N 天后删除)。
+
+### 3.3 机器人与引擎会话
+
+- 每个"机器人 × 工作组"对应一个独立的引擎 Session(`team_bot_sessions`),机器人的记忆就是这个 Session。离开工作组后不带走,也不跨工作组。
+- Session 的来源(`sessions.source`)记为 `team:<teamId>`,不会出现在 Agent API 的会话列表中。
+- 每个 Session 有自己的工作区,另外把工作组的**共享目录**作为额外的可写路径,通过三层访问策略合并进去(ADR-0010):
+
+```
+<dataDir>/teams/<teamId>/shared/
+├─ uploads/     成员上传的文件
+└─ outputs/     各机器人交付的文件(消息里以文件卡片显示)
+```
+
+- 同一个机器人在同一个工作组内**按顺序执行**。执行期间到达的新消息会合并起来,在下一轮一起交给它。不同机器人之间并行执行,受 RunManager 的全局和按引擎的并发限制。
+
+## 4. 消息与唤醒规则
+
+### 4.1 消息
+
+工作组的消息记录(`team_messages`)是成员看到的时间线,和机器人内部的执行过程(引擎事件)分开存放:
+
+| 发送者 | 消息类型 |
+|---|---|
+| 成员 | 普通消息(文字、@、附件) |
+| 组长 | 回复、任务开始和结束、子任务分派、申请加入机器人 |
+| 组员 | 回复(单项工作)、子任务结果 |
+| 系统 | 成员变化、暂停和恢复、超出限额、审批卡片 |
+
+机器人每一轮的工具调用、思考过程不进消息记录。成员可以从某条消息点开,查看对应 Run 的完整过程(复用现有的事件和回放)。
+
+### 4.2 谁被唤醒
+
+| 来源 | 规则 |
+|---|---|
+| 成员发消息并 @ 了机器人 | 唤醒被 @ 的机器人(可以同时 @ 多个) |
+| 成员发消息,没有 @ | 有组长就交给组长;没有组长但只有一个组员,就交给这个组员;否则返回 400 `mention_required` |
+| 组长分派子任务 | 唤醒对应组员 |
+| 组员完成或失败一个子任务 | 唤醒组长 |
+| 组员的单项工作完成 | 不唤醒任何机器人,回复直接给成员 |
+
+**组员之间不能互相 @,组员也不能主动 @ 组长**,只能通过子任务的结果向组长汇报。机器人发出的消息里如果写了 @,只当作文字,不会唤醒任何人。
+
+### 4.3 交给机器人的输入
+
+每次唤醒时,服务端把"自上次以来与它有关的新内容"拼成这一轮的输入:
+
+```
+【工作组新消息】
+[10:02] 成员 张三:@组长 帮我分析……(附件:shared/uploads/sales.xlsx)
+【子任务 #3 已完成 · 数据分析员】
+结果:……  文件:shared/outputs/summary.csv
+```
+
+- 组长能看到工作组里的全部新消息。
+- 组员只收到:@ 它的消息、分派给它的子任务,以及这些内容引用的上下文。
+- 每个机器人 Session 记录"已读到的 seq",以后调试时能看到它在某一轮实际读到了哪些内容(作为事件记下来)。
+
+## 5. 组长与任务
+
+### 5.1 能力卡片
+
+组长靠**能力卡片**了解每个组员会什么。卡片由服务端根据机器人的配置自动生成:
+
+- 名称、岗位描述(后台填写,写明擅长什么、不负责什么)
+- 技能:所用 Profile 中每个技能的 `name` 和 `description`(取自 SKILL.md 开头的元数据)
+- MCP 服务和工具摘要、可访问的资料库名称
+- 权限模式(只读 / 自动)
+
+组长的 Session 开始时,把当前所有组员的卡片注入它的提示词。成员变化时补一条系统消息,组长也可以随时调用 `team_members()` 重新获取。
+
+### 5.2 任务流程
+
+```
+成员 @组长 "……"
+  └─ 组长判断这是一项任务 → job_start(标题, 计划)          同一时间只能有一个进行中的任务
+       ├─ task_create(组员, 说明, 依赖的子任务) × N          不同组员的子任务可以并行
+       │     └─ 组员执行 → task_complete(结果, 文件) / task_fail(原因)
+       │           └─ 唤醒组长:继续分派 / 调整计划 / 重试
+       └─ job_complete(总结, 文件)  或  job_fail(原因)      → 发到工作组,交给成员
+```
+
+- 任务由组长判断后显式开始。闲聊、简单问题由组长直接回答,不开任务。
+- 任务进行中,成员发给组长的消息算作对当前任务的补充说明。
+- 已有进行中的任务时,`job_start` 会被拒绝;组长应先结束当前任务,或者告诉成员稍后再提。
+- 组员在子任务的这一轮结束时如果没有调用 `task_complete` 或 `task_fail`,服务端就把它最后的回复作为结果,按"完成"处理。
+- 成员可以随时取消任务:正在执行的子任务被中断,组长收到通知。
+- 任务进行中,成员仍然可以直接 @ 组员做单项工作;如果这个组员正在执行子任务,单项工作会排队等它做完。
+
+### 5.3 组长申请加入机器人
+
+工作组可以只建一个组长,再由组长根据实际需要申请加入机器人:
+
+1. 组长调用 `team_bot_catalog()` 查看可以加入的机器人。范围是这个工作组所用的 Bot Key 允许使用、且不在本组的组员机器人,返回能力卡片。
+2. 组长调用 `team_request_bot(botId, 理由)`,工作组里显示一张**审批卡片**,由成员批准或拒绝。
+3. 批准后机器人加入,添加系统消息,组长收到新组员的卡片。
+
+成员通过 API 直接增减机器人时不需要审批。移除一个正在执行子任务的组员时,该子任务按失败处理,并通知组长。
+
+### 5.4 协作工具(MCP Gateway 内置)
+
+Gateway 根据 Run 令牌中的 `teamId`、`botId` 和角色,只列出该角色可以用的工具:
+
+| 工具 | 组长 | 组员(子任务中) | 说明 |
+|---|---|---|---|
+| `team_members()` | ✓ | | 当前组员的能力卡片 |
+| `team_bot_catalog()` | ✓ | | 可以申请加入的机器人 |
+| `team_request_bot(botId, reason)` | ✓ | | 申请加入机器人,需要成员审批 |
+| `team_history(before?, limit?)` | ✓ | ✓ | 读取更早的消息 |
+| `job_start(title, plan)` / `job_complete(summary, files?)` / `job_fail(reason)` | ✓ | | 开始和结束任务 |
+| `task_create(botId, title, instructions, dependsOn?)` | ✓ | | 分派子任务 |
+| `task_cancel(taskId)` / `task_list()` | ✓ | | 管理子任务 |
+| `task_complete(result, files?)` / `task_fail(reason)` | | ✓ | 汇报子任务结果 |
+
+机器人每轮的最终回复会自动作为一条消息发到工作组,不需要专门的"发消息"工具。
+
+## 6. 审批
+
+- 设计上,机器人尽量**不触发审批**:Profile 的权限模式用 `auto` 或 `readonly`,第三方 MCP 工具的策略设成"直接调用"或"关闭"。
+- 如果仍然触发了审批或提问(包括 `team_request_bot`),就在工作组里显示一张审批卡片,由成员处理。这复用现有的交互服务,引擎侧不改。
+- 某个机器人在等审批时,只有它自己被挂起,其他机器人照常工作。
+- 审批超时(`interactionTimeoutSec`)按拒绝处理。对于子任务,就是子任务失败,再唤醒组长处理。
+
+## 7. 防失控与限额
+
+由于组员之间不能互相 @,协作链路只有"组长 ⇄ 组员"这一种往返,主要靠按任务设限额:
+
+| 限额 | 默认值(后台可改,工作组创建时可以调低) |
+|---|---|
+| 每个任务的子任务数 | 20 |
+| 每个任务中组长的执行轮数 | 30 |
+| 每个任务的成本上限 | 以美元计,按 Run 用量累加 |
+| 每个任务的时长上限 | 2 小时 |
+| 每个工作组同时执行的 Run 数 | 4 |
+
+超出限额时,任务自动暂停,并发一条系统消息说明原因,由成员选择"继续"(这一项限额放宽一倍)或"取消"。工作组可以随时整体暂停。
+
+## 8. 数据模型(新增)
+
+| 表 | 主要字段 |
+|---|---|
+| `bots` | id、name、avatar、kind(lead / worker)、description(岗位描述)、profileId、enabled、时间戳 |
+| `bot_api_keys` | id、name、keyHash、keyPrefix(`bk_`)、enabled、allowedBotIds、时间戳 |
+| `teams` | id、source(Bot Key id 或 admin)、title、human(`{id, name}`)、status、limits、debug(`{stepMode, stubBotIds}`,仅 admin,见 §12.2)、sharedDir、时间戳 |
+| `team_bots` | teamId、botId、role(lead / worker)、joinedAt |
+| `team_bot_sessions` | teamId、botId → sessionId、lastReadSeq |
+| `team_messages` | teamId、seq、sender(human / bot / system)、senderId、kind、text、mentions、fileIds、jobId、taskId、runId、ts |
+| `jobs` | id、teamId、title、plan、status、summary、用量合计、限额计数、时间戳 |
+| `tasks` | id、jobId、teamId、botId、title、instructions、dependsOn、status、result、fileIds、runId、时间戳 |
+
+现有表的改动:
+- `sessions.source` 增加 `team:<id>`
+- `interactions` 增加可为空的 `teamId`,用于在工作组事件流中推送和查询
+- `usage_daily` 的 source 增加 Bot Key 维度;另外按 botId 汇总,用于后台统计
+
+## 9. Bot API
+
+前缀 `/bot/v1`,只接受 Bot Key(`bk_`)、Bot 浏览器令牌或后台管理员的 Cookie(Bot Playground 使用,来源记为 `admin`),详见 ADR-0024。仅 admin 可用的调试接口(替身结果、逐步执行的"继续")也放在这个前缀下,其他调用方访问时返回 403。
+
+| 方法与路径 | 说明 |
+|---|---|
+| `GET /bots` | 这个 Key 可以使用的机器人及其能力卡片 |
+| `POST /teams` | `{title, human:{id,name}, leadBotId?, workerBotIds[], limits?}` |
+| `GET /teams`、`GET /teams/:id` | 这个 Key 创建的工作组 |
+| `PATCH /teams/:id` | 修改标题、限额 |
+| `POST /teams/:id/bots`、`DELETE /teams/:id/bots/:botId` | 增减机器人(需满足 §3.1 的组成规则) |
+| `POST /teams/:id/messages` | `{text, mentions?, fileIds?}`,发送者固定是这个工作组的成员 |
+| `GET /teams/:id/messages?after=&limit=` | 消息历史 |
+| `GET /teams/:id/stream` | SSE,支持断线续传(`Last-Event-ID`) |
+| `POST /teams/:id/files`、`GET /teams/:id/files/:fileId` | 上传到 `shared/uploads/`,下载共享目录中的文件 |
+| `POST /teams/:id/interactions/:iid` | 处理审批或回答提问 |
+| `GET /teams/:id/jobs`、`POST /teams/:id/jobs/:jobId/cancel` | 任务和子任务的进度;取消任务 |
+| `POST /teams/:id/jobs/:jobId/continue` | 超出限额后继续 |
+| `POST /teams/:id/pause`、`/resume`、`/close`、`/reopen`、`DELETE /teams/:id` | 生命周期 |
+| `GET /teams/:id/runs/:runId/events` | 某一轮的完整执行过程(复用现有事件格式) |
+| `POST /browser-tokens` | 签发 Bot 浏览器令牌 |
+
+SSE 事件:
+- `message.created`
+- `bot.status`(空闲 / 排队 / 工作中 / 等待审批)
+- `job.updated`、`task.updated`
+- `interaction.required`、`interaction.resolved`
+- `team.updated`(成员、状态变化)
+
+## 10. AgentServer 与外部的分工
+
+| AgentServer 负责 | 外部负责 |
+|---|---|
+| 机器人定义、Bot Key(后台) | 使用者的身份和登录;把自己的用户映射为成员 `{id, name}` |
+| 工作组、成员、消息、共享文件的存储 | 工作组的聊天界面(可以用 SDK 提供的组件,见 §12) |
+| 唤醒规则、调度、组长和组员的协作工具 | 谁可以建工作组、可以拉哪些机器人等业务规则(Bot Key 的范围之内) |
+| 审批卡片、限额、暂停、关闭 | 通知和推送 |
+| 事件流、用量、审计 | 外部 IM(飞书等)接入:桥接服务调用 Bot API,把外部的群映射为工作组 |
+| 后台观察和调试页面 | |
+
+## 11. 对现有模块的影响
+
+| 模块 | 改动 |
+|---|---|
+| 引擎适配器、沙箱 | 不改 |
+| Profile | 不改,机器人引用 Profile |
+| 文件访问策略 | 合并时加入共享目录(可写),属于基线层,Profile 不能取消 |
+| RunManager | 新增由调度器发起 Run 的入口;同一机器人 Session 按顺序执行已经满足 |
+| MCP Gateway | Run 令牌带上 teamId、botId、role、jobId、taskId;新增 §5.4 的协作工具;`team_request_bot` 复用 Gateway 内发起审批的现有流程 |
+| 交互服务 | 交互关联 teamId,推送到工作组事件流 |
+| 鉴权 | 按路径前缀区分 Key 类型(ADR-0024) |
+| 后台 | 新增"机器人""Bot Keys""工作组"三个页面(§12) |
+
+新增模块:`apps/server/src/teams/`,包括工作组服务、消息服务、调度器、协作工具、能力卡片和 Bot API 路由。
+
+## 12. 后台、Bot Playground 与 SDK
+
+### 12.1 后台页面
+
+- **机器人**:列表、新建和编辑(名称、头像、类型、岗位描述、Profile);预览能力卡片;"在 Playground 中测试"
+- **Bot Keys**:签发、停用、允许使用的机器人
+- **Bot Playground**:管理员建工作组、以成员身份下命令,用于验证机器人(§12.2)
+- **工作组**:所有来源的工作组,视图与 Playground 相同但只读,只能暂停、关闭;可以"复制到 Playground"(按相同成员组成新建一个工作组),用来复现问题
+
+### 12.2 Bot Playground
+
+做法与现有 Playground 相同:**没有单独的后端**,后台用同源 Cookie 调用 `/bot/v1`,工作组的来源记为 `admin`;界面用 `BotClient` 和 `<TeamChat>`,再加后台专用的调试面板。
+
+要验证的东西分三层:
+
+| 验证对象 | 关心什么 | 支持方式 |
+|---|---|---|
+| 单个组员 | 技能、权限、产出质量 | 只有这个组员的工作组,@ 它干活,查看每一轮的执行过程 |
+| 组长 | 是否读懂能力卡片,拆分、分派、收尾是否合理 | 能力卡片预览、每轮输入;替身组员 |
+| 整个工作组 | 端到端能否完成、成本、是否失控 | 任务看板、分项用量、逐步执行、调低限额 |
+
+布局沿用现有 Playground 的工作台结构:
+
+```
+┌ 侧栏 ────────────┬ 工作组时间线 ─────────────────────────────┬ 调试面板 ───────────────┐
+│ BOT PLAYGROUND + │ [工作组标题]  ● 进行中  [⏸暂停][⏭逐步][⋯]   │ 成员│任务│过程│输入│文件│用量│
+│                  │                                          │                         │
+│ ▸ 周报测试        │ ┌ 我:@组长 分析 Q3 数据并出报告 📎 ┐      │ 👑 组长    ● 工作中      │
+│ ▸ 组长拆分测试    │ └────────────────────────────────┘      │ 📊 数据员  ○ 空闲 [替身] │
+│ ▸ 数据员单测      │ 👑 组长:开始任务「Q3 分析」,计划:…     │ 📝 文档员  ◐ 排队        │
+│                  │ ├ ▸ #1 → 📊数据员:清洗并汇总    ✓       │ [+ 添加机器人]           │
+│                  │ ├ ▸ #2 → 📝文档员:生成 Word 报告 …       │                         │
+│                  │ ⚙ 系统:组长申请加入「图表员」 [批准][拒绝] │                         │
+│                  │ 📊 数据员 · #1 结果:…  📄summary.csv    │                         │
+│                  ├──────────────────────────────────────────┤                         │
+│                  │ [@ 选择机器人]  输入命令…           [➤]  │                         │
+└──────────────────┴──────────────────────────────────────────┴─────────────────────────┘
+```
+
+调试面板的页签:
+
+| 页签 | 内容 |
+|---|---|
+| 成员 | 各机器人的状态(空闲 / 排队 / 工作中 / 等审批)、能力卡片预览、增减机器人、替身开关 |
+| 任务 | 任务和子任务的树形视图:状态、依赖、耗时、成本,点击跳到时间线中的位置 |
+| 过程 | 选择机器人和轮次,查看完整执行过程。每个机器人底层是普通 Session,复用 `Timeline` 和现有的 `DebugPanel` |
+| 输入 | 每一轮服务端实际交给该机器人的内容(拼好的新消息、读到的 seq)。排查组长问题时先看这里 |
+| 文件 | 共享目录,预览和下载 |
+| 用量 | 按机器人、任务、子任务分别统计 |
+
+点击时间线中任意一条机器人消息,都会跳到"过程"页签的对应轮次。
+
+**调试功能**(保存在工作组的 `debug` 字段中,只有来源为 `admin` 的工作组可以设置,Bot Key 设置会被拒绝):
+
+- **替身组员**(`stubBotIds`):分派给替身的子任务不执行,时间线中显示一张卡片,由管理员手动填写结果(可以附文件)或标记失败。用来在不花组员成本的情况下反复测试组长的拆分、重试和汇总,也可以故意返回失败,看组长怎么处理。
+- **逐步执行**(`stepMode`):调度器每次唤醒机器人之前先停下,在时间线中显示"下一步:唤醒 📊数据员(子任务 #1)",管理员点"继续"才执行。用来观察协作链路,防止配置有问题时一下子跑出一大串 Run。
+
+入口与联动:
+
+| 入口 | 行为 |
+|---|---|
+| 机器人编辑页"在 Playground 中测试" | 组员:新建只有它的工作组。组长:新建"组长 + 本后台可用组员的替身" |
+| 工作组页面"复制到 Playground" | 按相同成员组成新建工作组 |
+| 修改机器人配置 | 下一轮生效;组员的岗位描述变化后,组长收到一条更新能力卡片的系统消息 |
+| 回归用例(09 §3.6,M3) | 把"成员组成 + 第一条命令"保存为用例,以后批量重放并比对结果 |
+
+### 12.3 SDK
+
+- `@agent-server/client` 增加 `BotClient`(Bot API、工作组 SSE 订阅、断线续传)
+- `@agent-server/chat-ui` 增加 `<TeamChat>` 组件:消息时间线、@ 选择、任务进度、审批卡片、替身卡片(仅在 `debug` 生效时显示)、文件卡片
+- 两者在一期实现,先由后台使用;三期随 SDK 发布
+
+## 13. 分期
+
+| 期次 | 内容 | 验收 |
+|---|---|---|
+| 一期 | 机器人定义、Bot Key 和 `/bot/v1` 鉴权(含后台 Cookie)、工作组的组成规则与生命周期、消息、唤醒规则(只有 @ 组员的单项工作)、共享目录、工作组 SSE、审批卡片;`BotClient`、`<TeamChat>`;Bot Playground 基本形态(时间线、成员、过程、文件页签) | 在 Bot Playground 中建一个有两个组员的工作组,分别 @ 它们完成单项工作,过程中处理一次审批;用 Agent API 的 Key 访问 Bot API 被拒绝 |
+| 二期 | 组长、能力卡片、任务与子任务、协作工具、限额与暂停、组长申请加入机器人;Playground 的任务、输入、用量页签,替身组员,逐步执行,"在 Playground 中测试"入口 | 只建一个组长的工作组,组长申请加入两个机器人(经审批),把一项复杂任务拆成多个子任务完成并交付文件;人为触发子任务数上限后能继续或取消;全部组员设为替身时,能手动填写结果完成一项任务 |
+| 三期 | `BotClient`、`<TeamChat>` 随 SDK 发布,接入示例,子任务依赖和并行的完善;后台工作组页面"复制到 Playground";回归用例 | 在 platform-demo 中完成一期、二期的验收流程 |
+
+## 14. 待决事项
+
+| # | 问题 | 倾向 |
+|---|---|---|
+| T1 | 组长的提示词和协作规范放在哪里 | 内置一个"组长"Profile 和配套技能,后台可以复制修改 |
+| T2 | 组长能否申请移除组员 | 一期、二期不支持,由成员操作 |
+| T3 | 工作组长期运行后,组长的 Session 越来越长 | 依赖引擎自身的压缩;任务结束时由组长写一份任务纪要到共享目录,以后再观察是否需要每个任务重新开一个组长 Session |
+| T4 | 能力卡片里是否列出全部 MCP 工具 | 只列服务名和说明,工具较多时不展开 |