From 24885272ab5334b8bcdfc4a85416ced1c2ed1f20 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:04:15 +0800 Subject: [PATCH] fix(web-probe): read turn timing only from card fields (#678) Co-authored-by: Codex --- .../hwlab-node-web-observe-runner-source.ts | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/scripts/src/hwlab-node-web-observe-runner-source.ts b/scripts/src/hwlab-node-web-observe-runner-source.ts index 67ae3d2c..93a00de0 100644 --- a/scripts/src/hwlab-node-web-observe-runner-source.ts +++ b/scripts/src/hwlab-node-web-observe-runner-source.ts @@ -2872,10 +2872,11 @@ function buildSampleMetrics(samples, control) { const promptTimes = promptCommands.map((item) => item.tsMs); const timeline = samples.map((sample) => { const texts = sampleTexts(sample); + const timingTexts = sampleTurnTimingTexts(sample); const tsMs = Date.parse(sample.ts); const promptIndex = Number.isFinite(tsMs) ? latestPromptIndex(promptTimes, tsMs) : 0; - const totalElapsedValues = texts.flatMap(parseTotalElapsedSeconds).filter(Number.isFinite); - const recentUpdateValues = texts.flatMap(parseRecentUpdateSeconds).filter(Number.isFinite); + const totalElapsedValues = timingTexts.flatMap(parseTotalElapsedSeconds).filter(Number.isFinite); + const recentUpdateValues = timingTexts.flatMap(parseRecentUpdateSeconds).filter(Number.isFinite); const diagnosticTexts = texts.filter(isDiagnosticText).slice(0, 5); const terminalTexts = texts.filter(isTerminalTraceText).slice(0, 5); const finalResultTexts = texts.filter(isFinalResultText).slice(0, 5); @@ -3546,7 +3547,7 @@ function turnMetricItems(sample, timelineItem) { } if (Array.isArray(sample?.messages) && sample.messages.length > 0) { for (const message of sample.messages) { - const text = String(message?.textPreview || ""); + const text = [message?.durationText, message?.activityText].map((value) => String(value || "")).filter((value) => value.trim().length > 0).join("\n"); const totalElapsedValues = parseTotalElapsedSeconds(text).filter(Number.isFinite); const recentUpdateValues = parseRecentUpdateSeconds(text).filter(Number.isFinite); if (totalElapsedValues.length === 0 && recentUpdateValues.length === 0) continue; @@ -3596,9 +3597,7 @@ function turnMetricItems(sample, timelineItem) { function turnTexts(turn) { return [ turn?.durationText, - turn?.activityText, - turn?.textPreview, - turn?.text + turn?.activityText ].map((value) => String(value || "")).filter((value) => value.trim().length > 0); } @@ -3693,6 +3692,20 @@ function sampleTexts(sample) { return rows; } +function sampleTurnTimingTexts(sample) { + const rows = []; + for (const group of [sample?.turns, sample?.messages]) { + if (!Array.isArray(group)) continue; + for (const item of group) { + for (const value of [item?.durationText, item?.activityText]) { + const text = String(value || ""); + if (text.trim()) rows.push(text); + } + } + } + return rows; +} + function parseTotalElapsedSeconds(text) { const values = []; for (const match of String(text || "").matchAll(/(?:总耗时|耗时)\s*[=::]?\s*(\d{1,2}):(\d{2}):(\d{2})/giu)) { @@ -3805,7 +3818,8 @@ function detectTerminalZeroElapsed(samples) { const text = [item?.durationText, item?.activityText, item?.status, item?.textPreview, item?.text].filter(Boolean).join("\n"); if (!/(?:Code Agent|运行记录|completed|failed|canceled|blocked)/iu.test(text)) continue; if (!/(?:completed|failed|canceled|blocked|已完成|失败|取消)/iu.test(text)) continue; - const elapsedValues = parseTotalElapsedSeconds(text); + const timingText = [item?.durationText, item?.activityText].filter(Boolean).join("\n"); + const elapsedValues = parseTotalElapsedSeconds(timingText); if (!elapsedValues.includes(0)) continue; rows.push({ ...ref(sample),