diff options
| author | YurenHao0426 <blackhao0426@gmail.com> | 2026-02-13 05:21:48 +0000 |
|---|---|---|
| committer | YurenHao0426 <blackhao0426@gmail.com> | 2026-02-13 05:21:48 +0000 |
| commit | 257b5bcbd09d4a6b7b1b27d7db4cc2aeed766c39 (patch) | |
| tree | 3bb7f0c590e0dfe1b2834069be729ef8c5fb3e4f | |
| parent | b6f21c210ee804782eba2e7c30c2ccdcbd95bffb (diff) | |
Deduplicate merged trace messages and fix double-count in context
- Add dedup helper in computeMergedMessages to remove duplicate messages
by ID across all merge strategies (e.g. A-B-C + A-D-C → A-B-D-C)
- Fix getActiveContext adding merged trace messages twice (from both
outgoingTraces and mergedTraces)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| -rw-r--r-- | frontend/src/store/flowStore.ts | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/frontend/src/store/flowStore.ts b/frontend/src/store/flowStore.ts index 72298b8..665030b 100644 --- a/frontend/src/store/flowStore.ts +++ b/frontend/src/store/flowStore.ts @@ -1070,9 +1070,9 @@ const useFlowStore = create<FlowState>((set, get) => { } }); - // Check merged traces - const activeMerged = (node.data.mergedTraces || []).filter((m: MergedTrace) => - activeIds.includes(m.id) + // Check merged traces (skip if already added from outgoingTraces above) + const activeMerged = (node.data.mergedTraces || []).filter((m: MergedTrace) => + activeIds.includes(m.id) && !tracesById.has(m.id) ); activeMerged.forEach((m: MergedTrace) => { contextMessages.push(...m.messages); @@ -1898,6 +1898,18 @@ const useFlowStore = create<FlowState>((set, get) => { return allMessages; }; + // Deduplicate messages by ID, keeping first occurrence + // This handles cases like A-B-C + A-D-C merged at C, where A's messages appear in both traces + const dedup = (messages: Message[]): Message[] => { + const seen = new Set<string>(); + return messages.filter(msg => { + if (!msg.id) return true; // keep messages without ID + if (seen.has(msg.id)) return false; + seen.add(msg.id); + return true; + }); + }; + switch (strategy) { case 'query_time': { // Sort by query time, keeping Q-A pairs together @@ -1918,41 +1930,41 @@ const useFlowStore = create<FlowState>((set, get) => { }); pairs.sort((a, b) => a.time - b.time); - + const result: Message[] = []; pairs.forEach(pair => { if (pair.user) result.push(pair.user); if (pair.assistant) result.push(pair.assistant); }); - return result; + return dedup(result); } case 'response_time': { // Sort by response time, keeping Q-A pairs together const pairs: { user: Message | null; assistant: Message | null; time: number; trace: Trace }[] = []; - + sourceTraces.forEach(trace => { for (let i = 0; i < trace.messages.length; i += 2) { const user = trace.messages[i]; const assistant = trace.messages[i + 1] || null; const time = getMessageTimestamp(assistant || user, 'response'); - pairs.push({ - user: user ? tagMessage(user, trace) : null, - assistant: assistant ? tagMessage(assistant, trace) : null, + pairs.push({ + user: user ? tagMessage(user, trace) : null, + assistant: assistant ? tagMessage(assistant, trace) : null, time, trace }); } }); - + pairs.sort((a, b) => a.time - b.time); - + const result: Message[] = []; pairs.forEach(pair => { if (pair.user) result.push(pair.user); if (pair.assistant) result.push(pair.assistant); }); - return result; + return dedup(result); } case 'trace_order': { @@ -1963,7 +1975,7 @@ const useFlowStore = create<FlowState>((set, get) => { result.push(tagMessage(msg, trace)); }); }); - return result; + return dedup(result); } case 'grouped': { @@ -1974,21 +1986,21 @@ const useFlowStore = create<FlowState>((set, get) => { result.push(tagMessage(msg, trace)); }); }); - return result; + return dedup(result); } case 'interleaved': { // True interleaving - sort ALL messages by their actual time const allMessages = getAllMessagesWithTime(); - + // Sort by the earlier of query/response time for each message allMessages.sort((a, b) => { const aTime = a.msg.role === 'user' ? a.queryTime : a.responseTime; const bTime = b.msg.role === 'user' ? b.queryTime : b.responseTime; return aTime - bTime; }); - - return allMessages.map(m => m.msg); + + return dedup(allMessages.map(m => m.msg)); } case 'summary': { @@ -2000,7 +2012,7 @@ const useFlowStore = create<FlowState>((set, get) => { result.push(tagMessage(msg, trace)); }); }); - return result; + return dedup(result); } default: |
