mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-25 05:52:34 +00:00
fix(discord): keep free-response channels inline
Free-response channels are intended as lightweight chat surfaces — the bot
responds to every message without requiring an @mention. But the auto-thread
gate only checked DISCORD_NO_THREAD_CHANNELS, not DISCORD_FREE_RESPONSE_CHANNELS,
so every message in a free-response channel still spawned a brand-new thread.
That turns a chat channel into a thread-spawning machine: 1 thread per message.
The user-facing docs at website/docs/user-guide/messaging/discord.md already
describe the intended behavior ("Free-response channels also skip auto-threading
— the bot replies inline rather than spinning off a new thread per message"),
so this is a code-vs-docs gap, not a design change.
Fix: OR is_free_channel into skip_thread alongside the existing no_thread_channels
check. One-line production change.
Regression test added at tests/gateway/test_discord_free_response.py:
test_discord_free_response_channel_skips_auto_thread asserts that a message
in a free-response channel never calls _auto_create_thread. Reverting the
one-line fix causes the test to fail with 'Expected mock to not have been
awaited. Awaited 1 times.' — i.e. the test demonstrates the bug concretely.
This commit is contained in:
parent
3633c8690b
commit
d557544560
2 changed files with 32 additions and 1 deletions
|
|
@ -4223,7 +4223,7 @@ class DiscordAdapter(BasePlatformAdapter):
|
||||||
if not is_thread and not isinstance(message.channel, discord.DMChannel):
|
if not is_thread and not isinstance(message.channel, discord.DMChannel):
|
||||||
no_thread_channels_raw = os.getenv("DISCORD_NO_THREAD_CHANNELS", "")
|
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()}
|
no_thread_channels = {ch.strip() for ch in no_thread_channels_raw.split(",") if ch.strip()}
|
||||||
skip_thread = bool(channel_ids & no_thread_channels)
|
skip_thread = bool(channel_ids & no_thread_channels) or is_free_channel
|
||||||
auto_thread = os.getenv("DISCORD_AUTO_THREAD", "true").lower() in {"true", "1", "yes"}
|
auto_thread = os.getenv("DISCORD_AUTO_THREAD", "true").lower() in {"true", "1", "yes"}
|
||||||
is_reply_message = getattr(message, "type", None) == discord.MessageType.reply
|
is_reply_message = getattr(message, "type", None) == discord.MessageType.reply
|
||||||
if auto_thread and not skip_thread and not is_voice_linked_channel and not is_reply_message:
|
if auto_thread and not skip_thread and not is_voice_linked_channel and not is_reply_message:
|
||||||
|
|
|
||||||
|
|
@ -446,6 +446,37 @@ async def test_discord_voice_linked_channel_skips_mention_requirement_and_auto_t
|
||||||
assert event.source.chat_type == "group"
|
assert event.source.chat_type == "group"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_discord_free_response_channel_skips_auto_thread(adapter, monkeypatch):
|
||||||
|
"""Free-response channels should reply inline, never spawn a new thread.
|
||||||
|
|
||||||
|
Without this, every message in a free-response channel would auto-create
|
||||||
|
a fresh thread (since the channel bypasses the @mention gate, every
|
||||||
|
message looks like a fresh trigger). That turns a "lightweight chat"
|
||||||
|
channel into a thread-spawning machine — see the docs at
|
||||||
|
website/docs/user-guide/messaging/discord.md which already describe
|
||||||
|
this as the intended behavior.
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("DISCORD_REQUIRE_MENTION", "true")
|
||||||
|
monkeypatch.setenv("DISCORD_FREE_RESPONSE_CHANNELS", "789")
|
||||||
|
monkeypatch.delenv("DISCORD_AUTO_THREAD", raising=False) # default true
|
||||||
|
|
||||||
|
adapter._auto_create_thread = AsyncMock()
|
||||||
|
|
||||||
|
message = make_message(
|
||||||
|
channel=FakeTextChannel(channel_id=789),
|
||||||
|
content="casual chat in free-response channel",
|
||||||
|
)
|
||||||
|
|
||||||
|
await adapter._handle_message(message)
|
||||||
|
|
||||||
|
adapter._auto_create_thread.assert_not_awaited()
|
||||||
|
adapter.handle_message.assert_awaited_once()
|
||||||
|
event = adapter.handle_message.await_args.args[0]
|
||||||
|
assert event.text == "casual chat in free-response channel"
|
||||||
|
assert event.source.chat_type == "group"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue