fix: harden iMessage echo dedupe and reasoning suppression (#25897)

This commit is contained in:
Peter Steinberger
2026-02-25 00:43:44 +00:00
parent a9ce6bd79b
commit 2a11c09a8d
13 changed files with 273 additions and 40 deletions

View File

@@ -95,7 +95,7 @@ export function resolveIMessageInboundDecision(params: {
storeAllowFrom: string[];
historyLimit: number;
groupHistories: Map<string, HistoryEntry[]>;
echoCache?: { has: (scope: string, text: string) => boolean };
echoCache?: { has: (scope: string, lookup: { text?: string; messageId?: string }) => boolean };
logVerbose?: (msg: string) => void;
}): IMessageInboundDecision {
const senderRaw = params.message.sender ?? "";
@@ -224,15 +224,23 @@ export function resolveIMessageInboundDecision(params: {
// Echo detection: check if the received message matches a recently sent message (within 5 seconds).
// Scope by conversation so same text in different chats is not conflated.
if (params.echoCache && messageText) {
const inboundMessageId = params.message.id != null ? String(params.message.id) : undefined;
if (params.echoCache && (messageText || inboundMessageId)) {
const echoScope = buildIMessageEchoScope({
accountId: params.accountId,
isGroup,
chatId,
sender,
});
if (params.echoCache.has(echoScope, messageText)) {
params.logVerbose?.(describeIMessageEchoDropLog({ messageText }));
if (
params.echoCache.has(echoScope, {
text: messageText || undefined,
messageId: inboundMessageId,
})
) {
params.logVerbose?.(
describeIMessageEchoDropLog({ messageText, messageId: inboundMessageId }),
);
return { kind: "drop", reason: "echo" };
}
}
@@ -479,6 +487,11 @@ export function buildIMessageEchoScope(params: {
return `${params.accountId}:${params.isGroup ? formatIMessageChatTarget(params.chatId) : `imessage:${params.sender}`}`;
}
export function describeIMessageEchoDropLog(params: { messageText: string }): string {
return `imessage: skipping echo message (matches recently sent text within 5s): "${truncateUtf16Safe(params.messageText, 50)}"`;
export function describeIMessageEchoDropLog(params: {
messageText: string;
messageId?: string;
}): string {
const preview = truncateUtf16Safe(params.messageText, 50);
const messageIdPart = params.messageId ? ` id=${params.messageId}` : "";
return `imessage: skipping echo message${messageIdPart}: "${preview}"`;
}