diff --git a/CHANGELOG.md b/CHANGELOG.md index 28590fe3c..fb273a1bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,7 @@ - Pairing: replies now include sender ids for Discord/Slack/Signal/iMessage/WhatsApp; pairing list labels them explicitly. - Messages: default inbound/outbound prefixes from the routed agent’s `identity.name` when set. (#578) — thanks @p6l-richard - Signal: accept UUID-only senders for pairing/allowlists/routing when sourceNumber is missing. (#523) — thanks @neist +- Signal: ignore reaction-only messages so they don't surface as unknown media. (#616) — thanks @neist - Agent system prompt: avoid automatic self-updates unless explicitly requested. - Onboarding: tighten QuickStart hint copy for configuring later. - Onboarding: set Gemini 3 Pro as the default model for Gemini API key auth. (#489) — thanks @jonasjancarik diff --git a/src/signal/monitor.tool-result.test.ts b/src/signal/monitor.tool-result.test.ts index 5a051210d..2b760fee1 100644 --- a/src/signal/monitor.tool-result.test.ts +++ b/src/signal/monitor.tool-result.test.ts @@ -153,6 +153,42 @@ describe("monitorSignalProvider tool results", () => { ); }); + it("ignores reaction-only messages", async () => { + const abortController = new AbortController(); + + streamMock.mockImplementation(async ({ onEvent }) => { + const payload = { + envelope: { + sourceNumber: "+15550001111", + sourceName: "Ada", + timestamp: 1, + reactionMessage: { + emoji: "👍", + targetAuthor: "+15550002222", + targetSentTimestamp: 2, + }, + }, + }; + await onEvent({ + event: "receive", + data: JSON.stringify(payload), + }); + abortController.abort(); + }); + + await monitorSignalProvider({ + autoStart: false, + baseUrl: "http://127.0.0.1:8080", + abortSignal: abortController.signal, + }); + + await flush(); + + expect(replyMock).not.toHaveBeenCalled(); + expect(sendMock).not.toHaveBeenCalled(); + expect(updateLastRouteMock).not.toHaveBeenCalled(); + }); + it("does not resend pairing code when a request is already pending", async () => { config = { ...config, diff --git a/src/signal/monitor.ts b/src/signal/monitor.ts index cc989d796..b240aeb1b 100644 --- a/src/signal/monitor.ts +++ b/src/signal/monitor.ts @@ -315,11 +315,12 @@ export async function monitorSignalProvider( if (!envelope) return; if (envelope.syncMessage) return; - // Handle reaction messages - if (envelope.reactionMessage) { + const dataMessage = + envelope.dataMessage ?? envelope.editMessage?.dataMessage; + if (envelope.reactionMessage && !dataMessage) { const reaction = envelope.reactionMessage; if (reaction.isRemove) return; // Ignore reaction removals - const emoji = reaction.emoji ?? "👍"; + const emoji = reaction.emoji ?? "unknown"; const sender = resolveSignalSender(envelope); if (!sender) return; const senderDisplay = formatSignalSenderDisplay(sender); @@ -329,9 +330,6 @@ export async function monitorSignalProvider( // Future: could dispatch as a notification or store for context return; } - - const dataMessage = - envelope.dataMessage ?? envelope.editMessage?.dataMessage; if (!dataMessage) return; const sender = resolveSignalSender(envelope);