From 49e42be440776004dfb39bc081ad659079f29000 Mon Sep 17 00:00:00 2001 From: lyon Date: Sun, 21 Jun 2026 01:56:09 +0800 Subject: [PATCH] fix(workbench): derive session terminal status from durable trace --- internal/cloud/server-workbench-http.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/internal/cloud/server-workbench-http.ts b/internal/cloud/server-workbench-http.ts index b60671ad..1b85bca4 100644 --- a/internal/cloud/server-workbench-http.ts +++ b/internal/cloud/server-workbench-http.ts @@ -501,8 +501,11 @@ function factSessionSummary(session, facts = {}) { const projection = traceId ? factProjectionForTrace(facts, traceId) : null; const turn = traceId ? factTurnForTrace(facts, traceId) : null; const checkpoint = traceId ? factCheckpointForTrace(facts, traceId) : null; + const trace = traceId ? factTraceSnapshot(facts, traceId) : null; const messages = factMessagesForSession(session, facts); - const status = normalizeStatus(turn?.status ?? session?.status); + const traceStatus = normalizeTerminalStatus(trace?.status); + const checkpointStatus = normalizeTerminalStatus(checkpoint?.status); + const status = normalizeStatus(turn?.status ?? checkpointStatus ?? traceStatus ?? session?.status); const timingSource = checkpoint ?? (traceId ? null : session); const timing = factTimingProjection(timingSource, status); return { @@ -528,7 +531,7 @@ function factSessionSummary(session, facts = {}) { status: normalizeStatus(turn.status ?? status), running: RUNNING_STATUSES.has(normalizeStatus(turn.status ?? status)), terminal: TERMINAL_STATUSES.has(normalizeStatus(turn.status ?? status)) && !RUNNING_STATUSES.has(normalizeStatus(turn.status ?? status)), - eventCount: projection?.lastProjectedSeq ?? factTraceSnapshot(facts, traceId).eventCount, + eventCount: projection?.lastProjectedSeq ?? trace?.eventCount, projection, projectionStatus: projection?.projectionStatus ?? null, projectionHealth: projection?.projectionHealth ?? null, @@ -644,13 +647,13 @@ function factTurnForTrace(facts = {}, traceId, turnId = null) { function factTurnSnapshot({ turn = null, session = null, facts = {}, traceId, turnId = null } = {}) { const safeTrace = safeTraceId(traceId); const resolvedTurnId = factTurnId(turn, safeTrace) ?? safeTurnId(turnId) ?? safeTrace; - const status = normalizeStatus(turn?.status ?? session?.status); const messages = session ? factMessagesForSession(session, facts) : []; const userMessage = messages.find((message) => message.role === "user") ?? null; const assistantMessage = [...messages].reverse().find((message) => isAssistantLikeRole(message.role)) ?? null; const checkpoint = safeTrace ? factCheckpointForTrace(facts, safeTrace) : null; - const finalText = projectionText(turn?.finalResponse, turn?.assistantText, turn?.text, assistantMessage?.text); const trace = factTraceSnapshot(facts, safeTrace); + const status = normalizeStatus(turn?.status ?? normalizeTerminalStatus(checkpoint?.status) ?? normalizeTerminalStatus(trace.status) ?? session?.status); + const finalText = projectionText(turn?.finalResponse, turn?.assistantText, turn?.text, assistantMessage?.text); const timing = factTimingProjection(checkpoint, status); return { turnId: resolvedTurnId, @@ -1855,6 +1858,11 @@ function normalizeStatus(value) { return text || "unknown"; } +function normalizeTerminalStatus(value) { + const status = normalizeStatus(value); + return TERMINAL_STATUSES.has(status) && !RUNNING_STATUSES.has(status) ? status : null; +} + function firstUserPreview(messages) { return messages.find((message) => message.role === "user")?.textPreview ?? null; }