From bd33a48a5839f235f17ffa1cc2542852ce55067f Mon Sep 17 00:00:00 2001 From: kfa-ai <258095375+kfa-ai@users.noreply.github.com> Date: Wed, 13 May 2026 23:11:14 -0700 Subject: [PATCH] feat(whatsapp): surface quoted reply metadata --- scripts/whatsapp-bridge/bridge.js | 8 ++++- tests/gateway/test_whatsapp_formatting.py | 39 +++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/scripts/whatsapp-bridge/bridge.js b/scripts/whatsapp-bridge/bridge.js index 9ab6118da1b..9ff64471e56 100644 --- a/scripts/whatsapp-bridge/bridge.js +++ b/scripts/whatsapp-bridge/bridge.js @@ -300,7 +300,10 @@ async function startSocket() { const messageContent = getMessageContent(msg); const contextInfo = getContextInfo(messageContent); const mentionedIds = Array.from(new Set((contextInfo?.mentionedJid || []).map(normalizeWhatsAppId).filter(Boolean))); - const quotedParticipant = normalizeWhatsAppId(contextInfo?.participant || contextInfo?.remoteJid || ''); + const quotedMessageId = contextInfo?.stanzaId || null; + const quotedParticipant = normalizeWhatsAppId(contextInfo?.participant || '') || null; + const quotedRemoteJid = normalizeWhatsAppId(contextInfo?.remoteJid || '') || null; + const hasQuotedMessage = !!contextInfo?.quotedMessage; // Extract message body let body = ''; @@ -412,7 +415,10 @@ async function startSocket() { mediaType, mediaUrls, mentionedIds, + quotedMessageId, quotedParticipant, + quotedRemoteJid, + hasQuotedMessage, botIds, timestamp: msg.messageTimestamp, }; diff --git a/tests/gateway/test_whatsapp_formatting.py b/tests/gateway/test_whatsapp_formatting.py index 1cb4c7bf3d8..81b1a57c0c9 100644 --- a/tests/gateway/test_whatsapp_formatting.py +++ b/tests/gateway/test_whatsapp_formatting.py @@ -46,6 +46,10 @@ def _make_adapter(): adapter._message_queue = asyncio.Queue() adapter._http_session = MagicMock() adapter._mention_patterns = [] + adapter._dm_policy = "open" + adapter._allow_from = set() + adapter._group_policy = "open" + adapter._group_allow_from = set() return adapter @@ -287,6 +291,41 @@ class TestSendChunking: assert "Not connected" in result.error +# --------------------------------------------------------------------------- +# bridge event metadata +# --------------------------------------------------------------------------- + +class TestBridgeEventMetadata: + """WhatsApp bridge metadata is preserved for downstream consumers.""" + + @pytest.mark.asyncio + async def test_quoted_reply_metadata_is_preserved_in_raw_message(self): + adapter = _make_adapter() + data = { + "messageId": "incoming-msg", + "chatId": "15551234567@s.whatsapp.net", + "senderId": "15551234567@s.whatsapp.net", + "senderName": "Tester", + "chatName": "Tester", + "isGroup": False, + "body": "approved", + "hasMedia": False, + "mediaUrls": [], + "quotedMessageId": "outbound-msg", + "quotedParticipant": "99999999999@s.whatsapp.net", + "quotedRemoteJid": "15551234567@s.whatsapp.net", + "hasQuotedMessage": True, + } + + event = await adapter._build_message_event(data) + + assert event is not None + assert event.raw_message["quotedMessageId"] == "outbound-msg" + assert event.raw_message["quotedParticipant"] == "99999999999@s.whatsapp.net" + assert event.raw_message["quotedRemoteJid"] == "15551234567@s.whatsapp.net" + assert event.raw_message["hasQuotedMessage"] is True + + # --------------------------------------------------------------------------- # display_config tier classification # ---------------------------------------------------------------------------