fix: prevent Discord NO_REPLY bot loops - #29932
Conversation
Three-layer fix for Discord bot-to-bot silence token handling: 1. Entry filter (_handle_message): Drop Discord bot messages with content exactly "NO_REPLY" before they enter the agent loop. When DISCORD_ALLOW_BOTS=mentions, other bots' NO_REPLY must be ignored. 2. Backfill exclusion (_fetch_channel_context): Exclude NO_REPLY sentinel messages from channel history backfill so they don't contaminate session context. 3. Delivery suppression (send): Suppress literal NO_REPLY responses from being sent to Discord channels — it's a control/silence token, not user-facing content. Fixes noisy bot-to-bot loops caused by agent silence being surfaced as empty-response retries.
|
Thanks for the focused three-layer investigation. Current main has since centralized the outbound part of this behavior: Problems
Suggested changes
Automated hermes-sweeper review. |
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Two PRs address the Discord NO_REPLY loop through inbound filtering, history exclusion, and outbound suppression. Their Discord changes substantially overlap, but #29932 is focused while #29942 also bundles multiple unrelated fixes; moreover, current main already centralizes outbound NO_REPLY suppression, and both diffs target the removed pre-migration Discord module.
Related pull requests
- #29932
related— (+35/-0) — keep open for a narrow rework, not merge as-is: the diff directly filters bot-authored exact NO_REPLY messages, excludes them from history, and suppresses outbound delivery, but it edits the removed gateway/platforms/discord.py and its test reproduces the condition rather than exercising the active adapter. Consistent with the contributor keep_open review on #29932, port only the still-needed inbound/history hygiene to plugins/platforms/discord/adapter.py with adapter-level tests; drop the now-duplicated outbound change. - #29942 [closed]
duplicate— (+399/-16) — closed, relevant as an overlapping reference implementation but not a merge candidate: its Discord portion implements the same three layers as #29932, while most of the diff contains unrelated tool-result serialization, provider, compression, runtime-provider, and skill-sync changes. The contributor review explicitly required these concerns to be split, so its focused Discord logic may inform #29932 but the closed PR should not be reopened or merged.
Duplicates
#29932 and the Discord-specific portion of #29942 are substantially duplicate implementations of inbound NO_REPLY filtering, history exclusion, and outbound suppression; #29942 additionally contains extensive unrelated changes.
Suggested consolidation
Do not merge either branch as-is. Consolidate the remaining work in #29932 by retaining it open, rebasing onto current main, porting only justified inbound/history filtering to the active Discord adapter with live-path tests, and omitting outbound suppression already centralized on main; keep #29942 closed as the superseded, unfocused duplicate reference.
Complex graph
flowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
subgraph Dup29932 ["PRs duplicating each other"]
P29932["PR #29932 (open)"]
P29942["PR #29942 (closed)"]
end
class P29932 open
class P29942 closed
class P29932 target
click P29932 "https://github.com/NousResearch/hermes-agent/pull/29932"
click P29942 "https://github.com/NousResearch/hermes-agent/pull/29942"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed or no verify verdict yet (state tag in the node label).
Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 31 kB of PR diffs, 2 kB of issue/PR text, 2 kB of discussion (3 comments), 1 verify verdict. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
Summary
NO_REPLYbefore they can enter the agent loopNO_REPLYsentinel messages from Discord channel history backfillNO_REPLYplatform responses at delivery timeWhy
When bot-to-bot routing is enabled with
DISCORD_ALLOW_BOTS=mentions, a botNO_REPLYsentinel can be treated as a real prompt. If the receiving agent then intentionally stays silent, the gateway can surface empty-response retries and create noisy bot-to-bot loops.NO_REPLYshould behave as a control/silence token, not a user prompt.Verification
./venv/bin/python -m pytest tests/gateway/test_discord_bot_filter.py tests/gateway/test_discord_bot_auth_bypass.py -q