Agent you create has this protection on by default — no import, no flag. Polling a status endpoint that actually changes state is not flagged; a genuine stall or A -> B -> A -> B oscillation is.
Result-aware tool-loop detection is wired into every
Agent as of PR #3005 (release after 2026-07-14). Earlier releases required import praisonaiagents.plugins.loop_detection_plugin to activate the BEFORE_TOOL hook — that plugin still works but is no longer necessary. Upgrade to pick up the built-in detection plus the fixed doom-loop consecutive-failure signal.Quick Start
1
It's already on
Result-aware tool-loop detection runs on every
Agent. No import, no configuration.2
Tune the thresholds
Override the per-agent config before the first tool call.
3
Turn it off
Disable detection for deterministic replay agents that repeat identical calls on purpose.
How It Works
The detector records each tool call before execution, checks three detectors, then back-fills the result hash after execution so progress breaks the streak. A warning fires once per autonomous turn — the next iteration’s prompt is prefixed with[System: repeated <detector> detected. Try a different approach. …], giving the model one chance to change course before a critical verdict blocks execution entirely.
Detectors
poll_no_progress uses heuristic tool name matching — tools with “status”, “poll”, “check”, “wait”, “ping”, or “health” in their name are classified as polling tools.Configuration Options
Per-
Agent detection is created lazily on the first tool call, so Agent(...) init has zero overhead. Set agent._loop_detector_config = LoopDetectionConfig(...) before the first tool call to override defaults.Common Patterns
Polling a status endpoint
Raise thresholds and keep detection on.Aggressive detection for short-lived agents
Disable a specific detector
Turn offping_pong when two tools legitimately alternate.
User Interaction Flow
Here’s what a user sees when the detector fires during an autonomous run.- After the warning fires, the next autonomous turn’s prompt is prefixed with
[System: repeated <detector> detected. Try a different approach. <message>]. - If the agent still cannot break out of the pattern and hits
critical_thresholdon the same(tool, args)fingerprint, the offending call is skipped and the tool result becomes{"error": "...", "loop_blocked": True}— the model sees this on its next observation and typically self-corrects. - The whole path is a soft-block, not an exception — trace spans, stream events, and
AFTER_TOOLhooks all still fire, so telemetry stays consistent.
Relationship to Loop Guard
Loop Detection is now always-on alongside Loop Guard (docs). Loop Detection catches identical-argument / no-progress / ping-pong fingerprints at any frequency and back-fills result hashes so polling with progress is not flagged. Loop Guard counts per-turn tool calls with idempotent-vs-mutating thresholds. Both fire through the sameblocked_result path, so trace spans, stream events, and AFTER_TOOL hooks stay consistent regardless of which one triggers.
Best Practices
Trust the defaults
Trust the defaults
Every
Agent already has result-aware detection with reasonable thresholds. Only tune when a legitimate use case (long polling, deterministic replay) requires it.Tune thresholds, not the on/off switch
Tune thresholds, not the on/off switch
Set
agent._loop_detector_config = LoopDetectionConfig(enabled=True, warn_threshold=...) before the first tool call. Disabling entirely removes the safety net.Polling != loop
Polling != loop
The detector uses name + args + result-hash, so a poll that returns changing output does not increment the streak. If your polling tool returns identical output while it waits, disable the
poll_no_progress detector for that agent.Zero overhead
Zero overhead
The detector is stdlib-only (
hashlib, json) and lazy-constructed on the first tool call. Agent(...) init is unaffected.Legacy plugin (advanced)
Legacy plugin (advanced)
The
praisonaiagents.plugins.loop_detection_plugin module still exists as an advanced hook-based override — most users no longer need it. Use it only to override thresholds globally via the BEFORE_TOOL hook without per-agent code.Related
Loop Guard
Always-on per-turn tool-call guardrails
Autonomy Loop
Self-directed execution and doom loop thresholds

