mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-22 05:22:09 +00:00
feat(discord): add thread_require_mention for multi-bot threads
By default, once Hermes participates in a Discord thread (auto-created on @mention or replied in once) it auto-responds to every subsequent message in that thread without requiring further @mentions. That's the right default for one-on-one conversations and isolated channel threads. But it's a confirmed footgun in multi-bot threads. When a user invokes one bot per turn — addressing Codex first, then Hermes — every other bot in the thread also fires on every message, burning credits and spamming the channel. Author has hit this personally in active multi-bot research-team threads. Add a new `discord.thread_require_mention` config key (env: `DISCORD_THREAD_REQUIRE_MENTION`), default `false` to preserve existing behavior. When `true`, the in-thread mention shortcut is disabled and threads are gated the same way channels are. Explicit @mentions still pass through as expected. Mirrors the existing helper shape (config.extra > env > default) and the existing yaml→env bridge pattern used by `require_mention`. Changes: - gateway/platforms/discord.py: new `_discord_thread_require_mention()` helper; in_bot_thread shortcut now AND's with `not _discord_thread_require_mention()` - gateway/config.py: bridge `discord.thread_require_mention` from config.yaml to `DISCORD_THREAD_REQUIRE_MENTION` env var (mirrors the existing `require_mention` bridge two lines above) - hermes_cli/config.py: add `thread_require_mention: False` default to DEFAULT_CONFIG['discord'] - tests/gateway/test_discord_free_response.py: 4 new tests covering default behaviour (in-thread shortcut still works), enabled behaviour (mention required in threads), enabled+mentioned (mention still passes through), and yaml-via-config.extra path. Also clears DISCORD_* env vars in the `adapter` fixture so process-env state from the contributor's shell doesn't leak into per-test behaviour. - tests/gateway/test_config.py: 2 new tests covering the yaml→env bridge (both the apply-from-yaml and env-precedence-over-yaml paths) - website/docs/user-guide/messaging/discord.md: document the new env var + config key with multi-bot rationale; cross-link from `auto_thread` section Tested on Ubuntu 24.04.
This commit is contained in:
parent
d557544560
commit
d863773c81
6 changed files with 169 additions and 3 deletions
|
|
@ -908,6 +908,8 @@ def load_gateway_config() -> GatewayConfig:
|
|||
if isinstance(discord_cfg, dict):
|
||||
if "require_mention" in discord_cfg and not os.getenv("DISCORD_REQUIRE_MENTION"):
|
||||
os.environ["DISCORD_REQUIRE_MENTION"] = str(discord_cfg["require_mention"]).lower()
|
||||
if "thread_require_mention" in discord_cfg and not os.getenv("DISCORD_THREAD_REQUIRE_MENTION"):
|
||||
os.environ["DISCORD_THREAD_REQUIRE_MENTION"] = str(discord_cfg["thread_require_mention"]).lower()
|
||||
frc = discord_cfg.get("free_response_channels")
|
||||
if frc is not None and not os.getenv("DISCORD_FREE_RESPONSE_CHANNELS"):
|
||||
if isinstance(frc, list):
|
||||
|
|
|
|||
|
|
@ -3577,6 +3577,25 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
return {part.strip() for part in s.split(",") if part.strip()}
|
||||
return set()
|
||||
|
||||
def _discord_thread_require_mention(self) -> bool:
|
||||
"""Return whether thread participation requires @mention to follow up.
|
||||
|
||||
When ``False`` (default), once the bot has participated in a thread it
|
||||
keeps responding to every message in that thread without needing to be
|
||||
mentioned again — useful for one-on-one conversations.
|
||||
|
||||
When ``True``, the @mention requirement is enforced inside threads as
|
||||
well. Set this when multiple bots share a thread and you want each
|
||||
one to only fire on explicit @mention, avoiding bot-to-bot loops or
|
||||
unwanted cross-replies.
|
||||
"""
|
||||
configured = self.config.extra.get("thread_require_mention")
|
||||
if configured is not None:
|
||||
if isinstance(configured, str):
|
||||
return configured.lower() not in ("false", "0", "no", "off")
|
||||
return bool(configured)
|
||||
return os.getenv("DISCORD_THREAD_REQUIRE_MENTION", "false").lower() in ("true", "1", "yes", "on")
|
||||
|
||||
def _thread_parent_channel(self, channel: Any) -> Any:
|
||||
"""Return the parent text channel when invoked from a thread."""
|
||||
return getattr(channel, "parent", None) or channel
|
||||
|
|
@ -4209,8 +4228,15 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
)
|
||||
|
||||
# Skip the mention check if the message is in a thread where
|
||||
# the bot has previously participated (auto-created or replied in).
|
||||
in_bot_thread = is_thread and thread_id in self._threads
|
||||
# the bot has previously participated (auto-created or replied in)
|
||||
# — UNLESS thread_require_mention is enabled, in which case threads
|
||||
# are gated the same as channels. Useful when multiple bots share
|
||||
# a thread.
|
||||
in_bot_thread = (
|
||||
is_thread
|
||||
and thread_id in self._threads
|
||||
and not self._discord_thread_require_mention()
|
||||
)
|
||||
|
||||
if require_mention and not is_free_channel and not in_bot_thread:
|
||||
if self._client.user not in message.mentions and not mention_prefix:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue