agent-ecosystem/src/main/services/team/mergeLiveLeadProcessMessages.ts

73 lines
2.5 KiB
TypeScript

import type { InboxMessage } from '@shared/types';
export function getLiveLeadProcessMessageKey(message: {
messageId?: string;
timestamp: string;
from: string;
text: string;
}): string {
if (typeof message.messageId === 'string' && message.messageId.trim().length > 0) {
return message.messageId;
}
return `${message.timestamp}\0${message.from}\0${(message.text ?? '').slice(0, 80)}`;
}
export function mergeLiveLeadProcessMessages(
durableMessages: InboxMessage[],
liveMessages: InboxMessage[]
): InboxMessage[] {
if (liveMessages.length === 0) {
return durableMessages;
}
const normalizeText = (text: string): string => text.trim().replace(/\r\n/g, '\n');
const isLeadThoughtLike = (msg: { source?: unknown; to?: string }): boolean =>
!msg.to && (msg.source === 'lead_process' || msg.source === 'lead_session');
const getLeadThoughtFingerprint = (msg: {
from: string;
text: string;
leadSessionId?: string;
}): string => `${msg.leadSessionId ?? ''}\0${msg.from}\0${normalizeText(msg.text)}`;
const existingTextFingerprints = new Set<string>();
for (const msg of durableMessages) {
if (typeof msg.from !== 'string' || typeof msg.text !== 'string') continue;
if (!isLeadThoughtLike(msg)) continue;
existingTextFingerprints.add(getLeadThoughtFingerprint(msg));
}
const leadProcessTextFingerprints = new Set<string>();
const contentSeen = new Map<string, number>();
const merged: InboxMessage[] = [];
const seen = new Set<string>();
for (const msg of [...durableMessages, ...liveMessages]) {
if (msg.source === 'lead_process' && !msg.to) {
const fp = getLeadThoughtFingerprint(msg);
if (existingTextFingerprints.has(fp) || leadProcessTextFingerprints.has(fp)) {
continue;
}
leadProcessTextFingerprints.add(fp);
}
if (typeof msg.to === 'string' && msg.to.trim().length > 0) {
const contentFp = `${msg.from}\0${msg.to}\0${(msg.text ?? '').replace(/\s+/g, ' ').slice(0, 100)}`;
const msgMs = Date.parse(msg.timestamp);
const existingMs = contentSeen.get(contentFp);
if (existingMs !== undefined && Math.abs(msgMs - existingMs) <= 5000) {
continue;
}
contentSeen.set(contentFp, msgMs);
}
const key = getLiveLeadProcessMessageKey(msg);
if (seen.has(key)) {
continue;
}
seen.add(key);
merged.push(msg);
}
merged.sort((left, right) => Date.parse(right.timestamp) - Date.parse(left.timestamp));
return merged;
}