diff --git a/tests/channels/test_discord_channel.py b/tests/channels/test_discord_channel.py index 82ef6c51..a0a03227 100644 --- a/tests/channels/test_discord_channel.py +++ b/tests/channels/test_discord_channel.py @@ -273,17 +273,41 @@ async def test_stop_is_safe_after_partial_start(monkeypatch) -> None: @pytest.mark.asyncio -async def test_on_message_ignores_bot_messages() -> None: - # Incoming bot-authored messages must be ignored to prevent feedback loops. +async def test_on_message_ignores_self_messages() -> None: + # Self-loop guard: messages from this bot's own account must be dropped (#3217). channel = DiscordChannel(DiscordConfig(enabled=True, allow_from=["*"]), MessageBus()) + channel._bot_user_id = "999" # simulate bot identity populated in on_ready() handled: list[dict] = [] channel._handle_message = lambda **kwargs: handled.append(kwargs) # type: ignore[method-assign] - await channel._on_message(_make_message(author_bot=True)) + await channel._on_message(_make_message(author_id=999, author_bot=True)) assert handled == [] + +@pytest.mark.asyncio +async def test_on_message_accepts_messages_from_other_bots() -> None: + # Multi-agent setups: messages from OTHER bots must be processed, not dropped (#3217). + channel = DiscordChannel(DiscordConfig(enabled=True, allow_from=["*"]), MessageBus()) + channel._bot_user_id = "999" + handled: list[dict] = [] + + async def capture_handle(**kwargs) -> None: + handled.append(kwargs) + + channel._handle_message = capture_handle # type: ignore[method-assign] + + await channel._on_message(_make_message(author_id=123, author_bot=True)) + + assert len(handled) == 1 + assert handled[0]["sender_id"] == "123" + + +@pytest.mark.asyncio +async def test_on_message_stops_typing_on_handle_exception() -> None: # If inbound handling raises, typing should be stopped for that channel. + channel = DiscordChannel(DiscordConfig(enabled=True, allow_from=["*"]), MessageBus()) + async def fail_handle(**kwargs) -> None: raise RuntimeError("boom")