calute.runtime.loop_detection#
Tool-loop detection for Calute.
Detects repetitive tool call patterns and prevents infinite loops:
Same-call repetition: The same tool with the same arguments is called N times in a row without meaningful progress.
Ping-pong detection: Two tools alternate back and forth (A→B→A→B).
Total iteration cap: Hard limit on total tool calls per session turn.
Each detector emits observable events/log entries and can be configured with warning and critical thresholds.
- class calute.runtime.loop_detection.LoopDetectionConfig(same_call_warning: int = 3, same_call_critical: int = 5, pingpong_warning: int = 4, pingpong_critical: int = 6, max_tool_calls_per_turn: int = 25, enabled: bool = True)[source]#
Bases:
objectConfiguration for loop detection thresholds.
- same_call_warning#
Consecutive identical calls before warning.
- Type
int
- same_call_critical#
Consecutive identical calls before blocking.
- Type
int
- pingpong_warning#
Alternation count before warning.
- Type
int
- pingpong_critical#
Alternation count before blocking.
- Type
int
- max_tool_calls_per_turn#
Hard cap on total tool calls in one turn.
- Type
int
- enabled#
Master switch for loop detection.
- Type
bool
- enabled: bool = True#
- max_tool_calls_per_turn: int = 25#
- pingpong_critical: int = 6#
- pingpong_warning: int = 4#
- same_call_critical: int = 5#
- same_call_warning: int = 3#
- class calute.runtime.loop_detection.LoopDetector(config: calute.runtime.loop_detection.LoopDetectionConfig | None = None)[source]#
Bases:
objectStateful loop detector for a single agent turn.
Create a new LoopDetector for each turn (or session). Call
record_callafter every tool invocation. The detector returns aLoopEventwith severity OK, WARNING, or CRITICAL.Example
>>> detector = LoopDetector() >>> event = detector.record_call("search", {"q": "hello"}) >>> event.severity <LoopSeverity.OK: 'ok'>
- add_listener(callback) None[source]#
Register a callable invoked with each emitted LoopEvent.
Listeners receive every WARNING and CRITICAL event. Exceptions raised by listeners are caught and logged without interrupting detection.
- Parameters
callback – A callable that accepts a single
LoopEventargument.
- property call_count: int#
Return the total number of tool calls recorded so far.
- Returns
The count of tool calls stored in the internal history.
- record_call(tool_name: str, arguments: dict | str | None = None) LoopEvent[source]#
Record a tool call and check for loop patterns.
Appends the call to the internal history and runs all detection checks in order: max-calls cap, same-call repetition, and ping-pong alternation. The first non-OK result is returned immediately.
- Parameters
tool_name – Name of the tool being invoked.
arguments – The call arguments as a dict, a JSON string, or
None. Arguments are hashed for comparison; the raw values are not stored.
- Returns
A
LoopEventdescribing the detection result. SeverityCRITICALmeans the call should be blocked;WARNINGmeans it should be logged but allowed;OKmeans no pattern was detected.
- class calute.runtime.loop_detection.LoopEvent(severity: LoopSeverity, pattern: str, tool_name: str, details: str, call_count: int = 0)[source]#
Bases:
objectEmitted when a loop pattern is detected or when a call is checked.
Carries the severity, pattern type, and descriptive details for every tool call check performed by the
LoopDetector.- severity#
The severity level of the detection result.
- pattern#
The type of loop pattern detected. One of
"same_call","pingpong","max_calls","none", or"disabled".- Type
str
- tool_name#
Name of the tool that triggered the event.
- Type
str
- details#
Human-readable description of the detection result.
- Type
str
- call_count#
The relevant repetition or alternation count that triggered the event. Defaults to
0for OK events.- Type
int
- call_count: int = 0#
- details: str#
- pattern: str#
- severity: LoopSeverity#
- tool_name: str#
- class calute.runtime.loop_detection.LoopSeverity(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]#
Bases:
EnumSeverity level for a loop detection event.
- OK#
No loop pattern detected; tool call proceeds normally.
- WARNING#
A potential loop pattern has been detected but the call is still allowed. A log entry is emitted for observability.
- CRITICAL#
A confirmed loop pattern has been detected and the call should be blocked to prevent infinite execution.
- CRITICAL = 'critical'#
- OK = 'ok'#
- WARNING = 'warning'#