diff --git a/extensions/signal/src/monitor/event-handler.ack-reaction.test.ts b/extensions/signal/src/monitor/event-handler.ack-reaction.test.ts index da97e9d8547..af6ef328601 100644 --- a/extensions/signal/src/monitor/event-handler.ack-reaction.test.ts +++ b/extensions/signal/src/monitor/event-handler.ack-reaction.test.ts @@ -186,6 +186,34 @@ describe("Signal ACK reactions", () => { expect(sendReactionSignal).not.toHaveBeenCalled(); }); + it("does NOT send ack when message body is empty (whitespace-only text, no attachment, no quote)", async () => { + const deps = makeDeps(); + const handler = createSignalEventHandler(deps); + await handler( + makeEvent({ + dataMessage: { message: " ", timestamp: 1700000000000 }, + }), + ); + + expect(sendReactionSignal).not.toHaveBeenCalled(); + }); + + it("sends ack when message has no text but has an attachment", async () => { + const deps = makeDeps(); + const handler = createSignalEventHandler(deps); + await handler( + makeEvent({ + dataMessage: { + message: "", + timestamp: 1700000000000, + attachments: [{ id: "att1", contentType: "image/png", size: 1024 }], + }, + }), + ); + + expect(sendReactionSignal).toHaveBeenCalledTimes(1); + }); + it("sends ack BEFORE dispatch", async () => { const callOrder: string[] = []; vi.mocked(sendReactionSignal).mockImplementation(async () => { diff --git a/extensions/signal/src/monitor/event-handler.ts b/extensions/signal/src/monitor/event-handler.ts index 7bb7492c23c..b571e5f50f1 100644 --- a/extensions/signal/src/monitor/event-handler.ts +++ b/extensions/signal/src/monitor/event-handler.ts @@ -702,9 +702,15 @@ export function createSignalEventHandler(deps: SignalEventHandlerDeps) { return; } + // Early body guard: if the message has no text, no attachment, and no quote it will be + // dropped at the bodyText check below — don't send a false ACK in that case. + const hasEarlyBody = Boolean( + messageText || dataMessage.attachments?.length || dataMessage.quote?.text?.trim(), + ); + // Send ACK reaction immediately — before any awaited I/O (attachment fetch, read receipt) // so the user gets instant visual feedback that their message was received. - if (typeof envelope.timestamp === "number") { + if (hasEarlyBody && typeof envelope.timestamp === "number") { maybeSendSignalAckReaction({ cfg: deps.cfg, agentId: route.agentId,