diff --git a/web/hwlab-cloud-web/src/components/workbench/ConversationPanel.vue b/web/hwlab-cloud-web/src/components/workbench/ConversationPanel.vue index 5fd38bf5..9c883ca5 100644 --- a/web/hwlab-cloud-web/src/components/workbench/ConversationPanel.vue +++ b/web/hwlab-cloud-web/src/components/workbench/ConversationPanel.vue @@ -26,8 +26,6 @@ const clipboard = useClipboard(); const panelRef = ref(null); const { following, keepBottomAfterUpdate, onScroll: onPanelScroll, scrollToBottom } = useBottomFollowScroll(panelRef, { threshold: 56 }); const detailMessageId = ref(null); -const displayedDurationFloorMs = new Map(); -const sealedDurationMs = new Map(); const visibleMessages = computed(() => workbench.sessionDetailLoading ? [] : workbench.activeMessages); const hasRunningAgentMessages = computed(() => visibleMessages.value.some(isRunningMessage)); const { nowMs } = useWorkbenchNowTicker(hasRunningAgentMessages); @@ -58,16 +56,6 @@ watch(() => workbench.sessionDetailLoading, async () => { acknowledgeVisibleMessages(); }); -watch(visibleMessages, (messages) => { - const visibleKeys = new Set(messages.map(messageDurationFloorKey)); - for (const key of Array.from(displayedDurationFloorMs.keys())) { - if (!visibleKeys.has(key)) displayedDurationFloorMs.delete(key); - } - for (const key of Array.from(sealedDurationMs.keys())) { - if (!visibleKeys.has(key)) sealedDurationMs.delete(key); - } -}, { immediate: true }); - function openDetails(message: ChatMessage): void { detailMessageId.value = message.id; } @@ -259,63 +247,12 @@ function traceForDisplay(message: ChatMessage): ChatMessage["runnerTrace"] { function messageDurationMeta(message: ChatMessage): { text: string; label: string } | null { if (message.role !== "agent") return null; const timing = messageTimingForDisplay(message); - const rawDurationMs = isRunningMessage(message) ? durationSince(timing?.startedAt) : terminalMessageDurationMs(message, timing); - const durationMs = isRunningMessage(message) ? monotonicDisplayDurationMs(message, rawDurationMs) : sealedDisplayDurationMs(message, rawDurationMs); + const durationMs = isRunningMessage(message) ? durationSince(timing?.startedAt) : terminalMessageDurationMs(message, timing); if (durationMs === null) return null; const value = formatDuration(durationMs); return { text: `耗时 ${value}`, label: `总耗时:${value}` }; } -function monotonicDisplayDurationMs(message: ChatMessage, durationMs: number | null): number | null { - if (durationMs === null) return null; - const key = messageDurationFloorKey(message); - const previous = displayedDurationFloorMs.get(key); - const next = previous === undefined ? durationMs : Math.max(previous, durationMs); - if (next !== previous) displayedDurationFloorMs.set(key, next); - return next; -} - -function sealedDisplayDurationMs(message: ChatMessage, durationMs: number | null): number | null { - const key = messageDurationFloorKey(message); - const runningFloor = displayedDurationFloorMs.get(key); - const sealedFloor = sealedDurationMs.get(key); - const previous = maxDefinedDurationMs(runningFloor, sealedFloor); - displayedDurationFloorMs.delete(key); - if (durationMs === null) return previous ?? null; - const next = previous === null ? durationMs : Math.max(previous, durationMs); - if (next !== previous) sealedDurationMs.set(key, next); - return next; -} - -function maxDefinedDurationMs(...values: Array): number | null { - let maximum: number | null = null; - for (const value of values) { - if (typeof value !== "number" || !Number.isFinite(value)) continue; - maximum = maximum === null ? value : Math.max(maximum, value); - } - return maximum; -} - -function messageDurationFloorKey(message: ChatMessage): string { - const primary = firstNonEmptyString(message.traceId, message.runnerTrace?.traceId, message.turnId, message.id) ?? "unknown-agent-message"; - migrateVisibleTimingAliases(primary, [message.id, message.runnerTrace?.traceId, message.traceId, message.turnId]); - return primary; -} - -function migrateVisibleTimingAliases(primary: string, aliases: unknown[]): void { - for (const aliasValue of aliases) { - if (typeof aliasValue !== "string") continue; - const alias = aliasValue.trim(); - if (!alias || alias === primary) continue; - const timingSample = visibleTimingSamples.get(alias); - if (timingSample && !visibleTimingSamples.has(primary)) visibleTimingSamples.set(primary, { ...timingSample }); - const displayedDuration = displayedDurationFloorMs.get(alias); - if (displayedDuration !== undefined && displayedDurationFloorMs.get(primary) === undefined) displayedDurationFloorMs.set(primary, displayedDuration); - const sealedDuration = sealedDurationMs.get(alias); - if (sealedDuration !== undefined && sealedDurationMs.get(primary) === undefined) sealedDurationMs.set(primary, sealedDuration); - } -} - function messageActivityMeta(message: ChatMessage): { text: string; label: string } | null { if (!isRunningMessage(message)) return null; const timing = messageTimingForDisplay(message);