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:
snav 2026-05-13 20:03:15 -04:00 committed by Teknium
parent d557544560
commit d863773c81
6 changed files with 169 additions and 3 deletions

View file

@ -302,6 +302,43 @@ class TestLoadGatewayConfig:
assert config.thread_sessions_per_user is False
def test_bridges_discord_thread_require_mention_from_config_yaml(self, tmp_path, monkeypatch):
"""discord.thread_require_mention in config.yaml should reach the runtime env var."""
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
config_path = hermes_home / "config.yaml"
config_path.write_text(
"discord:\n"
" thread_require_mention: true\n",
encoding="utf-8",
)
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
monkeypatch.delenv("DISCORD_THREAD_REQUIRE_MENTION", raising=False)
load_gateway_config()
assert os.environ.get("DISCORD_THREAD_REQUIRE_MENTION") == "true"
def test_thread_require_mention_yaml_does_not_overwrite_env(self, tmp_path, monkeypatch):
"""Explicit env var should win over config.yaml (env > yaml precedence)."""
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
config_path = hermes_home / "config.yaml"
config_path.write_text(
"discord:\n"
" thread_require_mention: false\n",
encoding="utf-8",
)
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
monkeypatch.setenv("DISCORD_THREAD_REQUIRE_MENTION", "true") # user override
load_gateway_config()
# Env value preserved, not clobbered by yaml.
assert os.environ.get("DISCORD_THREAD_REQUIRE_MENTION") == "true"
def test_bridges_quoted_false_platform_enabled_from_config_yaml(self, tmp_path, monkeypatch):
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()