Stuck-Loop Guard (Agent Loop Progress Detection)
The dominant computer-use failure mode is an agent burning its budget repeating
an action that has no effect — and the model usually can’t see its own loop, so
it must be caught mechanically from outside, by watching the stream of
(tool, args, result) triples. LoopGuard flags three patterns:
repeat— the same(tool, args)fired many times in a row;ping_pong— two actions alternating A-B-A-B with no progress;no_op— the observation (a screenshot/state digest) never changes.
It complements a step/time budget (which can’t tell a productive loop from a
stuck one) and the offline trajectory evaluator. Pure standard library
(collections + hashlib), deterministic; imports no PySide6.
Headless API
from je_auto_control import LoopGuard, digest_result
guard = LoopGuard(warn=8, critical=15)
for step in agent_steps:
verdict = guard.observe(step.tool, step.args,
digest_result(step.screenshot))
if verdict.level == "critical":
break # abort: stuck loop
if verdict.level == "warn":
nudge_the_model(verdict.pattern)
observe returns {pattern, level, count} where level is ok /
warn / critical once the run length crosses the thresholds. count is
the length of the detected run. digest_result makes a stable short hash of a
screenshot/observation (bytes or any JSON-able value). reset clears history.
Executor commands
A module-level default guard backs the executor/MCP surfaces so a flow can track progress across steps:
Command |
Effect |
|---|---|
|
Feed a step; returns |
|
Clear the default guard’s history. |
The same operations are exposed as MCP tools (ac_loop_guard_observe /
ac_loop_guard_reset) and as Script Builder commands under Agent.