feat(ui): show Agent Team status in CLI and WebShell - #11072
Conversation
E2E test reportReal Agent Team run
The first model turn produced three invalid Automated checks
Prior CI failures
Windows and Linux manual UI runs remain out of scope. The PR stays Draft for review and the fresh CI run. |
🖼️ web-shell visual previewRendered against a mock daemon (no real backend): the PR base vs this PR head Screenshots · before / afterFull-resolution recordings (.webm) are attached to the workflow run. — Qwen Code · web-shell visuals |
|
|
Resolves the LiveAgentPanel import conflict introduced by #10957, which moved cli production files off the core root barrel. Keeps main's deep `subagents/builtin-agents.js` specifier and takes `AgentStatus` from `agents/runtime/agent-types.js` rather than re-adding a root-barrel import. Also converts this branch's new `use-team-agent-roster` module and its test to per-module core specifiers, for the same reason: a cli file that imports the package root costs about 11.5s of test collection, and no test mocks the core package here.
Two defects in the team roster this branch adds. `buildSessionAgentsStatus` awaited `listTasks` unguarded. That call throws on every readdir failure except ENOENT — by design, so a leader never mistakes an unreadable board for an empty one — which meant an EACCES or EIO on `~/.qwen/tasks/<team>` failed the entire `/session/:id/agents` response, hiding ordinary subagents and background tasks along with the team rows. The shared-task label is decoration on rows the route can still render, so it now degrades to no label. `useTeamAgentRoster` built its result in the render body, so it returned a new array on every render — including the `[]` for the no-team case, which every user hits. `LiveAgentPanel` keys its one-second elapsed-time interval on that array, so the interval was torn down and recreated on every render and, under render churn, never lived long enough to fire. Memoizing on the manager, the shared tasks, the registered agents, and the lifecycle-event revision restores a stable identity.
The multi-agent coordination page told users teammates are visible "through the existing Agent View UI" and stopped there. This branch adds a leader-facing roster in both surfaces, so the page now says where it appears, that idle is a distinct state from completed, that Enter opens the teammate's tab, and that Web Shell shows status plus approvals but keeps conversations in the CLI.
|
Thanks for the PR! Template is complete, including the Chinese mirror and a real reviewer test plan. ✓ Problem: A genuine product gap, not theoretical hardening — #11069 is open and asks for exactly this ("Show Agent Team teammates in the existing live agent roster"). The Why it's needed section makes the stronger case well: a roster alone would not be usable in Web Shell while teammate reports and approvals were still disconnected from the ACP session. Direction: Aligned. The design doc names the right precedent (Claude Code Agent Teams: compact lead-side roster, explicit idle, shared-task ownership, direct navigation) and — more importantly — reuses the surfaces that already exist instead of adding a second execution path: Size: Touches core paths ( Approach: The roster half is minimal and I would not cut anything from it. The part I would still question is the third commit, Risk: Stage 1e matched the One process note: the head moved twice while I was reviewing ( Moving on to code review. 🔍 中文说明感谢贡献!模板完整,包含中文对照和真实的 reviewer 验收计划 ✓ 问题: 这是真实的产品缺口,不是理论性加固 —— #11069 仍处于 open 状态,诉求正是「在现有 live agent roster 中展示 Agent Team 队友」。 方向: 对齐。设计文档给出了正确的参照(Claude Code Agent Teams:紧凑的 lead 侧 roster、显式 idle、共享任务归属、直接跳转),更关键的是它复用了已有界面,而不是新造第二条执行链路 —— CLI 行复用 规模: 触及核心路径( 方案: roster 这一半已经是最小实现,我不会砍任何东西。我仍想提出来讨论的是第三个 commit 风险: Stage 1e 命中了 一个流程说明:我在 review 期间 head 移动了两次( 进入代码审查 🔍 — Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
Code reviewNo Critical blockers. The implementation stays on the reuse path the design doc promises, and the two commits that landed mid-review ( I went in expecting four problems and all four turned out to be fine on inspection — recording them because they are the places a reviewer would otherwise spend time:
On the mid-review fix. Two non-blocking items:
Minor, take it or leave it: sequenceDiagram
participant P1 as Teammate
participant P2 as TeamManager
participant P3 as ACP Session
participant P4 as Notification queue
participant P5 as Web Shell leader
P1->>P2: report result to leader
P2->>P3: leader message callback
P3->>P4: enqueue teammate notification
P4->>P5: resume the idle leader turn
P5-->>P3: reconcile and continue
P1->>P2: tool call needs approval
P2->>P3: TEAMMATE_APPROVAL_REQUEST
P3->>P5: requestPermission, labelled with teammate
P5-->>P3: selected option
P3-->>P2: respond with outcome
Note over P3,P4: replacing or deleting a team aborts pending approvals and drops queued notifications
Files changed (29 of 42 shown)
Test evidenceThis is an unattended CI run, so I did not build or execute anything from this PR — the evidence below is the PR's own CI, read through the API. On the reviewed head The green set is more informative than it looks for this particular diff. Not verified — and this is the honest gap:
The cancelled unit lane is pre-existing infrastructure, not this PR. Two independent pieces of evidence, both from GitHub-set metadata and the repo's own workflow file rather than from log prose: Sandboxed verification would settle what neither the diff nor CI can. The central claims here are behavioural, the PR carries
中文说明代码审查没有 Critical 阻塞项。 实现严格走在设计文档承诺的「复用既有能力」路线上,review 期间落地的两个 commit( 我原本预判有四个问题,实际查证后都没问题 —— 记录下来是因为这些正是 reviewer 会花时间的地方:
关于 review 期间的修复。 两个非阻塞项:
一个很小的点,改不改都行: 测试证据这是一次无人值守的 CI 运行,所以我没有构建或执行本 PR 的任何代码 —— 下面的证据是通过 API 读取的本 PR 自己的 CI 结果。 在被 review 的 head 对这个 diff 来说,通过的那批检查比看上去更有信息量。 未验证 —— 这是诚实的缺口:
被取消的单元 lane 属于既有基础设施问题,不是本 PR 造成的。 两条独立证据,都来自 GitHub 设定的元数据和仓库自己的 workflow 文件,而不是日志正文: 沙箱验证可以解决 diff 和 CI 都解决不了的部分。这里的核心主张都是行为性的,PR 带着
Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 — Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
|
Confidence: 4/5 — the review came back clean and the one real defect I found was already fixed and test-pinned before I posted; the missing point is that the unit lane has never completed on this PR, so I cannot confirm the 791 test lines pass. Before reading the diff I wrote down what I would do myself: derive a display-only roster from the live What I would thank the author for in six months is the comments. The identity contract on the roster hook, why Stating my reservation plainly, because it is the whole reason this is 4 and not 5: So: no blocking findings, and I am not requesting changes. I am also not approving in this run, because the lane that would substantiate the behavioural claims is still in flight. Approval is deferred until CI lands green on The two non-blocking items from Stage 2 stand as questions, not conditions: whether the MCP-inheritance commit belongs in a separate PR, and whether a per-poll 中文说明Confidence: 4/5 —— review 结果是干净的,我找到的唯一一个真实缺陷在我发帖之前就已经被修复并用测试钉住了;扣掉的那一分在于单元 lane 在本 PR 上从未跑完,所以我无法确认那 791 行测试是通过的。 在读 diff 之前我先写下了自己会怎么做:在既有的 六个月后我会感谢作者的是那些注释。roster hook 的 identity 契约、 坦白说出我的保留意见,因为它正是这里是 4 分而不是 5 分的全部原因: 所以:没有阻塞性发现,我不会 request changes。我在这次运行中也不会 approve,因为能够为行为性主张提供支撑的那条 lane 仍在进行。approve 被推迟到 CI 在 Stage 2 里的两个非阻塞项作为问题保留,不是条件:MCP 继承那个 commit 是否应该拆成独立 PR,以及「只要 team 处于 idle 就每次轮询读一次 — Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
Durable agent identities that collaborate on a shared thread, as the substrate for multi-agent work that survives the process it started in. An Agent Team teammate is a live in-process loop: it receives messages at a tool-round boundary, and it dies with its leader, taking the conversation with it. A mesh agent is an identity whose work happens in a daemon session resumed when the agent is addressed, so the conversation is durable, visible to every participant, and replayable. The two are complementary — a team is still the right shape inside one run. This is the storage and rules layer only; nothing starts a session yet. Storage follows the durable scheduled-tasks file: per-project runtime dir rather than the working tree, atomic writes, and a corrupt file that throws instead of reading as empty. Thread text is written by one agent and fed to another, so keeping it out of the repo also keeps it from becoming a committed, pulled prompt-injection surface. The dispatch rules are the load-bearing part, and four of them are what Multica arrived at in `handler/comment.go`: coalesce a post into a run that has not started, defer when one is already executing, never let an author wake itself, and let an explicit mention take routing away from the assignee. The fifth is ours — a per-thread auto-turn budget, spent only by agent-authored posts and reset by a human one. Multica does not need it because its runs terminate and a person owns the issue; two mesh agents answering each other have nothing else to stop them. Posting and booking share one thread lock. Splitting them would let two concurrent posts each see "no queued run for Alice" and book two, which is the duplicate-dispatch race the Agent Team lifecycle audit found in leader assignment (#10207).
Adds the module map (what this branch landed vs what is still unbuilt), the end-to-end sequence, the full dispatch decision table with the reason each outcome exists, a demo script, and an explicit scope boundary. Section 9 lists the seven choices most likely to be wrong — session binding growth, thread-scoped rather than pair-scoped budget, deferred work stranded by a run that dies, best-effort concurrency counting, agent-to-agent prompt injection, silent retention trimming, and the missing cancellation path — so a reviewer does not have to find them. Also carries the earlier gap analysis that led here.
Added: agent mesh — storage and dispatch rules, plus the architecture for reviewThis PR now carries a second, larger piece of work alongside the Agent Team roster. Recording what changed and what to review. Why it is hereThe roster makes an in-session team visible. It does not make several agents collaborate durably — a teammate is a live in-process loop that dies with its leader, taking the conversation with it. The mesh is the substrate for the second thing: durable agent identities that collaborate on a shared thread, with each agent's work happening in a daemon session that is resumed when the agent is addressed. The two are complementary. Agent Team stays unchanged and remains the right shape for sub-turn collaboration inside a single run. What landedStorage and rules only — nothing starts a session yet.
Storage follows the durable scheduled-tasks file: per-project runtime dir rather than the working tree, atomic writes, and a corrupt file that throws instead of reading as empty. Thread text is written by one agent and fed to another, so keeping it out of the repo also keeps it from becoming a committed, pulled prompt-injection surface. Four of the five dispatch rules are what Multica arrived at in Still unbuiltThread tools ( What to review
Section 7 has the end-to-end sequence, section 8 the full decision table with the reason each outcome exists, and section 10 the demo script. |
Turns the earlier sketch into an implementable design. Two findings from reading the sources changed its shape. Multica's agents do talk in real time — it resumes the prior agent session (`daemon/types.go:110`) rather than rebuilding context, and dispatches over a WebSocket push (`daemon/wakeup.go`), so an @ to an idle agent starts it in about a second. Its one limitation is that a message cannot enter a run already executing. Qwen Code does not share that limitation: `resumeBackgroundAgent` queues into a running agent. The design takes the durable shared-thread model and keeps mid-run steering. The execution leg was wrong. An agent cannot be a daemon session carrying an agent definition's persona: that machinery targets the agent runtime, and there is no per-session persona hook to reuse. An agent is instead one long-lived background agent per workspace — where the persona, transcript, transcript viewer, wake-with-message, cross-restart revival, auto-compaction and approvals all already exist. The orchestration layer is the only thing that has to be written, and none of the reuse goes through Agent Team. Also records the four changes the settled decisions require in the code already on this branch, the four questions still genuinely open, and what is deliberately out of scope.
Re-reading the design as an implementer surfaced two mistakes. The wall-clock gate measured elapsed time from first dispatch, so a thread opened on Monday would already be over budget when revisited on Tuesday. Elapsed time is not cost; a stuck run is the sweeper's job, not the budget's. Removed, leaving turns and tokens. `maxConcurrentRuns` contradicted the decisions above it: one long-lived body per agent, serial across threads, already caps an agent at one running run. The field was dead and `defer: agent_at_capacity` collapses into `defer: busy_elsewhere`. Both dropped. The prompt was one line — "thread context plus new posts" — for the part that decides whether any of this works. Now specified: an explicit thread frame on every wake (a long-lived cross-thread body makes confusion a certainty, not a risk), mention tokens handed over verbatim rather than guessed, whole thread on first entry with an honest truncation notice after that, and thread tools that take no thread id from the model — resolved from ambient context the way Agent Team resolves teammate identity, so a confused agent cannot post into an unrelated thread. Also records the comparison against Multica: ahead on mid-run steering, deliberately without code changes and multi-user features, and genuinely missing runtime binding. Roughly 35-40% of Multica as a product, most of the remainder being a server-product category difference rather than a backlog; roughly 80% of multi-agent collaboration itself.
Read as someone picking it up cold, the document had four gaps. The worst was silent: it read as an established design, while the code on this branch has never been built, type-checked, or executed — builds and test sweeps are not run on this machine, and CI on this PR will be the first thing to run any of it. A reader would reasonably have assumed a verified foundation and built on top. Section 0.2 now separates what was verified by reading source, what was written but never run, and what has never been prototyped end to end, and names the two claims that would collapse decisions 6 and 9 if they turn out wrong. It also had no order of work, no acceptance criteria, and no way for a reader to re-check the Multica claims independently. Sections 5.2 and 5.3 add a dependency-ordered sequence and the coverage expected at each step; 0.2 names the repo, the commit, and the symbols to argue from — an earlier version of this design was wrong about Multica precisely because it reasoned from documentation rather than those files.
Step 1 of the implementation order: the rules on disk now match the design rather than contradicting it. Applying the decisions removed two things rather than adding them. `maxConcurrentRuns` was dead on arrival — one long-lived body per agent, serial across threads, already caps an agent at one running run, so what needs bounding is the backlog behind it, and that is now `queueLimit`. The wall-clock budget measured elapsed time from first dispatch, which would have refused a thread opened on Monday and revisited on Tuesday; elapsed time is not cost, and a hung run belongs to the stall sweeper. Writing it also surfaced a design error worth naming. The `defer` class of outcomes put a scheduling decision inside a rules function: whether a booked run can start depends on what the agent's single body is doing, which is the dispatcher's business, not a rule. The rules now only book, coalesce, or refuse, and a run that cannot start yet is simply a queued run. That also collapses "busy on this thread" into a coalesce, which is correct — mid-run delivery is available here, so a second run would be waste. This is the case Multica has to defer and we do not. Budgets are evaluated against the thread tree's root, inherited at creation rather than resolved by walking parents, so splitting work into sub-threads cannot mint allowance. Tokens are charged from each run's usage delta and, unlike turns, are never reset by a human post: turns measure how long a conversation has run unattended, tokens measure money already spent. Still never executed — see the plan's §0.2.
Source-backed review of 2026-09-06-multi-agent-board-collaboration.md at af7fed7. Records the runtime seams the implementation must not re-derive, findings by severity, the minimal change set, and the checks that only an end-to-end run can settle. Nothing here was built or executed.
Design review, round 2 — hand-off committedSource-backed review of
Nothing in it was built or executed; every claim carries a Verdict: keep the root model, change the contract. Three Critical items:
Also recorded: the seven The doc has ten Important findings, a minimal change set in order, and six checks that only an end-to-end run on a build-capable machine can settle (with the C1/C2 reproductions as items 3 and 4). Three items are product decisions for the owner, not the implementer: envelope role (C3), whether a parent agent may post into a child thread it created (I3), and which blockers a human |
|
Scope note after the split: this PR is the Agent Team roster/status work only. The shared-thread mesh subsystem, its design doc, the round-2 review hand-off, and the per-step acceptance criteria all live in #11206, which is the single mesh PR. #11140 remains stacked on this branch until #11206 step 9 absorbs the sidebar entry. |
…er-web-shell # Conflicts: # packages/cli/src/acp-integration/session/Session.test.ts
|
Correction to the earlier handoff: the mesh design, foundation fixes, and shared agent-runtime fixes are now integrated directly into this PR. This PR is the canonical relay branch again; the follow-up PRs remain drafts only as review checkpoints. Current head: dce16b4. |
doudouOUC
left a comment
There was a problem hiding this comment.
Review — head dce16b4c, base main (draft)
+4 999 / −141 across 69 files. Author is a repository admin, so the two-tier core gate does not block; the non-blocking size advisory applies. Core-infrastructure surface touched: packages/core/src/agents/**, packages/core/src/tools/**, packages/core/src/services/**, plus packages/cli, packages/web-shell, packages/acp-bridge, packages/sdk-typescript — genuinely cross-package. No local test run.
Web Shell conventions: no violations found. I checked specifically, since this touches web-shell UI. No new component is introduced, no portal surface is added, and nothing new receives or forwards a ref, so the forwardRef and useWebShellPortalRoot() requirements do not come into play. Existing data-web-shell-* attributes and CSS variables are untouched.
Critical — duplicate task rows and duplicate React keys on the team-match arm
In packages/web-shell/client/App.tsx, the liveAgents.find(...) predicate has five arms. The last one is guarded against re-claiming a task:
(!seenTaskIds.has(task.id) &&
!isPreciselyClaimed(task) &&
matchesLiveTaskContent(task)),The team arm immediately above it is not:
(task.teamName != null &&
subagentName != null &&
task.label === subagentName) ||task.label === subagentName is not a unique match — it is the whole point of a team roster that the same named agent can be invoked more than once. Two distinct tool calls with the same subagentName pass the seenToolCallIds filter (their callIds differ), both resolve to the same live task, and both agents.push({ ...liveTask, toolUseId: tool.callId, ... }) — producing two entries carrying the identical liveTask.id.
seenTaskIds.add(liveTask.id) runs after the push, so it does not prevent the second match; and the reconciliation pass at the bottom (seenTaskIds.has(task.id) || ... alreadyListed) only guards live tasks that were never matched, not duplicates already in agents.
Consumers key on id:
packages/web-shell/client/components/panels/EnvironmentPanel.tsx:352—<li key={task.id}>packages/web-shell/client/components/artifacts/AgentWorkflow.tsx:193and:209—key={task.id}
So this is a duplicate visible row plus a React duplicate-key collision, which will also make state on those rows behave unpredictably across re-renders. Adding the !seenTaskIds.has(task.id) conjunct to the team arm — matching the arm below — looks sufficient.
Suggestions
1 372 lines of agents/mesh/** are unreachable at this SHA. Nothing in that directory is exported from packages/core/src/index.ts, so no consumer outside the package can reach it and it has no in-package production call site. I assume it is being staged ahead of the codex/mesh-step-* series landing, which is reasonable — but shipping it inside an agent-team UI PR makes both halves harder to review, and it inflates the size advisory above with code that cannot be exercised. Splitting it out would help.
Team rows' runtimeMs grows without bound. Rows constructed from a live team task never receive an endTime, so the elapsed computation keeps climbing after the agent is done. The tool-derived branch handles this correctly (tool.endTime ?? tool.startTime ?? startTime); the team branch inherits ...liveTask and has no equivalent.
The 3-second agents poll never quiesces. idle is a steady state rather than a terminal one, so the backoff condition is never satisfied and the poll runs for the life of the session. On an idle session that is pure overhead.
liveAgentEntries? is a dead optional. It is declared optional and read in four places with ?? … fallbacks, but no caller omits it, so all four fallbacks are unreachable. Either make it required or populate it from a path that legitimately can't supply it.
Verdict
C=1, four Suggestions. The Critical is a small fix; the unreachable-mesh point is the one I'd act on before asking anyone else to review this, since it is a third of the non-test diff. Limitations: no local test run, and I did not exercise the UI in a browser, so the duplicate-row consequence is derived from the code and the key sites rather than observed.
doudouOUC
left a comment
There was a problem hiding this comment.
Agent-assisted review at 088a990b6f61610ca6222967058401885b2c3c4a — 1 confirmed standing Critical; Partial review — coverage gaps.
Pinned base: 4dbfc0c1c1a40f59ceee76bac5477daddc646d9c. This is the current 70-file scope, including the mesh foundation, not the narrower roster-only scope described in some older comments.
Critical — prior duplicate teammate row/key finding still stands
packages/web-shell/client/App.tsx:2541-2551 still lets the team-name arm match a task without checking seenTaskIds. Given two transcript agent calls with distinct call IDs but args.name: 'reviewer', and one live team row labelled reviewer, both calls find that same row. :2567-2578 spreads its same id into both output entries. Recording the ID at :2599 does not help because this arm never reads it; the final reconciliation loop only prevents appending an additional unmatched task.
The result is two visible entries with the same ID, used as React keys in components/panels/EnvironmentPanel.tsx:351-352 and components/artifacts/AgentWorkflow.tsx:191-209. Trace merging is not a universal cure: App.tsx:2631 preserves the array when no trace is available, and trace fetching is conditional on the workflow tab/capability (:6812-6819). This is the same mechanism reported in review 5168484994, not a new independent finding.
Ensure one live task is claimed at most once, including the name-match arm. Extend the existing single-launch test (App.test.tsx:7738-7785) with two different call IDs sharing the teammate name and assert unique result IDs. The defect is established by the producer/consumer trace, not by missing tests alone.
Other checked surfaces and limits
Read the roster projection and memoized CLI roster hook, teammate permission/notification lifecycle, MCP-definition forwarding and per-agent discovery, resident-continuation result consumers, and selected permission/roster tests. Team status remains live-session/Config-owned through the existing agents snapshot; this PR does not add a new daemon route. The new continuation result is compared explicitly by send-message.ts, rather than treating every nonempty string as success.
Historical mesh notes require care: the current usage event uses cumulative rounds (agent-core.ts:1198-1210), and resident continuation already emits EXTERNAL_MESSAGE (agent-headless.ts:279-288); the original claim that those prompts were never transcripted is not supported. Delivery IDs now pass through to transcript records. The proposed trusted-envelope role is still documented as an open product decision, not an implemented dispatcher guarantee.
Coverage gaps: full mesh storage/locking/retention and dispatch-rule audit, all mesh design decisions, every changed test body, complete UI/platform behavior, and exhaustive downstream optional-field consumers. Pinned-source search finds only intra-mesh production imports; no integrated dispatcher was established. This is not a full pass on that foundation or a statement that all design Criticals are resolved. Prior size/polling/elapsed-time/dead-optional Suggestions are not converted into blockers or repeated as new findings.
No PR code, tests, builds, installs, or workflows executed. Author maintainer status was not independently verified; feature size is advisory, not an external-refactor policy block. Comment only; no approval implied.


What this PR does
This PR adds a leader-facing Agent Team roster to the existing CLI live-agent panel and projects the same team state into WebShell's environment and workflow views. Teammates retain their own lifecycle semantics: idle remains distinct from completed, current shared-task ownership is visible, and pressing Enter on a CLI teammate row opens the teammate's existing Agent tab.
It also completes the
qwen servecoordination path. An idle WebShell leader now resumes when a teammate reports, teammate tool approvals use the existing WebShell permission dialog, and replacing or deleting a team detaches its callbacks, cancels pending approvals, and discards queued notifications. Named Agent launches retain the teammate name through the daemon transcript so WebShell merges the launch entry with the live team entry instead of showing duplicates. A teammate launched from an Agent definition now inherits and discovers that definition's MCP servers in its isolated runtime.Why it's needed
Agent Team already supports independent teammate loops, shared tasks, mailbox messaging, approvals, and dedicated Agent tabs, but the leader had no glanceable view of who was active, idle, or working on which task. In WebShell, teammate reports and approvals were also not connected to the ACP session, so displaying a roster alone would not have produced a usable team workflow.
Reviewer Test Plan
How to verify
qwen servewith Agent Team enabled and open its WebShell in a fresh browser tab.Evidence (Before & After)
Before: teammates were visible only through their dedicated CLI Agent tabs. WebShell omitted live team state, did not resume the leader from teammate reports, and did not route teammate approvals through its permission dialog.
After: the CLI roster and WebShell environment/workflow views show current team state. Real tmux-hosted
qwen serveruns created named teammates, showed one row per teammate in Chrome, automatically resumed the leader from teammate reports, and cleaned up the team. A teammatewrite_filerequest appeared as a teammate-labelled WebShell approval; rejecting it left the target file absent. A teammate launched from an Agent definition called its private stdio MCP tool, returnedMCP_TEAM_PROOF:REAL_TEAM_MEMBER, and left no MCP child process after team deletion.Tested on
Environment (optional)
Node.js 22, local package builds, tmux-hosted
qwen serve, and Chrome WebShell with a configured live model.Risk & Scope
Linked Issues
Closes #11069
中文说明
本 PR 做了什么
本 PR 在现有 CLI 实时 Agent 面板中加入面向 Leader 的 Agent Team 成员列表,并把相同的团队状态投影到 WebShell 的环境与工作流视图中。队友保留独立的生命周期语义:idle 与 completed 明确区分,可以看到当前负责的共享任务,在 CLI 队友行上按 Enter 会打开该队友已有的 Agent 标签页。
它同时补齐了
qwen serve的协作链路。WebShell Leader 处于空闲状态时,现在会在队友报告后自动恢复;队友工具审批复用现有 WebShell permission dialog;Team 被替换或删除时会解绑回调、取消待处理审批并丢弃旧 Team 的排队通知。具名 Agent 启动会通过 daemon transcript 保留队友名,因此 WebShell 会把启动条目与实时团队条目合并,不再显示重复行。通过 Agent 定义启动的队友会在隔离运行时中继承并发现该定义声明的 MCP Server。为什么需要它
Agent Team 已经支持独立的队友循环、共享任务、邮箱通信、审批和专属 Agent 标签页,但 Leader 缺少一个可以快速查看谁在运行、谁处于 idle、谁在负责哪个任务的入口。在 WebShell 中,队友报告和审批此前也没有连接到 ACP Session,因此只展示 roster 并不能形成可用的团队工作流。
Reviewer 验收计划
如何验证
qwen serve,并在全新浏览器标签中打开 WebShell。证据(修改前与修改后)
修改前:队友只能通过各自的 CLI Agent 标签页查看。WebShell 不展示实时 Team 状态,不会因队友报告自动恢复 Leader,也不会把队友审批路由到 WebShell permission dialog。
修改后:CLI roster 与 WebShell 环境/工作流视图会展示当前 Team 状态。真实 tmux
qwen serve运行创建了具名队友,在 Chrome 中每个队友只显示一行;队友报告后 Leader 自动恢复并清理 Team。另一次真实队友write_file请求以带队友名的 WebShell 审批出现,拒绝后目标文件不存在。通过 Agent 定义启动的队友调用了其私有 stdio MCP 工具,返回MCP_TEAM_PROOF:REAL_TEAM_MEMBER,删除 Team 后没有残留 MCP 子进程。已测试平台
环境(可选)
Node.js 22、本地 package 构建、tmux 中运行的
qwen serve,以及连接已配置真实模型的 Chrome WebShell。风险与范围
关联 Issue
Closes #11069