feat(work-status): add opt-in turn statistics (#3177)
Add optional completed-turn statistics without changing the existing panel layout. Separate final text delivery speed from whole-turn throughput, preserve scope and opt-in settings, and explain each metric with localized delayed tooltips. Validated focused telemetry, lifecycle, sync and persistence tests, all-workspace type-check and lint, web builds, the 12-locale narrow layout, and full GitHub CI.
This commit is contained in:
@@ -17,7 +17,8 @@ conditionally; passing "am I first?" down would mean each one tracking what the
|
||||
sections above it decided to render.
|
||||
|
||||
Sections render nothing when they have no rows, so the panel collapses upward
|
||||
instead of reserving empty space.
|
||||
instead of reserving empty space. Opt-in Turn stats keeps its header for a
|
||||
selected session even without metrics, so a saved collapsed state can reopen.
|
||||
|
||||
## What it is not
|
||||
|
||||
@@ -103,11 +104,49 @@ which requests only providers enabled for this panel.
|
||||
| Subagent blockers | directory `permission` / `question` maps | one subscription covers every child |
|
||||
| Usage | `components/usage/usageGroups.ts` over `useQuotaStore` | grouping shared with the mobile popover; presentation is not |
|
||||
| Linked threads | `lib/linkedIssues.ts` over session metadata | written by the flows that attach an issue or PR |
|
||||
| Turn stats | `telemetry.ts` over `useSessionMessageRecords` | opt-in; computed only while expanded and authoritatively idle |
|
||||
| Goal | `useSessionGoal` | respects the Settings toggle |
|
||||
| MCP | `useMcpStore` | connect/disconnect reuses the dropdown's actions |
|
||||
| Pinned messages | `getContextObligatoryMessages` + `state.part` | see below |
|
||||
| Todos | live `state.todo[sessionId]`, persisted fallback | live channel wins |
|
||||
|
||||
### Turn stats
|
||||
|
||||
The section follows Usage and reuses the panel's existing rows. Only its header
|
||||
has an icon; metric rows use labels and values without leading icons. It
|
||||
reads already-loaded records without fetching history. The newest turn needs a
|
||||
preceding user message and completed assistant steps. A truncated or unfinished
|
||||
turn has no whole-turn result; later materialization can supply it.
|
||||
|
||||
Two rates answer different questions. Response speed uses the final assistant
|
||||
message's output tokens divided by the union of its nonempty text intervals.
|
||||
It excludes initial waiting, reasoning tokens and reasoning time, and earlier
|
||||
tool steps. It requires complete, valid text timing and a final message without
|
||||
tools, errors, synthetic text or ignored text. This measures text delivery from
|
||||
stored timestamps, not provider-side decode speed. The header shows only this
|
||||
rate; unavailable response timing never falls back to whole-turn speed.
|
||||
|
||||
Whole-turn speed uses output plus reasoning tokens from every step, divided by
|
||||
elapsed assistant time minus the union of completed and failed tool intervals.
|
||||
Waiting for each model response remains included. Invalid or missing inputs
|
||||
omit the dependent metric rather than becoming zero; reported zeros remain
|
||||
valid. TTFT averages the earliest text/reasoning start delay from every step,
|
||||
only when all steps have a valid sample.
|
||||
|
||||
Metric labels stay short. Every row is a single hover and keyboard-focus target
|
||||
for a shared tooltip, with a 750ms hover delay and a portal outside the panel's
|
||||
scroller. Tooltips explain the measurement in every locale. The token row uses
|
||||
compact input/output arrows; its tooltip gives full counts and explains that
|
||||
input excludes cached tokens and output includes reasoning across all steps.
|
||||
|
||||
Records subscriptions and aggregation stop while collapsed, busy, retrying, or
|
||||
awaiting status authority. Explicit idle events or a successful directory status
|
||||
snapshot allow computation. One component-owned committed result keeps the
|
||||
headline and rows stable during the next active turn. Its identity includes
|
||||
runtime, normalized directory and session. Scope changes discard it; fresh empty
|
||||
or reverted records clear it. There is no global message-ID cache. Corrections
|
||||
to existing message/part identities invalidate the current result.
|
||||
|
||||
### Context usage has its own computation, on purpose
|
||||
|
||||
`useSessionUIStore.getContextUsage` cannot serve this panel for two reasons:
|
||||
@@ -191,8 +230,9 @@ the row reflects the reset tree rather than a mid-creation snapshot.
|
||||
Ordering is by durability, not category:
|
||||
|
||||
1. **Session** (goal, context, cost), **Project** (attention, branch,
|
||||
changes, PR, checks) and **Usage** — true for as long as the session is
|
||||
open. Usage sits here rather than lower down because a spent quota stops the
|
||||
changes, PR, checks), **Usage**, and **Turn stats** (opt-in session telemetry:
|
||||
throughput, duration, TTFT, cache hit rate) — true for as long as the session
|
||||
is open. Usage sits here rather than lower down because a spent quota stops the
|
||||
work outright;
|
||||
2. **Subagents**, **Tasks** — what is happening right now;
|
||||
3. **MCP**, **Pinned messages**, **Context sources** — supporting material.
|
||||
@@ -201,10 +241,13 @@ Ordering is by durability, not category:
|
||||
|
||||
A persisted preference (`workStatusPanelEnabled`) drives a header toggle, and a
|
||||
dialog behind the equalizer icon switches individual sections off. Hidden
|
||||
sections are stored rather than visible ones, so a section added later appears
|
||||
for everyone instead of staying invisible to whoever had saved settings before
|
||||
it existed. Both travel the full settings pipeline, including the server
|
||||
whitelist without which the keys never reach `settings.json`.
|
||||
sections are stored rather than visible ones. Telemetry is the opt-in exception:
|
||||
UI-store v20 and legacy server-list hydration add it to the hidden set. A
|
||||
`workStatusHiddenSectionsExplicit` marker records that a list was chosen in a
|
||||
client with telemetry support. The marker and list travel together through
|
||||
autosave, sanitization, and server settings, so an explicit empty list enables
|
||||
everything while an old empty list does not enable telemetry. Complete settings
|
||||
snapshots own this preference; unrelated partial save echoes leave it unchanged.
|
||||
|
||||
`workStatusPanelVisible` is separate and transient: the switch can be on while
|
||||
layout still refuses the panel. The header and the git rail read it to drop the
|
||||
|
||||
Reference in New Issue
Block a user