From de14d135c4eb668f0558863e8ad417fbea72f2bb Mon Sep 17 00:00:00 2001 From: lyon Date: Tue, 16 Jun 2026 23:56:11 +0800 Subject: [PATCH] fix: retry trace hydration pages --- web/hwlab-cloud-web/src/stores/workbench.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/web/hwlab-cloud-web/src/stores/workbench.ts b/web/hwlab-cloud-web/src/stores/workbench.ts index c8247f41..db4f3b1b 100644 --- a/web/hwlab-cloud-web/src/stores/workbench.ts +++ b/web/hwlab-cloud-web/src/stores/workbench.ts @@ -10,6 +10,8 @@ const DEFAULT_CODE_AGENT_TIMEOUT_MS = 1_800_000; const DEFAULT_GATEWAY_TIMEOUT_MS = 120_000; const TRACE_HYDRATION_PAGE_LIMIT = 100; const TRACE_HYDRATION_MAX_PAGES = 60; +const TRACE_HYDRATION_MAX_ATTEMPTS = 3; +const TRACE_HYDRATION_RETRY_DELAY_MS = 700; export const useWorkbenchStore = defineStore("workbench", () => { const projectId = ref(resolveInitialWorkbenchProjectId()); @@ -383,7 +385,7 @@ export const useWorkbenchStore = defineStore("workbench", () => { try { let sinceSeq = traceHydrationSinceSeq(message.runnerTrace); for (let page = 0; page < TRACE_HYDRATION_MAX_PAGES; page += 1) { - const result = await api.agent.getAgentTrace(traceId, activeProjectId.value, codeAgentTimeoutMs.value, () => activityRef.value, { sinceSeq, limit: TRACE_HYDRATION_PAGE_LIMIT }); + const result = await fetchTraceHydrationPage(traceId, sinceSeq); if (!result.ok || !result.data) return; applyTraceHydrationResult(traceId, result.data); const nextSinceSeq = traceNextSinceSeq(result.data, sinceSeq); @@ -395,6 +397,23 @@ export const useWorkbenchStore = defineStore("workbench", () => { } } + async function fetchTraceHydrationPage(traceId: string, sinceSeq: number): Promise> { + let lastResult: ApiResult | null = null; + for (let attempt = 0; attempt < TRACE_HYDRATION_MAX_ATTEMPTS; attempt += 1) { + const result = await api.agent.getAgentTrace(traceId, activeProjectId.value, codeAgentTimeoutMs.value, () => activityRef.value, { sinceSeq, limit: TRACE_HYDRATION_PAGE_LIMIT }); + if (result.ok && result.data) return result; + lastResult = result; + if (attempt < TRACE_HYDRATION_MAX_ATTEMPTS - 1) { + await delayTraceHydrationRetry(TRACE_HYDRATION_RETRY_DELAY_MS * (attempt + 1)); + } + } + return lastResult ?? { ok: false, status: 0, data: null, error: "trace_hydration_failed" }; + } + + function delayTraceHydrationRetry(ms: number): Promise { + return new Promise((resolve) => window.setTimeout(resolve, ms)); + } + async function hydrateTraceEvents(source: ChatMessage[] = messages.value): Promise { await Promise.all(source.filter(messageNeedsTraceHydration).slice(-12).map((message) => hydrateTraceEventsForMessage(message))); }