feat(web-shell): show sub-agents as a chronological transcript with a parallel-agent timeline - #6772
Conversation
… parallel-agent timeline Replace the sub-agent panel's Result/Tools tabs with a single chronological view: the conclusion first, then the steps that produced it on a stepped rail, so a sub-agent reads as the nested conversation it is rather than two disjoint tabs the reader has to flip between. While the agent is still running there is no conclusion yet, so the step list pins to the newest call and the live stream tails it. The step list keeps its own scroll cap so the conclusion stays in view instead of the panel growing past a screen. Give the parallel-agents group a shared-axis mini timeline: one bar per agent laid out against the group's combined wall-clock span, so overlap, relative duration, and which agents are still running read at a glance instead of a flat list with no time information. A running bar animates a pulsing leading edge; a ruler with nice tick steps sits below and hides on narrow panels via a container query, where the bars still carry the relationships and each row keeps its absolute numbers. The layout falls back to the plain list when the bars would not be comparable — an agent without a start time, a single agent, or a sub-second span.
|
Thanks for the PR! Template looks good ✓ — all required sections present with bilingual detail. Problem: This is a UX improvement, not a bug fix. The PR makes a clear case that the current tab-based presentation of sub-agents fragments the narrative — you can't see the conclusion and the steps that produced it simultaneously. The before/after screenshots demonstrate the improvement concretely. Appropriate for a feature PR. Direction: Aligned. The CHANGELOG shows the web-shell is an actively developed surface (10+ web-shell PRs in recent history). Sub-agent visualization falls squarely within the product's scope — the CLI itself renders sub-agents as nested conversations, so making the web-shell do the same is natural. No direction concerns. Size: 6 files, ~362 production logic lines (CSS + TSX), ~162 test lines. All within Approach: The scope feels right — two focused components (SubAgentPanel chronological layout, ParallelAgentsGroup mini timeline) with no unrelated changes. The tab removal is the minimal change needed; the timeline is a reasonable addition with clean fallback logic (null for single agents, sub-second spans, or missing start times). Container query for narrow panels is the right primitive. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ — 所有必需部分齐全,含中英双语详情。 问题: 这是 UX 改进而非 bug 修复。PR 清楚说明了当前标签页式的子代理展示如何割裂了叙事——结论和产出它的步骤无法同时看到。before/after 截图具体展示了改进效果。作为 feature PR 合理。 方向: 对齐。CHANGELOG 显示 web-shell 是活跃开发的界面(近期 10+ 个 web-shell PR)。子代理可视化属于产品核心范围——CLI 本身就将子代理渲染为嵌套对话,web-shell 做同样的事很自然。无方向顾虑。 规模: 6 个文件,~362 行生产逻辑代码(CSS + TSX),~162 行测试代码。全部在 方案: 范围合理——两个聚焦的组件改动(SubAgentPanel 时间线布局、ParallelAgentsGroup 迷你时间线),无无关变更。移除标签页是所需的最小改动;时间线是合理的添加,有干净的降级逻辑(单个代理、不足一秒的跨度、缺少起始时间时返回 null)。窄面板用容器查询是正确的原语。进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewI read the PR's "Why it's needed" and independently proposed: remove the tab split, render the conclusion at the top with a "Result" caption, then the sub-tool list as a chronological step rail below (dots + connecting lines, colored by status), both in a single scroll-capped column. For parallel agents, compute each agent's bar position as a percentage of the group's combined wall-clock span, render with CSS The PR's implementation matches this proposal closely — and goes further with a few polished details: the No critical issues found. The geometry math in The diff is minimal and focused — no drive-by refactors, no scope creep. The CSS uses modern primitives correctly ( Reuse check: TestingThis is a web-shell React component change — tmux CLI testing doesn't apply (no terminal rendering involved). Verified with unit tests, typecheck, and lint instead. Full web-shell suite: Typecheck and lint both clean — no errors, no warnings. 中文说明代码审查我阅读了 PR 的"为什么需要"部分,独立提出了方案:移除标签页分割,结论置顶并标注"Result",子工具列表以时间线竖轨(圆点 + 连接线,按状态着色)排列在下方,整体在一个有滚动上限的列中。对于并行代理,计算每个代理横条在组合墙钟跨度中的百分比位置,用 CSS PR 的实现与此方案高度一致——还多了几个打磨细节:脉冲动画的 未发现关键问题。 diff 最小化且聚焦——无顺手重构、无范围蔓延。CSS 正确使用现代原语( 复用检查: 测试这是 web-shell React 组件变更——tmux CLI 测试不适用(不涉及终端渲染)。通过单元测试、类型检查和 lint 验证。 完整 web-shell 测试套件: 类型检查和 lint 均通过——无错误、无警告。 — Qwen Code · qwen3.7-max |
|
This PR does one thing well: it turns the sub-agent panel from a tab-split view into a single chronological narrative, and adds a parallel-agent timeline that actually communicates concurrency. The implementation is clean — focused diff, correct geometry math, graceful degradation, and thoughtful CSS. The I independently proposed the same approach and the PR exceeds it with polished details (reduced-motion guard, sliver clamping, nice-number ticks). 1551 tests pass, typecheck and lint are clean. No critical issues in code review. The problem is real — you genuinely can't see a sub-agent's conclusion and the steps that produced it at the same time in the current UI. The fix is minimal and focused. LGTM, approving. ✅ 中文说明这个 PR 做好了一件事:将子代理面板从标签页分割视图改为单一时间线叙事,并为并行代理添加了真正能传达并发性的时间线。实现干净——聚焦的 diff、正确的几何计算、优雅的降级、用心的 CSS。 我独立提出了相同方案,PR 在此基础上增加了打磨细节(减弱动画守卫、片段钳位、美数刻度)。1551 个测试全部通过,类型检查和 lint 均干净。代码审查未发现关键问题。 问题是真实的——在当前 UI 中确实无法同时看到子代理的结论和产出它的步骤。修复最小化且聚焦。 LGTM,批准。✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
| {stats && <span className={styles.rowStats}>{stats}</span>} | ||
| </div> | ||
| {track && ( | ||
| <div className={styles.track} aria-hidden="true"> |
There was a problem hiding this comment.
[Suggestion] The computeAgentsTimeline pure function has strong unit test coverage, but the component that consumes it has no render tests. The track/bar DOM (here) and the ruler (below, gated on ticks.length >= 2) are never asserted at the component level. A shallow render test would catch regressions where timeline data is computed but never reaches the DOM.
— qwen3.7-max via Qwen Code /review
| })} | ||
| </div> | ||
| {timeline && timeline.ticks.length >= 2 && ( | ||
| <div className={styles.ruler} aria-hidden="true"> |
There was a problem hiding this comment.
[Suggestion] The ruler is guarded by timeline.ticks.length >= 2 but no test asserts the ruler is absent when fewer than 2 ticks are produced (e.g., a very short span just above 1 second). This threshold-based rendering is easy to break during refactors.
— qwen3.7-max via Qwen Code /review
| : styles.tools | ||
| } | ||
| > | ||
| <div ref={windowRef} className={`${styles.tools} ${styles.scrollWindow}`}> |
There was a problem hiding this comment.
[Suggestion] The diff removes the compactThinking conditional from SubAgentTools — scrollWindow is now always applied. This is a behavioral change, but no test verifies the new unconditional scroll-capping behavior. Consider adding a test that asserts the scroll window class is present regardless of compactThinking.
— qwen3.7-max via Qwen Code /review
|
|
||
| {!isComplete && tool.subContent && ( | ||
| <div className={styles.content}> | ||
| <SubAgentStream text={tool.subContent} /> |
There was a problem hiding this comment.
[Suggestion] <SubAgentStream> is rendered only when !isComplete && tool.subContent, but the existing tests only cover the positive case (running agent shows stream). There is no test confirming that a completed agent with subContent does not render the stream — this is the key invariant of the conclusion-first layout.
— qwen3.7-max via Qwen Code /review
…variant Addresses the review's coverage suggestions. Adds component-level render tests for the parallel-agents timeline — a bar per agent reaches the DOM, the ruler renders with its nice ticks when the span is comparable, drops out when the span yields a single tick, and no timeline renders at all when the bars would not be comparable — plus a pure-function assertion that a span barely over one second produces a single tick (the ruler's threshold). For the sub-agent panel, asserts that a completed agent surfaces its stream text as the conclusion rather than the live stream, that the live stream is present while running, and that the step list carries its scroll cap regardless of compact-thinking.
|
Thanks for the review — all four were valid coverage gaps (the pure
中文说明四条建议都成立(纯函数
|
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
The tab-based SubAgentPanel has been cleanly replaced with a single chronological narrative (conclusion → step rail → live stream), and the new pure function is well-tested across the null-fallback cases, the bar geometry math, the nice-number tick selection, and the ruler gate. The four earlier Suggestions about missing render-test coverage are all addressed in 785031f (suite goes from 12 to 18 tests, all green).
— qwen3.7-max via Qwen Code /review
yiliang114
left a comment
There was a problem hiding this comment.
LGTM. Clean presentation-layer change — the chronological single-view is a clear improvement over the split tabs, and the shared-axis timeline for parallel agents makes concurrency actually visible. computeAgentsTimeline is nicely factored as a pure function with well-covered edge cases.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
| position: absolute; | ||
| left: 5px; | ||
| top: 16px; | ||
| bottom: -8px; |
There was a problem hiding this comment.
[Suggestion] The vertical connector line (.step:not(:last-child)::after) uses bottom: -8px, but the parent .tools has gap: 6px and the next step's dot starts at top: 7px. The connector only penetrates 2px into the next step's space (8 − 6 = 2), leaving a ~5px gap between the line and the next dot. The rail appears broken between every pair of steps.
Consider increasing bottom to approximately -14px (gap 6 + dot top 7 + 1) so the connector visually reaches the next dot.
— qwen3.7-max via Qwen Code /review
| itemCount={tool.subTools.length} | ||
| > | ||
| {tool.subTools.map((sub) => ( | ||
| <div |
There was a problem hiding this comment.
[Suggestion] Both tool.subTools.map and taskToolCalls.map (below at line ~365) wrap each child in identical boilerplate:
<div key={...} className={styles.step} data-status={...}>
<ChildComponent />
</div>A small wrapper component (e.g., StepItem({ callId, status, children })) would eliminate the duplication and give the step-rail pattern a single place to evolve.
— qwen3.7-max via Qwen Code /review
| }); | ||
|
|
||
| describe('ParallelAgentsGroup timeline rendering', () => { | ||
| it('renders one bar per agent and a ruler when the span is comparable', () => { |
There was a problem hiding this comment.
[Suggestion] Several specific code paths introduced in this PR lack test coverage:
- The
barRunningCSS class is never exercised in a DOM rendering test — all timeline render tests use only completed agents - The
data-statusattribute on step elements is never asserted, even though the CSS rail coloring depends entirely on it - A completed agent with
endTimeundefined (the?? starts[i]fallback incomputeAgentsTimeline) is not tested - No test uses a
failedagent with both result and tools to exercise theshowSectionCapspath - The
taskToolCallsrendering path (fromrawOutput.toolCalls) through the step wrapper is never tested — all SubAgentPanel tests usesubTools
Each is a narrow gap, but together they leave the new chronological layout's status-dependent styling and edge cases unverified.
— qwen3.7-max via Qwen Code /review
What this PR does
Reworks how sub-agents are displayed in the Web Shell transcript. A single sub-agent no longer splits its output across Result / Tools tabs — it now renders as one chronological view: the conclusion first, then the steps that produced it on a stepped rail, reading like the nested conversation it actually is. While the agent is still running there is no conclusion yet, so the step list pins to the newest call and the live stream tails below it. The step list keeps its own scroll cap so the conclusion stays in view rather than the panel growing past a screen.
A group of parallel sub-agents gains a shared-axis mini timeline: one bar per agent laid out against the group's combined wall-clock span, with a ruler beneath it. A running agent's bar animates a pulsing leading edge. The whole treatment degrades gracefully — the ruler hides on narrow panels (split view, mobile) via a container query while the bars keep the relationships and each row keeps its absolute numbers, and it falls back to the previous plain list whenever the bars would not be comparable (an agent with no start time, a single agent, or a sub-second span).
Why it's needed
A sub-agent is a nested mini-conversation — thinking, a sequence of tool calls, then a conclusion — but the previous panel presented it as a tool with two disjoint tabs, so you could never see how a conclusion was reached without flipping to another tab and back. And a group of parallel agents rendered as a flat list carried no time information at all, so the one thing worth conveying — that the agents ran concurrently, who overlapped whom, who is still running — was invisible. This change makes both read at a glance.
Reviewer Test Plan
How to verify
In the Web Shell, run a prompt that delegates to a sub-agent (the Task tool) and expand it: the conclusion sits at the top under a
Resultcaption, with the tool calls that produced it listed below underTools (N)on a stepped rail (dots colored by status — a failed step shows red). There are no Result / Tools tabs. While it is still running, expand it mid-flight: the step list follows the newest call and the live stream tails beneath it, with no captions (there is no conclusion yet).Run a prompt that spawns several sub-agents concurrently and expand the "Parallel agents" group: each row now has a bar on a shared time axis, a still-running agent's bar has a pulsing edge, and a ruler sits below. Narrow the panel (open the split view, or shrink the window): the ruler disappears while the bars remain and each row keeps its
Ns · Nknumbers.Unit tests:
cd packages/web-shell && npx vitest run client/components/messages/tools/SubAgentPanel.test.tsx client/components/messages/tools/ParallelAgentsGroup.test.tsx— covers the completed conclusion+steps layout, the running steps+stream layout, and the timeline geometry (span/overlap math, near-instant sliver clamping, nice ruler ticks, and the null-fallback cases).Evidence (Before & After)
Light
Dark
Rendered from the components' real DOM and the shipped
*.module.cssrules against the app's real theme tokens; the narrow-panel container-query behavior (ruler hides, bars remain) was asserted programmatically.State coverage (running, failed step, narrow panel)
The before/after above shows the completed sub-agent and the wide parallel group; these cover the remaining states — a sub-agent still running (steps pinned to the newest call, live stream tailing below, no captions), a failed step (red rail dot), and a parallel group in a narrow panel where the ruler drops out while the bars stay.
Light
Dark
Tested on
Environment (optional)
Unit tests + visual verification via Playwright/Chromium. Not exercised against a live daemon; the changes are presentation-only in the message renderer.
Risk & Scope
Linked Issues
N/A — originated from an internal review of the SubAgentView display.
中文说明
这个 PR 做了什么
重构 Web Shell 里子代理(sub-agent)的展示方式。
① 单体子代理:不再用 Result / Tools 标签页把输出切成两半,改为一条时间线叙事——结论置顶,下面是产出该结论的步骤,沿一条带圆点的竖轨排列,读起来就是它本来的样子:一段嵌套的小对话。运行中还没有结论,此时步骤列表钉住最新一步、实时流跟在末尾。步骤列表有独立的滚动上限,所以结论始终留在视野内,面板不会越长越高超出一屏。
② 并行子代理:为并行代理组加了共享时间轴的迷你时间线——每个代理一条横条,按整组的合并墙钟跨度布局,下方配刻度尺;运行中的代理横条有脉冲端点。整体平滑降级:窄面板(分屏、移动端)用容器查询隐藏刻度尺、保留横条(横条承载重叠与相对时长,每行仍有绝对数值);当横条无法比较时(某代理无开始时间、只有单个代理、或跨度不足 1 秒)回退为原来的纯列表。
为什么需要
子代理本质是一段嵌套的小对话(思考 → 一串工具调用 → 结论),但原面板把它当成带两个割裂标签页的工具,看结论时无法同时看到它是怎么得出的。并行代理组渲染成纯列表则完全没有时间信息,最该传达的「它们在并行、谁和谁重叠、谁还在跑」反而不可见。本次改动让两者都一目了然。
验证要点
Result标题下置顶,产出它的工具调用在Tools (N)下沿竖轨列出(圆点按状态着色,失败步骤为红色),没有标签页。运行中展开:步骤跟随最新一步、实时流跟在下方,无分节标题。Ns · Nk数值。cd packages/web-shell && npx vitest run client/components/messages/tools/SubAgentPanel.test.tsx client/components/messages/tools/ParallelAgentsGroup.test.tsx。风险与范围
纯展示层改动,仅限两个消息渲染组件;无数据模型/协议变更(子代理的子工具、结果、各代理起止时间均已有数据)。复用现有 i18n key,无需新翻译。未做实时 daemon 端到端验证;深层子代理嵌套沿用现有竖轨、未单独压测。