From ffa8b562e9c198dc5cac88b06b36f1ad1615889f Mon Sep 17 00:00:00 2001 From: Teknium Date: Sun, 22 Mar 2026 04:25:19 -0700 Subject: [PATCH] fix(discord): properly route slash event handling in threads Cherry-picked from PR #2017 by @simpolism. Fixes #2011. Discord slash commands in threads were missing thread_id in the SessionSource, causing them to route to the parent channel session. Commands like /usage and /reset returned wrong data or affected the wrong session. Detects discord.Thread channels in _build_slash_event and sets chat_type='thread' with thread_id. Two tests added. --- gateway/platforms/discord.py | 13 ++++++- tests/gateway/test_discord_slash_commands.py | 36 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/gateway/platforms/discord.py b/gateway/platforms/discord.py index af36d568..20b7a8d5 100644 --- a/gateway/platforms/discord.py +++ b/gateway/platforms/discord.py @@ -1500,7 +1500,17 @@ class DiscordAdapter(BasePlatformAdapter): def _build_slash_event(self, interaction: discord.Interaction, text: str) -> MessageEvent: """Build a MessageEvent from a Discord slash command interaction.""" is_dm = isinstance(interaction.channel, discord.DMChannel) - chat_type = "dm" if is_dm else "group" + is_thread = isinstance(interaction.channel, discord.Thread) + thread_id = None + + if is_dm: + chat_type = "dm" + elif is_thread: + chat_type = "thread" + thread_id = str(interaction.channel_id) + else: + chat_type = "group" + chat_name = "" if not is_dm and hasattr(interaction.channel, "name"): chat_name = interaction.channel.name @@ -1516,6 +1526,7 @@ class DiscordAdapter(BasePlatformAdapter): chat_type=chat_type, user_id=str(interaction.user.id), user_name=interaction.user.display_name, + thread_id=thread_id, chat_topic=chat_topic, ) diff --git a/tests/gateway/test_discord_slash_commands.py b/tests/gateway/test_discord_slash_commands.py index eea4dc2c..6c4911de 100644 --- a/tests/gateway/test_discord_slash_commands.py +++ b/tests/gateway/test_discord_slash_commands.py @@ -241,6 +241,42 @@ async def test_dispatch_thread_session_builds_thread_event(adapter): assert "TestGuild" in event.source.chat_name +# ------------------------------------------------------------------ +# _build_slash_event — preserve thread context for native slash commands +# ------------------------------------------------------------------ + + +def test_build_slash_event_preserves_thread_context(adapter): + interaction = SimpleNamespace( + channel=_FakeThreadChannel(channel_id=555, name="Planning"), + channel_id=555, + user=SimpleNamespace(display_name="Jezza", id=42), + ) + + event = adapter._build_slash_event(interaction, "/status") + + assert event.text == "/status" + assert event.source.chat_id == "555" + assert event.source.chat_type == "thread" + assert event.source.thread_id == "555" + assert "TestGuild" in event.source.chat_name + + +def test_build_slash_event_uses_group_context_for_channels(adapter): + interaction = SimpleNamespace( + channel=_FakeTextChannel(channel_id=123, name="general"), + channel_id=123, + user=SimpleNamespace(display_name="Jezza", id=42), + ) + + event = adapter._build_slash_event(interaction, "/status") + + assert event.source.chat_id == "123" + assert event.source.chat_type == "group" + assert event.source.thread_id is None + assert "TestGuild / #general" == event.source.chat_name + + # ------------------------------------------------------------------ # Auto-thread: _auto_create_thread # ------------------------------------------------------------------