diff --git a/gateway/platforms/feishu.py b/gateway/platforms/feishu.py index 3b57db46d3..126a3b7a09 100644 --- a/gateway/platforms/feishu.py +++ b/gateway/platforms/feishu.py @@ -1970,8 +1970,8 @@ class FeishuAdapter(BasePlatformAdapter): if not message_id or self._is_duplicate(message_id): logger.debug("[Feishu] Dropping duplicate/missing message_id: %s", message_id) return - if getattr(sender, "sender_type", "") == "bot": - logger.debug("[Feishu] Dropping bot-originated event: %s", message_id) + if self._is_self_sent_bot_message(event): + logger.debug("[Feishu] Dropping self-sent bot event: %s", message_id) return chat_type = getattr(message, "chat_type", "p2p") @@ -3294,6 +3294,23 @@ class FeishuAdapter(BasePlatformAdapter): return self._post_mentions_bot(normalized.mentioned_ids) return False + def _is_self_sent_bot_message(self, event: Any) -> bool: + """Return True only for Feishu events emitted by this Hermes bot.""" + sender = getattr(event, "sender", None) + sender_type = str(getattr(sender, "sender_type", "") or "").strip().lower() + if sender_type not in {"bot", "app"}: + return False + + sender_id = getattr(sender, "sender_id", None) + sender_open_id = str(getattr(sender_id, "open_id", "") or "").strip() + sender_user_id = str(getattr(sender_id, "user_id", "") or "").strip() + + if self._bot_open_id and sender_open_id == self._bot_open_id: + return True + if self._bot_user_id and sender_user_id == self._bot_user_id: + return True + return False + def _message_mentions_bot(self, mentions: List[Any]) -> bool: """Check whether any mention targets the configured or inferred bot identity.""" for mention in mentions: diff --git a/tests/gateway/test_feishu.py b/tests/gateway/test_feishu.py index 14ed9e1715..cfb5d12fa1 100644 --- a/tests/gateway/test_feishu.py +++ b/tests/gateway/test_feishu.py @@ -743,6 +743,57 @@ class TestAdapterBehavior(unittest.TestCase): self.assertFalse(adapter._should_accept_group_message(SimpleNamespace(mentions=[other_mention]), sender_id, "")) + @patch.dict( + os.environ, + { + "FEISHU_BOT_OPEN_ID": "ou_hermes", + "FEISHU_BOT_USER_ID": "u_hermes", + }, + clear=True, + ) + def test_other_bot_sender_is_not_treated_as_self_sent_message(self): + from gateway.config import PlatformConfig + from gateway.platforms.feishu import FeishuAdapter + + adapter = FeishuAdapter(PlatformConfig()) + event = SimpleNamespace( + sender=SimpleNamespace( + sender_type="bot", + sender_id=SimpleNamespace(open_id="ou_other_bot", user_id="u_other_bot"), + ) + ) + + self.assertFalse(adapter._is_self_sent_bot_message(event)) + + @patch.dict( + os.environ, + { + "FEISHU_BOT_OPEN_ID": "ou_hermes", + "FEISHU_BOT_USER_ID": "u_hermes", + }, + clear=True, + ) + def test_self_bot_sender_is_treated_as_self_sent_message(self): + from gateway.config import PlatformConfig + from gateway.platforms.feishu import FeishuAdapter + + adapter = FeishuAdapter(PlatformConfig()) + by_open_id = SimpleNamespace( + sender=SimpleNamespace( + sender_type="bot", + sender_id=SimpleNamespace(open_id="ou_hermes", user_id="u_other"), + ) + ) + by_user_id = SimpleNamespace( + sender=SimpleNamespace( + sender_type="app", + sender_id=SimpleNamespace(open_id="ou_other", user_id="u_hermes"), + ) + ) + + self.assertTrue(adapter._is_self_sent_bot_message(by_open_id)) + self.assertTrue(adapter._is_self_sent_bot_message(by_user_id)) + @patch.dict( os.environ, {