From 1f59fbd33ec242bfb1757ace9d6e0ae8f51ebd24 Mon Sep 17 00:00:00 2001 From: lyon Date: Sun, 21 Jun 2026 03:29:29 +0800 Subject: [PATCH] fix: keep running turn timing authoritative --- internal/cloud/server-workbench-http.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/cloud/server-workbench-http.ts b/internal/cloud/server-workbench-http.ts index 2973c6aa..08bc80fc 100644 --- a/internal/cloud/server-workbench-http.ts +++ b/internal/cloud/server-workbench-http.ts @@ -510,7 +510,7 @@ function factSessionSummary(session, facts = {}) { // stale running turn row must not keep the visible timer running after the // terminal event has already been projected. const status = normalizeStatus(checkpointStatus ?? traceStatus ?? turnStatus ?? session?.status); - const timingSource = checkpoint ?? (traceId ? null : session); + const timingSource = checkpointStatus ? checkpoint : turn ?? checkpoint ?? (traceId ? null : session); const timing = factTimingProjection(timingSource, status); return { sessionId, @@ -594,9 +594,11 @@ function factMessageDto(message, parts = [], facts = {}) { const turn = traceId ? factTurnForTrace(facts, traceId) : null; const checkpoint = traceId ? factCheckpointForTrace(facts, traceId) : null; const messageStatus = normalizeStatus(message?.status); - const checkpointStatus = isAssistantLikeRole(role) ? normalizeTerminalStatus(checkpoint?.status) : null; - const status = normalizeStatus(checkpointStatus ?? (isAssistantLikeRole(role) ? turn?.status : null) ?? messageStatus); - const timing = factTimingProjection(isAssistantLikeRole(role) ? checkpoint ?? turn ?? message : message, status); + const assistantLike = isAssistantLikeRole(role); + const checkpointStatus = assistantLike ? normalizeTerminalStatus(checkpoint?.status) : null; + const status = normalizeStatus(checkpointStatus ?? (assistantLike ? turn?.status : null) ?? messageStatus); + const timingSource = assistantLike ? (checkpointStatus ? checkpoint : turn ?? checkpoint ?? message) : message; + const timing = factTimingProjection(timingSource, status); const text = projectionText(message?.text, message?.content, message?.message, message?.finalResponse); const normalizedParts = parts.length > 0 ? [...parts].sort(compareFactPartsAsc).map((part) => factPartDto(part, messageId, traceId)).filter(Boolean) @@ -662,7 +664,7 @@ function factTurnSnapshot({ turn = null, session = null, facts = {}, traceId, tu const traceStatus = normalizeTerminalStatus(trace.status); const status = normalizeStatus(checkpointStatus ?? traceStatus ?? turn?.status ?? session?.status); const finalText = projectionText(turn?.finalResponse, turn?.assistantText, turn?.text, assistantMessage?.text); - const timing = factTimingProjection(checkpoint, status); + const timing = factTimingProjection(checkpointStatus ? checkpoint : turn ?? checkpoint, status); return { turnId: resolvedTurnId, traceId: safeTrace,