diff --git a/gateway/config.py b/gateway/config.py index 470eee7f2..6c8825298 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -556,6 +556,18 @@ def load_gateway_config() -> GatewayConfig: os.environ["DISCORD_AUTO_THREAD"] = str(discord_cfg["auto_thread"]).lower() if "reactions" in discord_cfg and not os.getenv("DISCORD_REACTIONS"): os.environ["DISCORD_REACTIONS"] = str(discord_cfg["reactions"]).lower() + # ignored_channels: channels where bot never responds (even when mentioned) + ic = discord_cfg.get("ignored_channels") + if ic is not None and not os.getenv("DISCORD_IGNORED_CHANNELS"): + if isinstance(ic, list): + ic = ",".join(str(v) for v in ic) + os.environ["DISCORD_IGNORED_CHANNELS"] = str(ic) + # no_thread_channels: channels where bot responds directly without creating thread + ntc = discord_cfg.get("no_thread_channels") + if ntc is not None and not os.getenv("DISCORD_NO_THREAD_CHANNELS"): + if isinstance(ntc, list): + ntc = ",".join(str(v) for v in ntc) + os.environ["DISCORD_NO_THREAD_CHANNELS"] = str(ntc) # Telegram settings → env vars (env vars take precedence) telegram_cfg = yaml_cfg.get("telegram", {}) diff --git a/gateway/platforms/discord.py b/gateway/platforms/discord.py index d6580ab9a..703c75492 100644 --- a/gateway/platforms/discord.py +++ b/gateway/platforms/discord.py @@ -2193,9 +2193,11 @@ class DiscordAdapter(BasePlatformAdapter): # UNLESS the channel is in the free-response list or the message is # in a thread where the bot has already participated. # - # Config (all settable via discord.* in config.yaml): + # Config (all settable via discord.* in config.yaml or DISCORD_* env vars): # discord.require_mention: Require @mention in server channels (default: true) # discord.free_response_channels: Channel IDs where bot responds without mention + # discord.ignored_channels: Channel IDs where bot NEVER responds (even when mentioned) + # discord.no_thread_channels: Channel IDs where bot responds directly without creating thread # discord.auto_thread: Auto-create thread on @mention in channels (default: true) thread_id = None @@ -2206,9 +2208,18 @@ class DiscordAdapter(BasePlatformAdapter): parent_channel_id = self._get_parent_channel_id(message.channel) if not isinstance(message.channel, discord.DMChannel): + # Check ignored channels first - never respond even when mentioned + ignored_channels_raw = os.getenv("DISCORD_IGNORED_CHANNELS", "") + ignored_channels = {ch.strip() for ch in ignored_channels_raw.split(",") if ch.strip()} + channel_ids = {str(message.channel.id)} + if parent_channel_id: + channel_ids.add(parent_channel_id) + if channel_ids & ignored_channels: + logger.debug("[%s] Ignoring message in ignored channel: %s", self.name, channel_ids) + return + free_channels_raw = os.getenv("DISCORD_FREE_RESPONSE_CHANNELS", "") free_channels = {ch.strip() for ch in free_channels_raw.split(",") if ch.strip()} - channel_ids = {str(message.channel.id)} if parent_channel_id: channel_ids.add(parent_channel_id) @@ -2230,10 +2241,14 @@ class DiscordAdapter(BasePlatformAdapter): # Auto-thread: when enabled, automatically create a thread for every # @mention in a text channel so each conversation is isolated (like Slack). # Messages already inside threads or DMs are unaffected. + # no_thread_channels: channels where bot responds directly without thread. auto_threaded_channel = None if not is_thread and not isinstance(message.channel, discord.DMChannel): + no_thread_channels_raw = os.getenv("DISCORD_NO_THREAD_CHANNELS", "") + no_thread_channels = {ch.strip() for ch in no_thread_channels_raw.split(",") if ch.strip()} + skip_thread = bool(channel_ids & no_thread_channels) auto_thread = os.getenv("DISCORD_AUTO_THREAD", "true").lower() in ("true", "1", "yes") - if auto_thread: + if auto_thread and not skip_thread: thread = await self._auto_create_thread(message) if thread: is_thread = True