diff --git a/gateway/run.py b/gateway/run.py index 12b9adbbbc..df882d8e6b 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -623,7 +623,12 @@ class GatewayRunner: return await self._handle_set_home_command(event) # Check for pending exec approval responses - session_key_preview = f"agent:main:{source.platform.value}:{source.chat_type}:{source.chat_id}" if source.chat_type != "dm" else f"agent:main:{source.platform.value}:dm" + if source.chat_type != "dm": + session_key_preview = f"agent:main:{source.platform.value}:{source.chat_type}:{source.chat_id}" + elif source.platform and source.platform.value == "whatsapp" and source.chat_id: + session_key_preview = f"agent:main:{source.platform.value}:dm:{source.chat_id}" + else: + session_key_preview = f"agent:main:{source.platform.value}:dm" if session_key_preview in self._pending_approvals: user_text = event.text.strip().lower() if user_text in ("yes", "y", "approve", "ok", "go", "do it"): diff --git a/gateway/session.py b/gateway/session.py index eaa8d289b4..65528cdd82 100644 --- a/gateway/session.py +++ b/gateway/session.py @@ -154,6 +154,12 @@ def build_session_context_prompt(context: SessionContext) -> str: lines.append(f"**Source:** {platform_name} (the machine running this agent)") else: lines.append(f"**Source:** {platform_name} ({context.source.description})") + + # User identity (especially useful for WhatsApp where multiple people DM) + if context.source.user_name: + lines.append(f"**User:** {context.source.user_name}") + elif context.source.user_id: + lines.append(f"**User ID:** {context.source.user_id}") # Connected platforms platforms_list = ["local (files on this machine)"] @@ -325,8 +331,12 @@ class SessionStore: def _generate_session_key(self, source: SessionSource) -> str: """Generate a session key from a source.""" platform = source.platform.value - + if source.chat_type == "dm": + # WhatsApp DMs come from different people, each needs its own session. + # Other platforms (Telegram, Discord) have a single DM with the bot owner. + if platform == "whatsapp" and source.chat_id: + return f"agent:main:{platform}:dm:{source.chat_id}" return f"agent:main:{platform}:dm" else: return f"agent:main:{platform}:{source.chat_type}:{source.chat_id}" diff --git a/scripts/whatsapp-bridge/bridge.js b/scripts/whatsapp-bridge/bridge.js index 796b30ff9a..48e4d880b0 100644 --- a/scripts/whatsapp-bridge/bridge.js +++ b/scripts/whatsapp-bridge/bridge.js @@ -111,10 +111,15 @@ async function startSocket() { const senderNumber = senderId.replace(/@.*/, ''); // Skip own messages UNLESS it's a self-chat ("Message Yourself") - // Self-chat JID ends with the user's own number - if (msg.key.fromMe && !chatId.includes('status') && isGroup) continue; - // In non-group chats, fromMe means we sent it — skip unless allowed user sent to themselves - if (msg.key.fromMe && !isGroup && ALLOWED_USERS.length > 0 && !ALLOWED_USERS.includes(senderNumber)) continue; + if (msg.key.fromMe) { + // Always skip in groups and status + if (isGroup || chatId.includes('status')) continue; + // In DMs: only allow self-chat (remoteJid matches our own number) + const myNumber = (sock.user?.id || '').replace(/:.*@/, '@').replace(/@.*/, ''); + const chatNumber = chatId.replace(/@.*/, ''); + const isSelfChat = myNumber && chatNumber === myNumber; + if (!isSelfChat) continue; + } // Check allowlist for messages from others if (!msg.key.fromMe && ALLOWED_USERS.length > 0 && !ALLOWED_USERS.includes(senderNumber)) {