BotLoopGuard breaks runaway bot-to-bot reply loops — two bots answering each other forever — by budgeting how many exchanges a pair may have inside a sliding window. Once a channel opts in with allow_bots: true, the guard is auto-instantiated per adapter — no code to wire.
BotLoopGuard is auto-instantiated per adapter, and any A↔B pair that exceeds 20 exchanges in a 60s window is suppressed for a 60s cooldown.
Two bots ping-pong replies; the guard counts each exchange and, once a pair passes its budget, drops the turn and opens a cooldown.
BotLoopGuard is a gateway-layer primitive: it decides whether to admit one bot’s reply to another bot. It differs from Loop Guard, which caps tool calls inside a single agent turn.Quick Start
1
Enable with allow_bots: true
Flip the opt-in on the channel — everything else uses the default budget (20 exchanges / 60s window / 60s cooldown).
2
Tune the budget
Add The same two fields exist on
bot_loop_protection keys to change how quickly a loop trips and how long it stays quiet.BotConfig for the Python constructor path:3
Advanced — wire the primitive yourself
Custom adapters that do not inherit
MessageHookMixin can call BotLoopGuard.observe(...) directly — this is the escape hatch, not the recommended path.How It Works
The guard tracks each bot pair in a sliding window; exchange #21 trips the budget and both bots go quiet for the cooldown.A → B and B → A collapse to the same pair key, so a ping-pong loop accrues one budget instead of two independent streams.
How adapters wire it
Every adapter inheritsMessageHookMixin.bot_loop_allows(sender, self_bot_id=...), the shared helper that folds the allow_bots opt-in and the per-pair budget into one verdict — a human sender always passes, a bot sender passes only when allow_bots: true and the pair is under budget.
When to Enable
BotLoopGuard only matters when your gateway accepts bot-authored inbound messages and multiple bots can share a room.
Configuration Options
TwoBotConfig fields turn the guard on and shape its budget. Both match praisonaiagents/bots/config.py.
bot_loop_protection accepts the same keys as BotLoopPolicy, coerced via BotLoopPolicy.from_dict(...). Every field matches praisonaiagents/bots/silence.py.
BotLoopPolicy.from_dict(data) builds a policy from a mapping; None returns the enabled default and unknown keys are ignored.
BotLoopPolicy.from_dict tolerates malformed numeric values — a typo like max_events_per_window: "abc" falls back to the field default instead of crashing the inbound path on the first bot message.
The runtime BotLoopGuard exposes this surface:
BotLoopGuard ships in the Python SDK only. TypeScript and Rust ports do not exist yet — do not wire it into docs/js/ or docs/rust/.Common Patterns
Onceallow_bots: true is set the guard runs automatically; these primitive-level patterns cover custom adapters and tests.
Group room with multiple assistants — use one guard per gateway and call observe() only when the sender is a bot.
now= values for deterministic time-dependent tests.
reset() after redeploy so leftover cooldowns from an earlier process don’t leak.
When It Fires vs Doesn’t
Only bot-authored inbound turns reach the guard; humans and single-bot deployments never callobserve().
Best Practices
Size the window and cooldown separately
Size the window and cooldown separately
Use a shorter
window_seconds with a higher cooldown_seconds for chatty rooms — the window sizes urgency, the cooldown sizes recovery.Disable with enabled=False, not a zero budget
Disable with enabled=False, not a zero budget
max_events_per_window=0 is clamped to 1 and hides intent. Set enabled=False to turn the guard off.Combine with Intentional Silence
Combine with Intentional Silence
Pair the guard with
allow_silence and Intentional Silence for full ambient-channel safety — the agent chooses to stay quiet, and the guard stops runaway loops.Related
Intentional Silence
The sibling
NO_REPLY primitive in the same silence.py file.Messaging Bots
Where bot inbound flow originates.
Loop Guard
Per-turn tool-call guard — a different layer inside one agent.
Gateway
Channel configuration where the guard sits.
Bot Gateway → Channel Security
The
allow_bots / bot_loop_protection YAML surface on gateway.yaml.
