Repository navigation
feat(web-shell): show the trajectory over real time, idle included - #12607
Conversation
…and say an empty selection once
|
Thanks for the review. CI landed green on
The new head needs CI again, so the deferred approval will re-evaluate on |
|
@qwen-code /triage |
yiliang114
left a comment
There was a problem hiding this comment.
LGTM at 971ef82. CI green and settled on this head (11 lanes, 0 pending, 0 failed), zero open threads. Requested by maintainer.
qwen-code-dev-bot
left a comment
There was a problem hiding this comment.
APPROVE at 971ef82.
- Head re-verified immediately before submitting: 971ef82, OPEN and mergeable. Every check context carries a success, with review-pr excluded as reviewer-bot infrastructure per my standing disclosure. No prior review and no inline thread.
- No new Critical. This adds a second time axis to a strip whose first axis is already shipped, so I read it for the two ways adding a mode usually goes wrong: the new mode disturbing the old one, and a selection or a label surviving a switch that invalidates it.
- The existing axis is untouched by construction rather than by care. The mode is an option defaulting to active, the shift accumulator advances only in active mode while clock mode merely sums the gaps, and a test asserts the active axis stays as it was, so the default cannot drift because someone tuned the new mode.
- The label and the axis cannot disagree, which is the invariant worth having here. The strip reads the mode off the model instead of off a second prop, and the docblock on the mode-change callback states the reason. A component that accepted the mode twice could announce real time while drawing compressed time.
- Selection invalidation was extended instead of left behind. The stored selection carries the mode alongside the window it was drawn on and is honoured only while both still match, so switching axes lapses a selection in the same render rather than filtering the new axis by numbers taken from the old one. The comment keys that on the inputs to the axis rather than on the memoised axis itself, because React keeps a memo identity as an optimisation and not as a promise, which is the correct reason and an easy one to get wrong.
- An empty selection is an answered question rather than a blank table. A stretch dragged across idle time in real-time mode finds no rows, the panel says so in words with the way back beside it, and the comment records why it is deliberately not a live region: the header row count changes in the same render and two announcements would say the same thing twice.
- The numbers the new mode introduces are computed and pinned rather than assumed. Active time is the domain minus the idle total clamped at zero, and a test asserts that parallel and overlapping calls count once towards it, which is exactly where a naive gap sum double-counts. The origin is the earliest drawn start after sorting, pinned by a test that feeds rows out of order, and rows with no recorded start are still never drawn in either mode.
- The clock formatter carries the two tests I would have asked for, as many fractional digits as the window needs and the first hour after midnight reading as 00 rather than 24, and coverage reaches the precision risk a wall-clock axis introduces: a short call placed exactly inside a long stretch of real time, the round trip back to compressed time, and the zoom dropped on a mode switch. The new copy is present in both languages and reuses the existing clear-selection key rather than adding a near-duplicate.
|
Post-merge review (head Checked:
Not run: local vitest or E2E suite (no working tree). Author reports E2E passed 192 on Reviewed with AI assistance. |
What this PR does
The trajectory overview strip gets a second way of laying out time. By default it still cuts out the idle time between turns, so the strip answers where the running time went. A new clock button on the axis, before the zoom buttons, switches it to real time: idle stretches stay on the axis, the two ends of the axis read as local clock times, and the right-hand label says how long the window ran and how much of that was activity, for example "1m elapsed, 1.8s active". The button is a pressed-state toggle. Zoomed windows are labelled with clock times at the precision the window needs, down to milliseconds. The switch is announced through the strip's existing status line.
On a real-time axis a dragged selection can fall entirely inside idle time. The table then says "No request or tool ran in the selected time." with a clear button beside it, and the header reads "Showing 0 of N rows". This is the state the first selection PR left out, because on the compressed axis every stretch touches some record.
Switching mode drops the current selection and zoom. Both are held in the coordinates of the axis they were made on, and the other mode lays the axis out differently, so the same numbers would point at a different stretch of the run. The selection is now tied to the timeline it was drawn on rather than to the loaded window. It lapses in the same render the axis changes, whether that comes from a refresh, another session or a mode switch.
Why it's needed
Part of #12293. Active time answers "was it the model or the tools", but not "how long did this run actually take, and where did it sit waiting". Real time answers that: long pauses before a retry, or between a tool result and the next request, become visible as gaps. This follows the
actualTimeswitch in deepseek-harness's trajectory overview.Reviewer Test Plan
How to verify
web-shell.trajectory.spec.tsdrive all of this with real mouse input.Evidence (Before & After)
Captured by CI's
Capture web-shell visualsjob on headefc4903: the same session as the existing trajectory captures, switched to real time. Turn 1, with its failed request, retry, read and delegation, sits at the left. Turn 2 sits at the far right after the idle gap. The axis starts at a clock time, the right-hand label reads "1m 18s elapsed, 18.8s active", and the clock button is lit.web-shell E2E Smokeon the same head: 192 passed, and the log shows all four "real time" cases below executing. The export renderer bundle measured 1,944,135 bytes in that run, under the 1,970,000 warning line.Browser specs added, all
@smoke:Unit tests: 204 pass across the trajectory hook, loader, projection, range helper, panel and overview. Fifteen mutations were each killed by at least one test. They cover:
Tested on
Environment (optional)
Unit tests locally on Linux. The browser specs run in CI's
web-shell E2E Smoke; Chromium cannot run on the machine these changes were written on.Risk & Scope
Linked Issues
Part of #12293
中文说明
轨迹概览条新增第二种时间布局。默认仍然压缩掉轮次之间的空闲,回答「运行时间花在哪」。轴上缩放按钮之前新增一个时钟按钮,切换到真实时间:空闲留在轴上,轴两端显示本地时刻,右端显示窗口历时与其中的活跃时长,例如「历时 1m,活跃 1.8s」。按钮是带按下状态的开关;放大后的窗口按所需精度显示时刻,最细到毫秒;切换通过概览已有的状态行播报。
真实时间下拖选可能完全落在空闲里。此时表格显示「所选区间内没有请求或工具运行。」和清除按钮,表头为「区间内 0 / N 行」。这正是第一个选区 PR 留下的状态:压缩轴上任何区间都会碰到记录。
切换模式会清除当前选区与缩放。两者都用所在轴的坐标保存,另一种模式的轴布局不同,同样的数字会指向运行里的另一段。选区现在绑定到绘制它的时间轴,而不是已加载的窗口;刷新、换会话、切换模式都会让它在同一次渲染里失效。
「历时」从窗口里第一条画出的记录算到最后一条,不是会话时长。模式不持久化;选区不在模式间换算;键盘操作概览条是下一步(阶梯中的 T3c)。