Skip to main content

savi-loop-guard

A zero-dependency Python library that detects when an AI agent is stuck in a loop: calling the same tool over and over, or firing calls far faster than any real workflow would. Drop it into your own agent code. No account, no API key, no network call, ever.

Built by SAVI as a standalone, dependency-free package, so you can detect these patterns in your own agent code without an account, an API key, or a dependency on SAVI's platform.


Install

pip install savi-loop-guard

No dependencies. Nothing else gets installed alongside it.


Quick start

Record each call as your agent makes it, then check for loops whenever you want (after every call, on a timer, whatever fits your loop):

from loop_guard import LoopGuard, CallEvent
from datetime import datetime, timezone

guard = LoopGuard()

guard.record(CallEvent(
    span_id="call_1",
    agent_id="doc-extractor",
    timestamp=datetime.now(timezone.utc),
    tool_call="search_web",
))

issues = guard.check()
for issue in issues:
    print(issue["type"], issue["agent_id"])

An issue looks like:

{"type": LoopType.VELOCITY, "agent_id": "doc-extractor", "elapsed_s": 12.4, "call_count": 6}
# or
{"type": LoopType.STRUCTURAL, "agent_id": "doc-extractor",
 "tool_call": "search_web", "tool_variants": ["search_web", "search_web_v2"], "call_count": 7}

Prevent the call instead of just observing it

check_before_call() records the event and raises immediately if it would trip a threshold, for callers who want to stop the loop rather than find out about it afterwards:

from loop_guard import LoopGuard, CallEvent, LoopDetected

guard = LoopGuard()

try:
    guard.check_before_call(event)
except LoopDetected as e:
    print(f"Blocked: {e.loop_type}")  # "velocity_loop" or "structural_loop"
    print(e.details)                  # the same dict check() would have returned

What it detects

Two independent checks:

  • Velocity loop: more than 5 calls from the same agent_id within a 30-second window.
  • Structural loop: the same tool called more than 5 times, with fuzzy matching so a broken agent can't dodge detection by alternating between near-identical tool names (search_web vs search_web_v2 vs web_search count as the same tool if their name tokens overlap enough).

All four numbers are configurable:

guard = LoopGuard(
    velocity_window_seconds=30,
    velocity_call_limit=5,
    structural_call_limit=5,
    tool_fuzzy_similarity_threshold=0.70,
)

How this compares

A few other standalone Python packages exist for this: agent-loop-detector, agent-loop-guard, agentguard-kit. All of them, like savi-loop-guard's record()/check() API, are post-hoc/observational; they analyze calls after they happen. savi-loop-guard adds check_before_call() on top for callers who want to prevent the call rather than just observe it, which none of those currently offer.


Known limitations

LoopGuard keeps every recorded event in memory for the life of the instance; nothing is ever pruned automatically. That's deliberate: structural-loop detection is a total call count with no time bound by design (a tool called 6 times over 3 hours is still a loop, not just a tool called 6 times in 30 seconds), so silently dropping "old" events would blind it to exactly the slow, steady loops it exists to catch.

In practice this means: for a short-lived task, a single LoopGuard() is fine as-is. For a long-running process, create a fresh LoopGuard() per logical unit of work (e.g. per agent run) rather than holding one open indefinitely, so memory doesn't grow without bound.


License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

savi_loop_guard-0.1.0.tar.gz (10.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

savi_loop_guard-0.1.0-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

Details for the file savi_loop_guard-0.1.0.tar.gz.

File metadata

  • Download URL: savi_loop_guard-0.1.0.tar.gz
  • Upload date:
  • Size: 10.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for savi_loop_guard-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c07b36cbc2f3141b6b6da021fd32c27ac0d2159db523fdb55c8c2d5486bd6c65
MD5 0e492efddcf86466b7ca1b519fb17f66
BLAKE2b-256 4bcc6d4692f1fb80f708dfb11822be7ae2827424e76a7f419205e11deb7805be

See more details on using hashes here.

Provenance

The following attestation bundles were made for savi_loop_guard-0.1.0.tar.gz:

Publisher: publish-loop-guard.yml on data-gras/savi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file savi_loop_guard-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for savi_loop_guard-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4bdc3a817fc9e24c13fb137c6d8615659b75f2e0d79c1ee43d1ee46ae7334bc3
MD5 9418059b8a74200dd826051a384bb695
BLAKE2b-256 7571c6765a040ab6f318cf693ea47c428db12b224e13bf16ad8c1d0464fa772b

See more details on using hashes here.

Provenance

The following attestation bundles were made for savi_loop_guard-0.1.0-py3-none-any.whl:

Publisher: publish-loop-guard.yml on data-gras/savi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page