summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYurenHao0426 <blackhao0426@gmail.com>2026-02-13 05:21:48 +0000
committerYurenHao0426 <blackhao0426@gmail.com>2026-02-13 05:21:48 +0000
commit257b5bcbd09d4a6b7b1b27d7db4cc2aeed766c39 (patch)
tree3bb7f0c590e0dfe1b2834069be729ef8c5fb3e4f
parentb6f21c210ee804782eba2e7c30c2ccdcbd95bffb (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.ts48
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: