From ce4b3333ce1c4745f16428edbce4b364fb64622c Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:46:40 +0800 Subject: [PATCH] fix(workbench): hydrate active session on new realtime trace (#1964) --- web/hwlab-cloud-web/src/stores/workbench.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/web/hwlab-cloud-web/src/stores/workbench.ts b/web/hwlab-cloud-web/src/stores/workbench.ts index 1076802b..e29f7034 100644 --- a/web/hwlab-cloud-web/src/stores/workbench.ts +++ b/web/hwlab-cloud-web/src/stores/workbench.ts @@ -76,6 +76,7 @@ export const useWorkbenchStore = defineStore("workbench", () => { const traceHydrationQueue: ChatMessage[] = []; let traceHydrationPumpActive = false; const terminalRealtimeRefreshInFlight = new Set(); + const realtimeSessionRefreshInFlight = new Set(); let realtimeStream: WorkbenchEventStream | null = null; let realtimeKey = ""; const sessionListRefreshInFlight = new Map>(); @@ -1248,8 +1249,10 @@ function nonBlockingProjection(projection: ProjectionDiagnostic | null): Project const authoritySessionId = traceResultSessionId(trace) ?? traceResultSessionId(snapshot); const ownerSessionId = traceOwnerSessionId(traceId, authoritySessionId); if (!ownerSessionId) return; + let matchedMessage = false; updateSessionMessages(ownerSessionId, (source) => source.map((message) => { if (!messageMatchesTraceAuthority(message, traceId, authoritySessionId, ownerSessionId)) return message; + matchedMessage = true; const mergedRunnerTrace = mergeRunnerTrace(message.runnerTrace, trace); const traceStatus = normalizedStatusText(trace.status ?? snapshot.status) ?? null; const clearCompletedDiagnostics = shouldClearCompletedTurnDiagnostics(traceStatus, null); @@ -1259,10 +1262,25 @@ function nonBlockingProjection(projection: ProjectionDiagnostic | null): Project const projection = clearCompletedDiagnostics ? nonBlockingProjection(trace.projection ?? null) : trace.projection ?? runnerTrace.projection ?? message.projection ?? null; return { ...message, ...messageTimingPatchForMerge(message, trace), runnerTrace, error: clearCompletedDiagnostics ? null : error ?? message.error ?? null, projection, projectionStatus: projection?.projectionStatus ?? null, projectionHealth: projection?.projectionHealth ?? null, blocker: projection?.blocker ?? null, updatedAt: new Date().toISOString() }; })); + if (!matchedMessage && ownerSessionId === activeSessionId.value) void refreshRealtimeSessionFromRest(ownerSessionId, `realtime-trace-snapshot:${traceId}`); markWorkbenchTraceProjected(traceId); scheduleSessionListRefresh(ownerSessionId, SESSION_LIST_REALTIME_REFRESH_DELAY_MS); } + async function refreshRealtimeSessionFromRest(sessionId: string, reason: string): Promise { + const id = normalizeWorkbenchSessionId(sessionId); + if (!id || id !== activeSessionId.value || realtimeSessionRefreshInFlight.has(id)) return; + realtimeSessionRefreshInFlight.add(id); + try { + recordActivity(reason); + const existing = sessions.value.find((item) => item.sessionId === id) ?? null; + const selected = await loadWorkbenchSession(id, existing); + if (selected && activeSessionId.value === id) applySelectedSessionDetail(selected, "system"); + } finally { + realtimeSessionRefreshInFlight.delete(id); + } + } + function completeTrace(traceId: string, result: AgentChatResultResponse): void { const authoritySessionId = traceResultSessionId(result); const ownerSessionId = traceOwnerSessionId(traceId, authoritySessionId);