Skip to content

fix(discord): add multi-layer safety against bot-to-bot death-loops (#32791) - #33985

Closed
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/32791-discord-death-loop
Closed

fix(discord): add multi-layer safety against bot-to-bot death-loops (#32791)#33985
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/32791-discord-death-loop

Conversation

@Tranquil-Flow

Copy link
Copy Markdown
Contributor

What

Three-layer safety fix for multi-bot Discord channels: prevents ack-loop death-spiral (#32791).

Layer 1: free_response_channels no longer bypasses DISCORD_ALLOW_BOTS=mentions.
Layer 2: Anti-loop circuit breaker. After N bot replies in a channel (default 3), suspend auto-reply for M minutes (default 10).
Layer 3: In-band operator HALT. Known operators can post STOP/HALT to suspend auto-reply globally.

Files

  • plugins/platforms/discord/adapter.py (+127 lines)
  • tests/gateway/test_discord_safety_layers.py (+391 lines, 8 tests)

Tests

pytest tests/gateway/test_discord_safety_layers.py -v  # 8 passed
pytest tests/gateway/test_discord_bot_filter.py -v       # 8 passed
pytest tests/gateway/test_discord_free_response.py -v    # 36 passed

All 52 tests pass. 6/8 new tests fail without the production change. Ruff clean.

…ousResearch#32791)

Three-layer safety fix for multi-bot Discord channels:

Layer 1 — Config-semantics: free_response_channels no longer bypasses
DISCORD_ALLOW_BOTS=mentions. Bot messages in free-response channels
without @mention are blocked, matching documented behaviour.

Layer 2 — Anti-loop circuit breaker: after N consecutive bot replies
within a configurable window (default: 3 in 60s), auto-reply is
suspended for that channel for M minutes (default: 10 min).
Configurable via DISCORD_CIRCUIT_BREAKER_THRESHOLD / _WINDOW_S /
_COOLDOWN_S env vars.

Layer 3 — In-band operator HALT: when a known operator (DISCORD_OPERATOR_IDS)
posts STOP/HALT/KILL/FREEZE/CEASE, auto-reply is suspended across ALL
channels for M minutes (DISCORD_HALT_COOLDOWN_S, default: 10 min).
Gives operators an emergency stop that doesn't require host access.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists platform/discord Discord bot adapter comp/plugins Plugin system and bundled plugins labels May 28, 2026

@Tranquil-Flow Tranquil-Flow left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — this is a clean, well-structured fix.

Layer 1free_response_channels now respects DISCORD_ALLOW_BOTS=mentions. When a bot posts in a free-response channel without @mentioning us, the bypass is gated. Correctly handles the edge case where two Hermes profiles would otherwise reply to each other indefinitely.

Layer 2 — Per-channel circuit breaker with configurable window/threshold/cooldown. Three consecutive bot replies within 60s window trips a 10-minute suspension. Timestamps rotated efficiently with list comprehension — no unbounded growth.

Layer 3 — In-band operator HALT/STOP/KILL/FREEZE commands. Known operators can globally suspend auto-reply. Clean integration.

All 8 safety-layer tests pass plus the existing 44 Discord tests are unaffected (52 total).

CI note: test (2) failures are in test_discord_document_handling.py — document content injection assertions. Completely unrelated to this PR (different test file, different feature area). Pre-existing flake.

Ready to merge once CI is re-triggered or the flake is addressed separately.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the detailed writeup and the implementation — closing as out of scope.

Bot-to-bot communication isn't a supported topology in Hermes. The safe default (DISCORD_ALLOW_BOTS=none) blocks all bot-originated messages, so the death-loop is only reachable because the deployment opted into DISCORD_ALLOW_BOTS=mentions across multiple profiles specifically to wire Hermes bots replying to each other — which we don't support.

A couple of notes from review:

  • The issue's Layer-1 root cause doesn't hold on current main. free_response_channels does not bypass the bot filter: the on_message DISCORD_ALLOW_BOTS gate runs first and unconditionally, so an unmentioned bot message is dropped before free-response is ever consulted. The loop the incident hit comes from Discord's reply auto-mention satisfying allow_bots=mentions on every turn — which only matters once you've opted into bot-to-bot at all.
  • We're not adding per-channel circuit-breaker / operator-HALT machinery to babysit an unsupported multi-bot setup, and the config for it (thresholds, patterns, operator allowlist) would be new DISCORD_* env vars, which is against policy — .env is for secrets only, behavioral config goes in config.yaml.

Supported guidance: keep DISCORD_ALLOW_BOTS at its default of none. If you need to accept messages from a specific trusted bot, scope it narrowly — don't have multiple Hermes profiles reply to each other in a shared channel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists platform/discord Discord bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants