Skip to content

feat(teams): add multi-agent team support with TL, bidding arena, and blackboard - #96

Open
moyunqinghe wants to merge 4 commits into
OpenBMB:mainfrom
momobiubiu:feat/multi-agent-teams
Open

feat(teams): add multi-agent team support with TL, bidding arena, and blackboard#96
moyunqinghe wants to merge 4 commits into
OpenBMB:mainfrom
momobiubiu:feat/multi-agent-teams

Conversation

@moyunqinghe

Copy link
Copy Markdown

Summary

Adds multi-agent team support: teams of digital employees with a Team Lead (TL), task assignment/claiming, a 3-round HP-based bidding arena, a per-team blackboard, and full HITL (human-in-the-loop) controls. Design decisions are documented in design-multi-agent-team-decisions.md.

Backend

  • New app/teams/ module: teams/members CRUD, task lifecycle (pending → bidding → in_progress → review/rework → done/cancelled/escalated), bidding with per-round TL scoring and HP elimination, blackboard ingest pipeline (parse → normalize → structured write → citations), wake events, and audit trail (team_task_events)
  • 7 new tables (SQLite ALTER/CREATE migrations in db/database.py), optimistic locking on task claim/award
  • Team TL chat integrated into the workspace chat: ChatSession.team_id, team-context injection (roster / open tasks / blackboard top-K) and task-dispatch post-processing in /api/chat/turn and /api/chat/stream
  • Channel bindings can target a team; inbound messages to a team-bound channel get TL semantics via service_intake.py (merged with the new inbound attachment support)
  • New blackboard query tool available inside member execution sessions

Frontend

  • New pages: TeamsPage, TeamDetailPage (task board, bidding records, reports, award override), TeamChatPage; BiddingArena and TeamCard components; sidebar navigation entry
  • Agent-scope storage extended with team scope (isTeamScope / readEmployeeScope); chat header/empty-state updated for team sessions
  • Knowledge detail dialog gains a graph view (KnowledgeGraphCanvas) with a graph/cards toggle — this intentionally coexists with the new overview-panel KnowledgeGraphVisualization
  • i18n entries for all new UI text (zh source + en translations)

Explicitly out of scope (v1): pure-agent resident TL loop, unbounded debate, automatic cross-team information flow.

Risk

  • Large surface area (~15.6k insertions), but nearly all additive; existing single-agent paths are untouched. Shared-file changes are limited to scope-storage handling and additive fields (ChatSession.team_id, ChatTurnRequest.interaction_mode)
  • DB migration is SQLite-only, matching the supported production migration path
  • Rebased onto latest main; conflicts resolved in service_intake.py (attachments + team context both preserved), KnowledgePage.tsx (both graph views kept), and en.json (both translation sets kept)

Tests

  • pytest backend/tests: 1478 passed (incl. 7 new team test modules)
  • npm --prefix frontend-enterprise test: 145 passed
  • npm --prefix frontend-enterprise run build: passes
  • ruff check: no new violations beyond patterns already present in the codebase (e.g. FastAPI Depends B008); i18n:check failure count is lower than on main (pre-existing failures unrelated to this PR)

UI validation

Routes verified locally with an admin user: /teams, /teams/:id (board, bidding arena, award override), team TL chat via /workspace/chat/:sessionId, and the knowledge detail graph view.

@hm1229
hm1229 self-requested a review August 13, 2026 05:03
@moyunqinghe
moyunqinghe force-pushed the feat/multi-agent-teams branch from b05eb40 to cbe4a34 Compare August 13, 2026 06:37
@hm1229

hm1229 commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

[P1] 只读任务会话实际上可以被任意租户成员写入
_ensure_chat_session_available()只要发现 team_id 非空,就允许同租户任意用户通过通用 /api/chat/turn 发消息。
但团队会话不只有 TL 对话,还包括任务执行、竞标、验收等内部会话。前端明确显示“任务会话仅可查看”,后端注释也说这些会话“不对人直接聊”,实际却没有阻止。
具体场景:
普通租户成员从团队会话列表拿到某个任务会话的 session_id。
调用 /api/chat/turn,传入该 session_id。
_bind_request_to_session_agent() 直接使用会话绑定的 Agent,不再检查当前用户能否使用这个 Agent。
用户消息被写入自主任务、竞标或验收记录,并能触发对应 Agent。
这既会污染任务执行历史,也形成了 Agent 使用权限绕过。
建议只允许 TL 对话 类型的团队会话进入人工 /turn、/stream,其他团队会话直接返回 403/404,并补任务、竞标、验收会话不可写的回归测试。
2. [P1] 同一个 TL 领导多个团队时,可以把 A 团队会话写进 B 团队
/{team_id}/tl/chat 对传入 session 的校验 只检查:
租户相同
Agent 是当前 TL
没有检查 session.team_id == team.id,也没有确认它确实是 TL 对话。
而当前数据模型允许同一个 Agent 同时领导多个团队。因此可以:
Agent X 同时是团队 A、B 的 TL。
请求团队 B 的 /tl/chat,却传入团队 A 的 session_id。
B 的团队上下文和用户消息被写进 A 的会话。
回复解析后创建的任务却属于 B。
最终 A、B 的聊天历史和任务审计会互相串线。这里至少应该同时验证 team_id、agent_id 和会话类型,并增加“共享 TL 的两个团队”回归测试。
3. [P2] 统一线程列表也会把 TL 会话挂错团队
list_team_threads() 查询 TL 会话时同样没有按 ChatSession.team_id 过滤。
共享 TL 的情况下,A、B 两个团队都会查出对方的 TL 会话,同一会话会以不同团队名重复出现。应增加:
ChatSession.team_id == team.id

@moyunqinghe

Copy link
Copy Markdown
Author

感谢 review,三条意见全部采纳,已在 422d552 修复:

1. [P1] 非 TL 团队会话可被任意租户成员写入

chat.py 新增 _ensure_team_session_human_writable() 校验,挂在 /api/chat/turn/api/chat/stream 两个入口:团队会话(team_id 非空)中只有标题为「TL 对话」的会话允许人工发言,任务执行 / 竞标 / 验收等内部会话一律返回 403。判据与 _team_tl_session_team()tl/session 端点保持一致。这样 _bind_request_to_session_agent() 的 Agent 权限绕过低级路径也被一并堵死。

2. [P1] 共享 TL 时跨团队串写

/{team_id}/tl/chat 对传入 session_id 的校验现在同时检查 session.team_id == team.id 和「TL 对话」标题(原来只查租户和 Agent),不满足即 404,A 团队的会话无法再被写进 B 团队的上下文。

3. [P2] 统一线程列表串团队

list_team_threads() 查询 TL 会话时补上了 ChatSession.team_id == team.id 过滤,共享 TL 下同一会话不会再以两个团队名重复出现。

回归测试backend/tests/test_teams_conversations.py):

  • test_chat_turn_and_stream_reject_non_tl_team_sessions:任务 / 验收 / 竞标三类会话在 /turn、/stream 均 403
  • test_tl_chat_rejects_session_from_other_team_with_shared_tl:共享 TL 双团队,跨团队传 session → 404
  • test_team_threads_scope_tl_sessions_by_team_with_shared_tl:线程列表按团队归属不重复

另外把 test_teams_ops.py 里线程列表的旧用例补上了 team_id(原 fixture 恰好覆盖的是修复前的行为)。

后端全量测试 1525 个全部通过;ruff 无新增违规(剩余的 B008 等均为仓库既有模式)。

@hm1229 hm1229 self-assigned this Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants