Skip to content

feat: add Agent Team experimental feature for parallel sub-agent coordination#75

Open
BingqingLyu wants to merge 7 commits into
mainfrom
pr-2886-feat-agent-team
Open

feat: add Agent Team experimental feature for parallel sub-agent coordination#75
BingqingLyu wants to merge 7 commits into
mainfrom
pr-2886-feat-agent-team

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Apr 27, 2026

Copy link
Copy Markdown
Owner

TLDR

Adds Agent Team — an experimental feature that lets the lead agent spawn and coordinate a team of sub-agents working in parallel on different parts of a task. The feature is off by default and gated behind an experimental setting or environment variable.

Screenshots / Video Demo

N/A — no user-facing UI change beyond new tools appearing when the feature is enabled. The interaction happens entirely through tool calls within a conversation.

Dive Deeper

Why Agent Team?

Today, the Agent tool runs sub-agents one at a time — the leader spawns an agent, waits for it to finish, reads the result, then spawns the next. This is fine for small tasks, but falls apart when:

  • A task has naturally parallel subtasks (e.g., "refactor auth, update tests, and fix docs" are independent)
  • The user wants faster wall-clock time — three agents working simultaneously finish sooner than three sequential runs
  • Subtasks need to share context — one agent discovers something that another agent needs to know mid-flight

Agent Team solves this by introducing a leader–teammate model: the lead agent creates a team, spawns teammates that run concurrently, and coordinates them through messages and a shared task board.

How to enable

The feature is disabled by default. Enable it with either option (env var takes priority):

  • Settings: add to ~/.qwen/settings.json:
    { "experimental": { "agentTeam": true } }
  • Environment variable: QWEN_CODE_ENABLE_AGENT_TEAM=1

A session restart is required after changing the setting. When disabled, none of the team tools are registered and the feature has zero runtime cost.

New tools (6 total, all gated behind the setting)

Tool Purpose
team_create Create a named agent team
team_delete Tear down a team and clean up all resources
send_message Send a message to a specific teammate or back to the leader
task_create Post a task to the shared task board
task_update Claim a task, mark it completed, or update its status
task_list View all tasks and their current status

Common workflow

A typical agent team session follows this pattern:

  1. User asks for a complex task — e.g., "add input validation to all API endpoints and update the corresponding tests"
  2. Leader creates a team — calls team_create with a descriptive name
  3. Leader breaks work into tasks — calls task_create for each subtask (e.g., "validate /users endpoint", "validate /orders endpoint", "update user tests", etc.)
  4. Leader spawns teammates — uses the existing Agent tool to spawn teammates; each teammate gets an identity, a name, and a color for UI display
  5. Teammates self-organize — each teammate calls task_list to find pending tasks, claims one via task_update(status: "in_progress"), does the work, then reports results back to the leader via send_message
  6. Leader monitors and coordinates — receives teammate messages, reviews progress via task_list, and can post follow-up tasks or send instructions to specific teammates
  7. Cleanup — leader calls team_delete to shut down all teammates and clean up team state

Teammates can also communicate with each other via send_message, which is useful when one agent's findings affect another's work.

Architecture overview

  • TeamManager — central orchestrator that owns the backend, manages teammate lifecycle, and handles message routing with priority (leader messages are delivered before peer messages)
  • Mailbox — file-based message passing system (~/.qwen/teams/{name}/inboxes/); messages are persisted so they survive agent restarts
  • Task board — shared task tracker (~/.qwen/tasks/{name}/); tasks have statuses (pending → in_progress → completed) and dependency tracking (blocks/blockedBy)
  • Identity system — each teammate gets a unique ID (name@teamName), display name, and color; identity propagates through AsyncLocalStorage for in-process agents
  • Permission sync — when the leader approves a tool action (e.g., allowing file writes in a directory), that approval is propagated to all teammates, so the user isn't prompted repeatedly for the same permission
  • Leader permission bridge — teammates can escalate permission requests to the leader when they encounter actions that require user approval

Backend support

The existing agent backends are extended to support team-aware spawning:

  • InProcessBackend — teammates run as concurrent async tasks in the same process (current default)
  • TmuxBackend and iTermBackend — extended with the required interfaces but team spawning is not yet fully implemented (in-process is used as the runtime regardless of display mode)

Known limitations and pitfalls

  • Max 10 teammates per team. This is a hard cap (MAX_TEAMMATES = 10). Creating more will error. In practice, 2–4 teammates is the sweet spot — more agents means more coordination overhead.
  • Only the leader can spawn teammates. Teammates cannot spawn sub-teammates. This is enforced to prevent runaway agent trees.
  • In-process backend only. Teammates always run in-process regardless of the configured display backend. Tmux/iTerm pane-based teammates are a Phase 2 goal.
  • One team at a time. A session can only have one active team. Calling team_create while a team is already active will fail — you must team_delete first.
  • Teammates share the filesystem. All teammates operate on the same working directory (or a configured cwd). There is no file-level isolation between teammates — concurrent edits to the same file can conflict. The leader should assign non-overlapping file scopes to each teammate.
  • Message delivery is eventual. Messages are delivered when the recipient agent becomes idle (between tool calls). If an agent is mid-execution, messages queue and are flushed in priority order on the next idle cycle.
  • No conversation history for teammates. Teammates start fresh — they only see their system prompt and the initial task. They learn context through the task board and messages, not by reading the leader's conversation history.
  • Model costs scale linearly. Each teammate is a separate model session with its own context window. A team of 4 agents uses roughly 4x the tokens of a single agent.
  • The feature is experimental. The tool interfaces, task schema, and coordination protocol may change in future releases. Use in production workflows at your own risk.

Reviewer Test Plan

  1. Feature gate works:

    • Start a session without the setting/env var → confirm none of the 6 team tools appear in available tools
    • Enable via QWEN_CODE_ENABLE_AGENT_TEAM=1 → confirm all 6 tools appear
  2. Unit tests pass:

    cd packages/core && npx vitest run src/agents/team/
    cd packages/core && npx vitest run src/tools/team-create.test.ts src/tools/team-delete.test.ts src/tools/send-message.test.ts src/tools/task-create.test.ts src/tools/task-update.test.ts src/tools/task-list.test.ts src/tools/team-lifecycle.test.ts
  3. E2E smoke test (with feature enabled):

    • Ask the agent to do a task that benefits from parallelism (e.g., "create three utility functions in separate files")
    • Observe that the agent creates a team, spawns teammates, and coordinates work

Testing Matrix

🍏 🪟 🐧
npm run
npx
Docker
Podman - -
Seatbelt - -

Linked issues / bugs

No linked issues


🤖 Generated with Qwen Code

tanzhenxin and others added 7 commits April 4, 2026 15:57
…dination

Adds an experimental Agent Team feature that lets the lead agent spawn and
coordinate a team of sub-agents working in parallel on different parts of a task.

Key components:
- TeamManager: central orchestrator for teammate lifecycle and message routing
- Mailbox: file-based message passing system
- Task board: shared task tracker with status and dependency support
- Identity system: unique IDs, display names, and colors for teammates
- Permission sync: propagates leader approvals to teammates
- 6 new gated tools: team_create, team_delete, send_message, task_create, task_update, task_list

Feature is disabled by default and gated behind experimental setting or env var.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
useResultDisplayRenderer had no handler for TeamResultDisplay or
TaskListResultDisplay objects. In interactive mode, team_create and
team_delete returned {type, teamName, action} which fell through to
the default case casting it as string, crashing React with "Objects
are not valid as a React child."

Add explicit branch for team_result/task_list types and make the
default fallback safe with typeof check + JSON.stringify.
The test mock config was missing `getTeamManager` and
`onTeamManagerChange`, causing all 56 tests to fail with
"config.onTeamManagerChange is not a function".
# Conflicts:
#	packages/cli/src/nonInteractiveCli.ts
#	packages/core/src/tools/agent.test.ts
#	packages/core/src/tools/agent.ts
@BingqingLyu BingqingLyu added conflicting-group-1 conflicting-group-1 Conflicting PR group 1 — review as a batch conflicting-pr Shares at least one cross-PR dependency with other PRs and removed conflicting-group-1 labels May 7, 2026
@BingqingLyu

BingqingLyu commented May 7, 2026

Copy link
Copy Markdown
Owner Author

Conflict Group 1

This PR shares modified functions with 14 other PR(s): #106, #112, #113, #114, #117, #14, #17, #18, #36, #46, #6, #71, #86, #88.

These PRs should be reviewed as a batch — merging one may affect the others.

Function File Also modified by
consumePendingMemoryTaskPromises client.ts #114, #117
isSdkMcpServerConfig config.ts #106, #112, #113, #114, #117, #18, #46, #86, #88
loadCliConfig config.ts #106, #112, #113, #114, #117, #36, #46, #86, #88
normalizeConfigOutputFormat config.ts #106, #112, #113, #114, #117, #18, #86, #88
runNonInteractive nonInteractiveCli.ts #114, #14, #17, #6, #71
graph LR
    PR75["PR #75"]
    FconsumePendingMemoryTaskPromises_3380["consumePendingMemoryTaskPromises<br>client.ts"]
    PR75 -->|modifies| FconsumePendingMemoryTaskPromises_3380
    PR114["PR #114"]
    PR114 -->|modifies| FconsumePendingMemoryTaskPromises_3380
    PR117["PR #117"]
    PR117 -->|modifies| FconsumePendingMemoryTaskPromises_3380
    FisSdkMcpServerConfig_803["isSdkMcpServerConfig<br>config.ts"]
    PR75 -->|modifies| FisSdkMcpServerConfig_803
    PR106["PR #106"]
    PR106 -->|modifies| FisSdkMcpServerConfig_803
    PR112["PR #112"]
    PR112 -->|modifies| FisSdkMcpServerConfig_803
    PR113["PR #113"]
    PR113 -->|modifies| FisSdkMcpServerConfig_803
    PR114 -->|modifies| FisSdkMcpServerConfig_803
    PR117 -->|modifies| FisSdkMcpServerConfig_803
    PR18["PR #18"]
    PR18 -->|modifies| FisSdkMcpServerConfig_803
    PR46["PR #46"]
    PR46 -->|modifies| FisSdkMcpServerConfig_803
    PR86["PR #86"]
    PR86 -->|modifies| FisSdkMcpServerConfig_803
    PR88["PR #88"]
    PR88 -->|modifies| FisSdkMcpServerConfig_803
    FloadCliConfig_6977["loadCliConfig<br>config.ts"]
    PR75 -->|modifies| FloadCliConfig_6977
    PR106 -->|modifies| FloadCliConfig_6977
    PR112 -->|modifies| FloadCliConfig_6977
    PR113 -->|modifies| FloadCliConfig_6977
    PR114 -->|modifies| FloadCliConfig_6977
    PR117 -->|modifies| FloadCliConfig_6977
    PR36["PR #36"]
    PR36 -->|modifies| FloadCliConfig_6977
    PR46 -->|modifies| FloadCliConfig_6977
    PR86 -->|modifies| FloadCliConfig_6977
    PR88 -->|modifies| FloadCliConfig_6977
    FnormalizeConfigOutputFormat_803["normalizeConfigOutputFormat<br>config.ts"]
    PR75 -->|modifies| FnormalizeConfigOutputFormat_803
    PR106 -->|modifies| FnormalizeConfigOutputFormat_803
    PR112 -->|modifies| FnormalizeConfigOutputFormat_803
    PR113 -->|modifies| FnormalizeConfigOutputFormat_803
    PR114 -->|modifies| FnormalizeConfigOutputFormat_803
    PR117 -->|modifies| FnormalizeConfigOutputFormat_803
    PR18 -->|modifies| FnormalizeConfigOutputFormat_803
    PR86 -->|modifies| FnormalizeConfigOutputFormat_803
    PR88 -->|modifies| FnormalizeConfigOutputFormat_803
    FrunNonInteractive_8467["runNonInteractive<br>nonInteractiveCli.ts"]
    PR75 -->|modifies| FrunNonInteractive_8467
    PR114 -->|modifies| FrunNonInteractive_8467
    PR14["PR #14"]
    PR14 -->|modifies| FrunNonInteractive_8467
    PR17["PR #17"]
    PR17 -->|modifies| FrunNonInteractive_8467
    PR6["PR #6"]
    PR6 -->|modifies| FrunNonInteractive_8467
    PR71["PR #71"]
    PR71 -->|modifies| FrunNonInteractive_8467
Loading

Posted by codegraph-ai conflict detection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflicting-group-1 Conflicting PR group 1 — review as a batch conflicting-pr Shares at least one cross-PR dependency with other PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants