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.
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 defaults
Call
observe() for each bot-authored inbound turn and drop the turn when it returns False.2
Tune the budget with BotLoopPolicy
Pass a
BotLoopPolicy to change how quickly a loop trips and how long it stays quiet.3
Build the policy from YAML/kwargs
BotLoopPolicy.from_dict builds a policy from a config mapping and ignores unknown keys.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.
When to Enable
BotLoopGuard only matters when your gateway accepts bot-authored inbound messages and multiple bots can share a room.
Configuration Options
BotLoopPolicy declares the per-pair budget. 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.
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
Three patterns cover most gateway deployments. Group room with multiple assistants — use one guard per gateway and callobserve() 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.

