qwen-code/packages/web-shell/client/components
Shaojin Wen 6677ca1dd3
feat(web-shell): per-task token & time detail on completed todos (#5118)
* feat(web-shell): per-task token & time detail on completed todos

Expanding a completed task in the todo list now reveals when it ran (start /
end / duration) and what it spent: input / output / cached tokens, API time,
and tool time.

The agent stamps a cumulative-usage snapshot onto each todo (plan) update via
`_meta.stats`; the SDK normalizer carries it into the TodoWrite tool call's
rawOutput, and the web-shell diffs consecutive snapshots for tokens and API
time while summing transcript tool durations for tool time.

Works live (no polling race) and on /resume: tokens and tool time are
reconstructed from persisted usage metadata, while API time is live-only since
per-turn durations are not replayed. Sessions whose agent never stamped a
snapshot degrade gracefully to start/end + tool time.

* refactor(web-shell): show task duration inline on the end-time row

Trail the elapsed duration after the end time as a dimmed parenthetical
("12:34:15 (4m 14s)") instead of a separate row, since it's derived from the
start/end pair.

* fix(web-shell): correct per-task detail for reused todo ids; review follow-ups

- computeTodoDetails: when a completed id+content key restarts as in_progress (positional plan-N ids repeat across plans), reset the window so the new task diffs its own start instead of the prior task's far-earlier boundary — which rendered a cross-plan window with wildly inflated token/time numbers. Correct the todoStateKey JSDoc accordingly.
- Tool time: sort spans once and binary-search the task window instead of an O(todos x spans) scan per completed task.
- Tests: add the reuse-reset case, a windowed tool-time case, an SDK-normalizer -> extractTodoStats contract test (locks the stats passthrough so a field rename fails loudly), and a stopPropagation test (expander click must not bubble to the tool-row header).

* fix(web-shell): reset todo detail window on reopen via pending, not just direct

Track keys that have ever reached 'completed' instead of checking prev === 'completed': a reopened task can pass through 'pending' (completed → pending → in_progress), where prev at the re-activation is 'pending' and the direct check missed it, leaving a stale baseline that diffs across both runs. A pause/resume that never completed (in_progress → pending → in_progress) still keeps its first baseline, so its diff captures the whole task.

* fix(web-shell,cli): harden todo stats against NaN poisoning and partial snapshots

- MessageEmitter: only fold finite usage/duration values into the cumulative accumulator. A NaN/Infinity (incl. a NaN that survives `?? 0`) would poison the running total forever, making every later snapshot fail extractTodoStats and silently show 'not captured' for the rest of the session.
- extractTodoStats: require the token fields but default the live-only apiTimeMs to 0 when absent/non-finite, so a snapshot that omits it keeps its valid token counts instead of being dropped whole.
- computeTodoDetails: gate the start baseline on the stored value, not Map.has — a stats-less start (e.g. a plain plan message) recorded undefined, which Map.has treated as already-set, blocking a later stats-bearing snapshot from upgrading the baseline.
- Document the MessageEmitter-before-PlanEmitter ordering invariant in both emitters.
2026-06-15 15:40:06 +08:00
..
dialogs feat(cli,web-shell): persist goal status in daemon transcript events (#5098) 2026-06-14 21:08:06 +08:00
messages feat(web-shell): per-task token & time detail on completed todos (#5118) 2026-06-15 15:40:06 +08:00
panels feat(web-shell): revamp floating todo panel interactions (#5069) 2026-06-13 11:51:03 +08:00
Editor.keymap.test.ts feat(web-shell): add Option+Enter and Cmd+Enter newline shortcuts (#5005) 2026-06-12 13:07:56 +08:00
Editor.module.css feat(web-shell): make input shortcuts discoverable and clickable (#5096) 2026-06-14 16:41:37 +08:00
Editor.test.ts feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
Editor.tsx feat(web-shell): make input shortcuts discoverable and clickable (#5096) 2026-06-14 16:41:37 +08:00
InsightProgress.module.css feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
InsightProgress.tsx feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
InsightReady.tsx feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
MessageItem.tsx feat(web-shell): collapsible TodoWrite history with status diff (#5109) 2026-06-15 00:44:15 +08:00
MessageList.module.css feat(web-shell): revamp floating todo panel interactions (#5069) 2026-06-13 11:51:03 +08:00
MessageList.test.ts feat(web-shell): show time on parallel-agents box and sub-agent tools (#5084) 2026-06-14 00:46:42 +08:00
MessageList.tsx feat(web-shell): show time on parallel-agents box and sub-agent tools (#5084) 2026-06-14 00:46:42 +08:00
MessageTimestamp.module.css feat(web-shell): show message time on hover (#5079) 2026-06-13 15:30:44 +08:00
MessageTimestamp.test.tsx feat(web-shell): show message time on hover (#5079) 2026-06-13 15:30:44 +08:00
MessageTimestamp.tsx feat(web-shell): show message time on hover (#5079) 2026-06-13 15:30:44 +08:00
PromptChevron.tsx feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
ShortcutsPanel.module.css feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
ShortcutsPanel.tsx feat(web-shell): make input shortcuts discoverable and clickable (#5096) 2026-06-14 16:41:37 +08:00
StatusBar.module.css feat(web-shell): make input shortcuts discoverable and clickable (#5096) 2026-06-14 16:41:37 +08:00
StatusBar.tsx feat(web-shell): make input shortcuts discoverable and clickable (#5096) 2026-06-14 16:41:37 +08:00
StreamingStatus.module.css feat(web-shell): daemon web-shell improvements — token usage, settings, retry, streaming metrics, hidden commands (#5066) 2026-06-13 02:58:08 +00:00
StreamingStatus.tsx feat(web-shell): daemon web-shell improvements — token usage, settings, retry, streaming metrics, hidden commands (#5066) 2026-06-13 02:58:08 +00:00
Tips.module.css feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
Tips.tsx feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
ToastHost.module.css feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
ToastHost.tsx feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
WelcomeHeader.module.css feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
WelcomeHeader.tsx feat(web-shell): daemon web-shell improvements — token usage, settings, retry, streaming metrics, hidden commands (#5066) 2026-06-13 02:58:08 +00:00