diff --git a/web/hwlab-cloud-web/src/stores/workbench.ts b/web/hwlab-cloud-web/src/stores/workbench.ts index 5e80774f..caaeed44 100644 --- a/web/hwlab-cloud-web/src/stores/workbench.ts +++ b/web/hwlab-cloud-web/src/stores/workbench.ts @@ -627,9 +627,10 @@ export const useWorkbenchStore = defineStore("workbench", () => { const traceId = firstNonEmptyString(message.traceId, message.runnerTrace?.traceId, previous?.traceId, previous?.runnerTrace?.traceId); const authority = traceId ? traceAuthorityById.value[traceId] ?? null : null; const preservedTrace = authority ?? previous?.runnerTrace ?? null; - if (!preservedTrace) return message; + const terminalSealPatch = messageTerminalSealPatchForProjectionMerge(message, previous); + if (!preservedTrace) return { ...message, ...terminalSealPatch }; const runnerTrace = message.runnerTrace ? mergeRunnerTrace(message.runnerTrace, preservedTrace) : preservedTrace; - return { ...message, ...messageTimingPatch(message), runnerTrace }; + return { ...message, ...terminalSealPatch, runnerTrace }; } function findExistingProjectionMessage(message: ChatMessage, existing: ChatMessage[]): ChatMessage | null { @@ -1868,6 +1869,16 @@ function messageTimingPatchForMerge(message: ChatMessage, value: unknown): Parti return messageTimingPatch(message); } +function messageTerminalSealPatchForProjectionMerge(message: ChatMessage, previous: ChatMessage | null): Partial { + const incomingTimingPatch = messageTimingPatch(message); + if (!previous || !isTerminalMessageStatus(previous.status)) return incomingTimingPatch; + const patch: Partial = { status: previous.status, traceAutoLifecycle: previous.traceAutoLifecycle ?? "terminal" }; + if (typeof previous.text === "string" && previous.text.trim()) patch.text = previous.text; + const previousTiming = normalizeTimingProjection(previous); + if (previousTiming?.durationMs == null) return { ...incomingTimingPatch, ...patch }; + return { ...messageTimingPatch(previous), ...patch }; +} + function messageStatusPatchForTerminalMerge(message: ChatMessage, resultStatus: string | null, terminal: boolean): Partial { if (!terminal || isTerminalMessageStatus(message.status)) return {}; if (resultStatus && isTerminalMessageStatus(resultStatus)) return { status: resultStatus as ChatMessage["status"] };