Skip to main content

Crate tool_loop_guard

Crate tool_loop_guard 

Source
Expand description

§tool-loop-guard

Detect when an LLM agent gets stuck calling the same tool with the same args.

When an LLM agent gets confused, the most common failure mode is calling the same tool with the same args over and over. A circuit breaker won’t catch this (no errors), a deadline won’t catch it (single calls are fast), but the wall clock keeps ticking and the bill keeps growing.

LoopGuard watches a sliding window of recent tool calls and returns LoopDetectedError the moment a (tool_name, args) pair repeats more than threshold times within the last window calls.

use serde_json::json;
use tool_loop_guard::{LoopGuard, LoopDetectedError};

let mut guard = LoopGuard::with_capacity(8, 3);

let args = json!({"q": "anthropic prompt cache"});
guard.record("search", &args).unwrap();
guard.record("search", &args).unwrap();
match guard.record("search", &args) {
    Ok(()) => unreachable!(),
    Err(LoopDetectedError { tool_name, count, window, .. }) => {
        assert_eq!(tool_name, "search");
        assert_eq!(count, 3);
        assert_eq!(window, 8);
    }
}

The default key is (tool_name, canonical_json(args)). For more exotic matching (for example, ignore a request_id field in args) pass a custom key_fn via LoopGuard::with_key_fn.

§Why not just serde_json::to_string?

serde_json::to_string does not sort object keys, so {"a":1,"b":2} and {"b":2,"a":1} would hash differently. This crate re-walks the serde_json::Value and emits a stable canonical form (sorted object keys, compact separators) so semantically identical argument blobs collide as expected. That matches Python’s json.dumps(args, sort_keys=True, separators=(",", ":")).

Structs§

LoopDetectedError
Raised when the same (tool_name, args) pair fires too often.
LoopGuard
Sliding-window detector for repeated tool calls.

Enums§

ConfigError
Errors from invalid LoopGuard construction.

Functions§

default_key_fn
Compute the canonical default key for a (tool_name, args) pair.

Type Aliases§

Key
A canonical (tool_name, args) key used by the default key function.
KeyFn
A user-supplied key function.