From b26f0b05ba2ef1f5001b9dd1bd8daeec8a600914 Mon Sep 17 00:00:00 2001 From: 777genius Date: Sun, 26 Apr 2026 21:52:24 +0300 Subject: [PATCH] fix: hide duplicate opencode runtime replies --- src/renderer/utils/teamMessageFiltering.ts | 25 +++++++++ .../utils/teamMessageFiltering.test.ts | 56 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/renderer/utils/teamMessageFiltering.ts b/src/renderer/utils/teamMessageFiltering.ts index 63f2cce1..47e551a4 100644 --- a/src/renderer/utils/teamMessageFiltering.ts +++ b/src/renderer/utils/teamMessageFiltering.ts @@ -90,6 +90,22 @@ function isRelayDuplicateOfVisibleMessage( return normalizeMessageText(message.text) === normalizeMessageText(original.text); } +function getRuntimeDeliveryRelayDuplicateKey( + message: InboxMessage, + relayOfMessageId: string +): string | null { + if (message.source !== 'runtime_delivery') { + return null; + } + const from = normalizeParticipant(message.from); + const to = normalizeParticipant(message.to); + const text = normalizeMessageText(message.text); + if (!from || !to || !text) { + return null; + } + return [relayOfMessageId, from, to, text].join('\0'); +} + export function filterTeamMessages( messages: InboxMessage[], options: { @@ -163,6 +179,8 @@ export function filterTeamMessages( .filter((entry): entry is readonly [string, InboxMessage] => entry !== null) ); + const seenRuntimeDeliveryRelayDuplicates = new Set(); + return list.filter((m) => { const relayOfMessageId = typeof m.relayOfMessageId === 'string' ? m.relayOfMessageId.trim() : ''; @@ -173,6 +191,13 @@ export function filterTeamMessages( if (relayOfMessageId === ownMessageId) { return true; } + const runtimeDuplicateKey = getRuntimeDeliveryRelayDuplicateKey(m, relayOfMessageId); + if (runtimeDuplicateKey) { + if (seenRuntimeDeliveryRelayDuplicates.has(runtimeDuplicateKey)) { + return false; + } + seenRuntimeDeliveryRelayDuplicates.add(runtimeDuplicateKey); + } return !isRelayDuplicateOfVisibleMessage( m, visibleMessagesById.get(relayOfMessageId), diff --git a/test/renderer/utils/teamMessageFiltering.test.ts b/test/renderer/utils/teamMessageFiltering.test.ts index b06197d3..f5b02d94 100644 --- a/test/renderer/utils/teamMessageFiltering.test.ts +++ b/test/renderer/utils/teamMessageFiltering.test.ts @@ -175,6 +175,62 @@ describe('filterTeamMessages', () => { expect(result.map((message) => message.messageId)).toEqual(['reply-1', 'reply-2']); }); + it('hides exact duplicate OpenCode replies for the same delivered app message', () => { + const messages = [ + makeMessage({ + messageId: 'user-request-1', + from: 'user', + to: 'team-lead', + source: 'user_sent', + text: 'Ask everyone to message me.', + }), + makeMessage({ + messageId: 'delivery-1', + from: 'team-lead', + to: 'bob', + source: 'runtime_delivery', + text: 'Please message the user directly.', + relayOfMessageId: 'user-request-1', + }), + makeMessage({ + messageId: 'reply-1', + from: 'bob', + to: 'user', + source: 'runtime_delivery', + text: 'Привет! Я готов к работе.', + relayOfMessageId: 'delivery-1', + }), + makeMessage({ + messageId: 'reply-2', + from: 'bob', + to: 'user', + source: 'runtime_delivery', + text: ' Привет! Я готов к работе. ', + relayOfMessageId: 'delivery-1', + }), + makeMessage({ + messageId: 'reply-3', + from: 'bob', + to: 'user', + source: 'runtime_delivery', + text: 'Дополнительный контекст после проверки.', + relayOfMessageId: 'delivery-1', + }), + ]; + + const result = filterTeamMessages(messages, { + timeWindow: null, + filter: { from: new Set(), to: new Set(), showNoise: true }, + searchQuery: '', + }); + + expect(result.map((message) => message.messageId)).toEqual([ + 'user-request-1', + 'reply-1', + 'reply-3', + ]); + }); + it('hides internal lead relay deliveries while keeping member replies', () => { const messages = [ makeMessage({