pub struct LoopGuard { /* private fields */ }Expand description
Sliding-window detector for repeated tool calls.
The guard keeps the last window (tool_name, args) records in a
FIFO ring. On every LoopGuard::record, if the new key already appears
threshold times (including the call being recorded) in the buffer,
LoopDetectedError is returned. The new call is still recorded so
repeated calls to record after a detection stay deterministic.
Use LoopGuard::would_raise to peek at the next decision without
mutating the buffer.
Implementations§
Source§impl LoopGuard
impl LoopGuard
Sourcepub fn with_capacity(window: usize, threshold: usize) -> Self
pub fn with_capacity(window: usize, threshold: usize) -> Self
Construct a guard.
§Panics
Panics on invalid construction (matches the spirit of Python’s
ValueError, but in Rust idiom we treat invalid construction as a
programming bug rather than a recoverable error):
window < 2threshold < 2threshold > window
If you want a non-panicking constructor, see LoopGuard::try_new.
Sourcepub fn try_new(window: usize, threshold: usize) -> Result<Self, ConfigError>
pub fn try_new(window: usize, threshold: usize) -> Result<Self, ConfigError>
Fallible constructor. Returns Err(ConfigError) instead of panicking.
Sourcepub fn with_key_fn<F>(window: usize, threshold: usize, key_fn: F) -> Self
pub fn with_key_fn<F>(window: usize, threshold: usize, key_fn: F) -> Self
Construct a guard with a custom key function.
The key function decides which calls should be considered “the
same”. Two calls that produce equal Keys count toward the
threshold. Use this to ignore noisy fields like request_id or
timestamp that change every call but don’t represent real intent.
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
True if no calls have been recorded since construction or last reset.
Sourcepub fn recent_keys(&self) -> Vec<&Key> ⓘ
pub fn recent_keys(&self) -> Vec<&Key> ⓘ
Recent keys, oldest first.
Returned as borrowed references so callers do not pay an allocation
cost just to inspect the ring. Clone individual entries with
key.clone() if you need to keep them past the next record call.
Sourcepub fn record(
&mut self,
tool_name: &str,
args: &Value,
) -> Result<(), LoopDetectedError>
pub fn record( &mut self, tool_name: &str, args: &Value, ) -> Result<(), LoopDetectedError>
Record a call. Returns Err(LoopDetectedError) if the threshold is met.
The call is recorded into the ring before the count is checked, so subsequent calls observe the same offending entry until evicted.
Sourcepub fn would_raise(&self, tool_name: &str, args: &Value) -> bool
pub fn would_raise(&self, tool_name: &str, args: &Value) -> bool
Return true if the next record for this key would raise.
Lets callers preview the outcome without mutating the buffer. The simulation accounts for buffer eviction: if the buffer is already full and the oldest entry has the same key, the projected count loses one before gaining one.