From 9fc6f655d2a9dcf90eedbf8b6aa08f1caf99f00f Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:16:05 +0800 Subject: [PATCH] fix(workbench): stream durable fact turn snapshots (#1971) --- internal/cloud/server-workbench-http.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/internal/cloud/server-workbench-http.ts b/internal/cloud/server-workbench-http.ts index a3db622f..fb5eb98a 100644 --- a/internal/cloud/server-workbench-http.ts +++ b/internal/cloud/server-workbench-http.ts @@ -1897,11 +1897,22 @@ async function writeTraceRealtimeSnapshot({ writeEvent, options, actor, traceId, sessionId, threadId, traceId, - turn: turnSnapshot(context), + turn: realtimeTurnSnapshot(context), cursor: { traceSeq: traceSnapshotLastSeq(context.trace) } }); } +function realtimeTurnSnapshot(context) { + const facts = context?.facts; + const traceId = safeTraceId(context?.traceId); + if (traceId && facts && context?.factSession) { + const factTurn = factTurnForTrace(facts, traceId); + const projected = factTurnSnapshot({ turn: factTurn, session: context.factSession, facts, traceId, turnId: context.turnId }); + if (projected) return projected; + } + return turnSnapshot(context); +} + async function writeTraceRealtimeSnapshotSafe(input) { try { await writeTraceRealtimeSnapshot(input); @@ -1930,7 +1941,16 @@ async function visibleTraceContext(options, actor, traceId) { if (!resultVisible && !session) return { visible: false }; const trace = await readModel.traceSnapshot(traceId); const projection = createWorkbenchTurnProjection({ turnId: traceId, traceId, result, session, trace }); - return { visible: true, turnId: projection.turnId, traceId, status: projection.status, projection, result, session, trace }; + const factSessionIdValue = safeSessionId(session?.id ?? result?.sessionId ?? result?.session?.sessionId) ?? null; + let facts = emptyFactSet(); + if (factSessionIdValue && typeof readModel.queryFacts === "function") { + try { + const factResult = await readModel.queryFacts({ sessionId: factSessionIdValue, families: WORKBENCH_SESSION_DETAIL_FAMILIES, limit: 100 }); + facts = factResult?.facts ?? facts; + } catch { /* realtime falls back to legacy trace snapshot if durable facts are temporarily unavailable */ } + } + const factSession = factArray(facts.sessions).find((item) => factSessionId(item) === factSessionIdValue) ?? null; + return { visible: true, turnId: projection.turnId, traceId, status: projection.status, projection, result, session, trace, facts, factSession }; } function traceSnapshotForRealtime(snapshot) {