diff --git a/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.i18n.yaml b/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.i18n.yaml index 1cf49844ab..f8b22ddc13 100644 --- a/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.md -2026-08-04-web-latency-throughput-metrics.md: f891ce8d2f772c66d5affba2d89694d0eeb681b6 -2026-08-04-web-latency-throughput-metrics.zh.md: e62f5ad6341cffe052118871b57e27f5380c2fd1 +2026-08-04-web-latency-throughput-metrics.md: d7c816ba1d6380bd257fe358d26e3c2e72c3fbe1 +2026-08-04-web-latency-throughput-metrics.zh.md: c9e5f63da576b6b850a55dc2a741b59fd729705c diff --git a/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.md b/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.md index f891ce8d2f..d7c816ba1d 100644 --- a/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.md +++ b/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.md @@ -27,3 +27,5 @@ The stats line reuses the same step reading in its window fold: `deriveStats` ac ## Consequences A settled in-window turn's footer reveals `TTFT`/`tok/s` on hover after the wall time, and the stats line shows window-average latency and throughput beside its wall times, all without new session events or host changes. Metrics degrade by omission: providers or steps without timing or usage samples drop individual figures rather than rendering zeros. Older history outside the loaded window stays uncounted, recorded in the package README's stats-line limitation. + +Both readings divide by measured wall time, so neither is reproducible: the same replayed scenario yielded 69 and 70 tok/s on consecutive local runs, and a 3 ms replayed stream reads 26333 tok/s. The Web aria goldens therefore normalize throughput to `{{throughput}}` beside the existing `{{duration}}`, and the footer's decorative separators gained flanking spaces — without them the readings concatenate into one accessible string (`Ran for 13sTTFT 0.2s12 tok/s`), which both loses the reading boundaries a screen reader needs and denies `{{duration}}` the word boundary it matches on. diff --git a/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.zh.md b/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.zh.md index e62f5ad634..c9e5f63da5 100644 --- a/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.zh.md +++ b/.agents/notes/implemented/feature/2026-08-04-web-latency-throughput-metrics.zh.md @@ -27,3 +27,5 @@ assistant 页脚把读数追加到既有 hover 显示的时间附属元素中、 ## 后果 窗口内已结算轮次的页脚在 hover 时于实际耗时之后显示 `首 token`/`tok/s`,统计行在墙钟时间旁显示窗口平均延迟与吞吐,全程不新增会话事件、不改 host。指标以省略的方式退化:没有计时或 usage 采样的提供方或步骤只是丢掉对应数字,而不会渲染成零。已加载窗口之外的更早历史仍不计入,已记录在包 README 的统计行限制中。 + +两个读数都以实测墙钟时间作分母,因此都不可复现:同一个回放场景在本机连续两次跑出 69 与 70 tok/s,而一段 3 毫秒的回放流会读成 26333 tok/s。因此 Web aria golden 在既有的 `{{duration}}` 之外,把吞吐归一化为 `{{throughput}}`;页脚的装饰性分隔符也补上了两侧空格——没有它们,这些读数会连成一整串无障碍文本(`Ran for 13sTTFT 0.2s12 tok/s`),既让屏幕阅读器失去读数之间的边界,也让 `{{duration}}` 失去它赖以匹配的词边界。 diff --git a/apps/web/tests/scaffold.ts b/apps/web/tests/scaffold.ts index a4498e0cf2..cf3a6384e0 100644 --- a/apps/web/tests/scaffold.ts +++ b/apps/web/tests/scaffold.ts @@ -523,8 +523,14 @@ export async function seedSession(scaffold: WebScaffold, fixtureText: string, id } /** - * Normalize an aria snapshot: uuid, cwd, workspace-basename, and duration - * volatility collapse to stable tokens. + * Normalize an aria snapshot: uuid, cwd, workspace-basename, duration, and + * decode-throughput volatility collapse to stable tokens. + * + * Throughput needs a token for the same reason durations do, and no fixture + * can supply one: the figure divides a replayed step's output tokens by the + * wall time the local run took to stream them, so it moves between two runs + * on one machine (measured 69 → 70 tok/s) and swings wildly on a fast replay + * (26333 tok/s for a 3 ms stream). */ function normalizeAria(snapshot: string, workspaceCwd: string): string { // The session heading renders the workspace's basename, not the full @@ -534,14 +540,17 @@ function normalizeAria(snapshot: string, workspaceCwd: string): string { .split(workspaceCwd).join('{{cwd}}') .split(base).join('{{workspace}}') .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '{{uuid}}') + // The optional space in `\d+m ?\d+s` covers both minute spellings: the + // stats line's compact `2m42s` and the message-chrome template's `2m 42s`. .replace( - /~\d+(?:y(?: \d+mo)?|mo(?: \d+d)?)|\b(?:\d+d(?: \d+h(?: \d+m \d+s)?)?|\d+h \d+m \d+s|\d+m \d+s|\d+(?:\.\d+)?s|\d+(?:\.\d+)?ms)\b/g, + /~\d+(?:y(?: \d+mo)?|mo(?: \d+d)?)|\b(?:\d+d(?: \d+h(?: \d+m \d+s)?)?|\d+h \d+m \d+s|\d+m ?\d+s|\d+(?:\.\d+)?s|\d+(?:\.\d+)?ms)\b/g, duration => duration.startsWith('~') ? duration : '{{duration}}', ) .replace( /约\d+(?:年(?:\d+个月)?|个月(?:\d+天)?)|\d+(?:天(?:\d+小时(?:\d+分\d+秒)?)?|小时\d+分\d+秒|分\d+秒|(?:\.\d+)?秒)/g, duration => duration.startsWith('约') ? duration : '{{duration}}', ) + .replace(/\d+(?:\.\d+)?(?= tok\/s(?!\w))/g, '{{throughput}}') // Message IconActions clocks widen by calendar day/year; collapse every // shape so goldens stay stable across midnight and year boundaries. .replace(/\d{4}年\d{1,2}月\d{1,2}日 \d{2}:\d{2}/g, '{{clock}}') diff --git a/apps/web/tests/snapshots/bash-abort-row/ui.expected.md b/apps/web/tests/snapshots/bash-abort-row/ui.expected.md index 8d544cefc1..7c975351d3 100644 --- a/apps/web/tests/snapshots/bash-abort-row/ui.expected.md +++ b/apps/web/tests/snapshots/bash-abort-row/ui.expected.md @@ -30,4 +30,4 @@ - text: Select model - img - button "Send message" [disabled] -- text: 1 turns · 1 steps Tool call {{duration}} Cache hit 0% Input 10 tok · Output 10 tok +- text: 1 turns · 1 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 0% Input 10 tok · Output 10 tok diff --git a/apps/web/tests/snapshots/code-mode-round/ui.expected.md b/apps/web/tests/snapshots/code-mode-round/ui.expected.md index 42758237bb..6270a5429f 100644 --- a/apps/web/tests/snapshots/code-mode-round/ui.expected.md +++ b/apps/web/tests/snapshots/code-mode-round/ui.expected.md @@ -36,7 +36,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -44,5 +44,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "7% of context used" - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Context 7% of 128K Cache hit 52% Input 17.2K tok · Output 252 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 52% Input 17.2K tok · Output 252 tok diff --git a/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md b/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md index 85ef8932b2..2442e9d927 100644 --- a/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md +++ b/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md @@ -51,7 +51,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -59,5 +59,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "13% of context used" - button "Send message" [disabled] -- text: 1 turns · 4 steps Tool call {{duration}} Context 13% of 128K Cache hit 77% Input 66.5K tok · Output 312 tok +- text: 1 turns · 4 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 77% Input 66.5K tok · Output 312 tok diff --git a/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md b/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md index 159e77d5bc..37ae3ba520 100644 --- a/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md +++ b/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md @@ -31,7 +31,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -39,5 +39,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "6% of context used" - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Context 6% of 128K Cache hit 99% Input 15.7K tok · Output 111 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 99% Input 15.7K tok · Output 111 tok diff --git a/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md b/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md index f6f965337e..5e554f289d 100644 --- a/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md +++ b/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md @@ -23,7 +23,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -31,5 +31,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "6% of context used" - button "Send message" [disabled] -- text: 1 turns · 1 steps Context 6% of 128K Cache hit 99% Input 7.8K tok · Output 21 tok +- text: 1 turns · 1 steps LLM {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 99% Input 7.8K tok · Output 21 tok diff --git a/apps/web/tests/snapshots/live-interactions/cancel.expected.md b/apps/web/tests/snapshots/live-interactions/cancel.expected.md index cd06310db0..156b30f82a 100644 --- a/apps/web/tests/snapshots/live-interactions/cancel.expected.md +++ b/apps/web/tests/snapshots/live-interactions/cancel.expected.md @@ -20,7 +20,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} - textbox "Message the agent" - button "Commands": - img diff --git a/apps/web/tests/snapshots/live-interactions/retry.expected.md b/apps/web/tests/snapshots/live-interactions/retry.expected.md index 5f834e15f0..91ddca897a 100644 --- a/apps/web/tests/snapshots/live-interactions/retry.expected.md +++ b/apps/web/tests/snapshots/live-interactions/retry.expected.md @@ -25,7 +25,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -33,5 +33,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "6% of context used" - button "Send message" [disabled] -- text: 1 turns · 1 steps Context 6% of 128K Cache hit 99% Input 7.8K tok · Output 79 tok +- text: 1 turns · 1 steps LLM {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 99% Input 7.8K tok · Output 79 tok diff --git a/apps/web/tests/snapshots/markdown-images/ui.expected.md b/apps/web/tests/snapshots/markdown-images/ui.expected.md index ed42dfec84..fbdbff395a 100644 --- a/apps/web/tests/snapshots/markdown-images/ui.expected.md +++ b/apps/web/tests/snapshots/markdown-images/ui.expected.md @@ -19,7 +19,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} - textbox "Message the agent" - button "Commands": - img diff --git a/apps/web/tests/snapshots/message-actions/ui.expected.md b/apps/web/tests/snapshots/message-actions/ui.expected.md index 815acaef1d..81c2796e5a 100644 --- a/apps/web/tests/snapshots/message-actions/ui.expected.md +++ b/apps/web/tests/snapshots/message-actions/ui.expected.md @@ -20,7 +20,7 @@ - img - button "Branch into a new conversation" [disabled]: - img -- text: Available only on the last message of a completed turn 7/25 {{clock}}Ran for {{duration}} +- text: Available only on the last message of a completed turn 7/25 {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - button "Read a.txt": - img - img @@ -46,7 +46,7 @@ - img - button "Branch into a new conversation": - img -- text: 7/25 {{clock}}Ran for {{duration}} +- text: 7/25 {{clock}} Ran for {{duration}} - textbox "Message the agent" - button "Commands": - img @@ -55,4 +55,4 @@ - text: Select model - img - button "Send message" [disabled] -- text: 2 turns · 3 steps Tool call {{duration}} Cache hit 98% Input 7.8K tok · Output 103 tok +- text: 2 turns · 3 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 98% Input 7.8K tok · Output 103 tok diff --git a/apps/web/tests/snapshots/plan-review/approved.expected.md b/apps/web/tests/snapshots/plan-review/approved.expected.md index 2120c32408..0bcf2c5dca 100644 --- a/apps/web/tests/snapshots/plan-review/approved.expected.md +++ b/apps/web/tests/snapshots/plan-review/approved.expected.md @@ -36,7 +36,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -44,5 +44,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "4% of context used" - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Context 4% of 128K Cache hit 51% Input 10.2K tok · Output 346 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 51% Input 10.2K tok · Output 346 tok diff --git a/apps/web/tests/snapshots/question-composer/answered.expected.md b/apps/web/tests/snapshots/question-composer/answered.expected.md index a54b7dcd75..8176008f25 100644 --- a/apps/web/tests/snapshots/question-composer/answered.expected.md +++ b/apps/web/tests/snapshots/question-composer/answered.expected.md @@ -31,7 +31,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -39,5 +39,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "3% of context used" - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Context 3% of 128K Cache hit 95% Input 8.6K tok · Output 180 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 95% Input 8.6K tok · Output 180 tok diff --git a/apps/web/tests/snapshots/queue-actions/preserved.expected.md b/apps/web/tests/snapshots/queue-actions/preserved.expected.md index 2ce0077a2e..3c76d0d623 100644 --- a/apps/web/tests/snapshots/queue-actions/preserved.expected.md +++ b/apps/web/tests/snapshots/queue-actions/preserved.expected.md @@ -20,7 +20,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} Edited queue item {{clock}} +- text: {{clock}} Ran for {{duration}} Edited queue item {{clock}} - button "Copy": - img - button "Branch into a new conversation" [disabled]: diff --git a/apps/web/tests/snapshots/seeded-history/command-row.expected.md b/apps/web/tests/snapshots/seeded-history/command-row.expected.md index 9338167f2c..fb2f5e4cba 100644 --- a/apps/web/tests/snapshots/seeded-history/command-row.expected.md +++ b/apps/web/tests/snapshots/seeded-history/command-row.expected.md @@ -33,7 +33,7 @@ - img - button "Branch into a new conversation": - img -- text: 7/25 {{clock}}Ran for {{duration}} +- text: 7/25 {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - button "Context compacted View compaction summary": - img - text: Context compacted View compaction summary @@ -51,4 +51,4 @@ - text: Select model - img - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Cache hit 98% Input 15.8K tok · Output 135 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 98% Input 15.8K tok · Output 135 tok diff --git a/apps/web/tests/snapshots/seeded-history/ui.expected.md b/apps/web/tests/snapshots/seeded-history/ui.expected.md index f24aaac77c..f804046ad2 100644 --- a/apps/web/tests/snapshots/seeded-history/ui.expected.md +++ b/apps/web/tests/snapshots/seeded-history/ui.expected.md @@ -33,7 +33,7 @@ - img - button "Branch into a new conversation": - img -- text: 7/25 {{clock}}Ran for {{duration}} +- text: 7/25 {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - button "Context compacted View compaction summary": - img - text: Context compacted View compaction summary @@ -49,4 +49,4 @@ - text: Select model - img - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Cache hit 98% Input 15.8K tok · Output 135 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 98% Input 15.8K tok · Output 135 tok diff --git a/apps/web/tests/snapshots/steering/settled.expected.md b/apps/web/tests/snapshots/steering/settled.expected.md index 00f1b33206..c68451bc19 100644 --- a/apps/web/tests/snapshots/steering/settled.expected.md +++ b/apps/web/tests/snapshots/steering/settled.expected.md @@ -37,7 +37,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -45,5 +45,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "6% of context used" - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Context 6% of 128K Cache hit 98% Input 15.8K tok · Output 156 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 98% Input 15.8K tok · Output 156 tok diff --git a/apps/web/tests/snapshots/subagent-conversation/ui.expected.md b/apps/web/tests/snapshots/subagent-conversation/ui.expected.md index 561277b8ee..c3f1038650 100644 --- a/apps/web/tests/snapshots/subagent-conversation/ui.expected.md +++ b/apps/web/tests/snapshots/subagent-conversation/ui.expected.md @@ -28,7 +28,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} Now give the same explanation to a human reader. {{clock}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s Now give the same explanation to a human reader. {{clock}} - button "Copy": - img - button "Branch into a new conversation" [disabled]: @@ -43,10 +43,11 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img - 'button "Access mode, current: Workspace Write"': Workspace Write +- button "6% of context used" - button "Send message" [disabled] -- text: 2 turns · 2 steps Context 6% of 128K Cache hit 99% Input 15.6K tok · Output 158 tok +- text: 2 turns · 2 steps LLM {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 99% Input 15.6K tok · Output 158 tok diff --git a/apps/web/tests/snapshots/web-search-round/ui.expected.md b/apps/web/tests/snapshots/web-search-round/ui.expected.md index 45098769f7..8fdd4d8585 100644 --- a/apps/web/tests/snapshots/web-search-round/ui.expected.md +++ b/apps/web/tests/snapshots/web-search-round/ui.expected.md @@ -23,7 +23,7 @@ - img - button "Branch into a new conversation": - img -- text: {{clock}}Ran for {{duration}} +- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s - textbox "Message the agent" - button "Commands": - img @@ -31,5 +31,6 @@ - button "Select model, current DeepSeek-V4-Flash": - text: DeepSeek-V4-Flash - img +- button "0% of context used" - button "Send message" [disabled] -- text: 1 turns · 2 steps Tool call {{duration}} Context 0% of 128K Cache hit 0% Input 22 tok · Output 7 tok +- text: 1 turns · 2 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 0% Input 22 tok · Output 7 tok diff --git a/packages/client/ui-conversation/src/client/chat/MessageIconActions.tsx b/packages/client/ui-conversation/src/client/chat/MessageIconActions.tsx index 640189bf63..e1481c437f 100644 --- a/packages/client/ui-conversation/src/client/chat/MessageIconActions.tsx +++ b/packages/client/ui-conversation/src/client/chat/MessageIconActions.tsx @@ -71,24 +71,33 @@ export function MessageIconActions({ }, 1000) }) }, [copied, text]) + // The dot is decorative and stays hidden, but its margins separate the + // readings only on screen: without the flanking spaces a reader hears one + // run-on string ("Ran for 13sTTFT 0.2s12 tok/s") instead of three facts. const clockEl = time === undefined ? null : ( {formatMessageClock(time, t, day)} {runMs !== undefined && ( <> + {' '} · + {' '} {t('message.ranFor', { duration: formatRunDuration(runMs, t) })} )} {ttftMs !== undefined && ( <> + {' '} · + {' '} {t('message.ttft', { seconds: formatLatencySeconds(ttftMs) })} )} {tokensPerSecond !== undefined && ( <> + {' '} · + {' '} {t('message.tokensPerSecond', { tps: formatTokensPerSecond(tokensPerSecond) })} )}