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_idwithin 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_webvssearch_web_v2vsweb_searchcount 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.
Metadata
Release files for savi-loop-guard 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| savi_loop_guard-0.1.0.tar.gz | 10.5 kB | With provenance | Details for savi_loop_guard-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| savi_loop_guard-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for savi_loop_guard-0.1.0-py3-none-any.whl |
Total release size: 18.1 kB
Release files / savi_loop_guard-0.1.0.tar.gz
| Download URL | savi_loop_guard-0.1.0.tar.gz |
|---|---|
| Size | 10.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c07b36cbc2f3141b6b6da021fd32c27ac0d2159db523fdb55c8c2d5486bd6c65
|
|
BLAKE2b-256 checksum How to use checksums |
4bcc6d4692f1fb80f708dfb11822be7ae2827424e76a7f419205e11deb7805be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 12, 2026.
Transparency logRelease files / savi_loop_guard-0.1.0-py3-none-any.whl
| Download URL | savi_loop_guard-0.1.0-py3-none-any.whl |
|---|---|
| Size | 7.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4bdc3a817fc9e24c13fb137c6d8615659b75f2e0d79c1ee43d1ee46ae7334bc3
|
|
BLAKE2b-256 checksum How to use checksums |
7571c6765a040ab6f318cf693ea47c428db12b224e13bf16ad8c1d0464fa772b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 12, 2026.
Transparency logSecurity for savi-loop-guard 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for savi_loop_guard-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 12, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.