The defining failure of the first generation of autonomous agents was not bad reasoning - it was never stopping. AutoGPT would search the same query, read the same page, decide it needed more information, and search again, until someone killed the process. Every serious agent runtime now ships a guard that watches the trace and trips.
An agent trace is a list of steps, each an action with arguments. Two guards:
Step limit. If the trace is longer than max_steps, that is a breach - the agent overran its budget.
Repeat loop. Compute a canonical signature for each step:
tool + "|" + ",".join(f"{k}={args[k]}" for k in sorted(args))
Then look for consecutive runs of identical signatures. A maximal run of length >= repeat_limit is one breach, reported once, at the run's starting index.
Consecutive matters. A, B, A, B, A, B is a ping-pong, not a stuck action - a naive implementation that just counts occurrences would flag it, and would then trip on any agent that legitimately alternates between two tools. Only an unbroken run counts here.
Implement:
def audit_trace(steps, max_steps, repeat_limit):
Return {"ok": bool, "steps_used": int, "violations": list[str]} where violations are:
Sort the violations list ascending before returning. ok is True only when it is empty.
Returns the three-key dict. Argument values are stringified with str(), and argument keys are sorted so that {"a":1,"b":2} and {"b":2,"a":1} produce the same signature.
steps = [{"tool": "search", "args": {"q": "x"}}] * 3
print(audit_trace(steps, 10, 3)["violations"])
# ['repeat_loop:search|q=x@0']
steps = [{'tool': 'search', 'args': {'q': 'x'}}] * 3
print(audit_trace(steps, 10, 3)['violations'])['repeat_loop:search|q=x@0']
All three steps share the signature 'search|q=x', forming one maximal run of length 3 starting at index 0. The run length meets repeat_limit, so a single violation is reported. The trace is 3 steps against a limit of 10, so there is no step-limit breach.
0 <= len(steps) <= 1000; max_steps >= 0; repeat_limit >= 2str()len(steps) > max_stepsviolations list is sorted ascending