v9.1.1
Menu

Audit an Agent Trace for Step Limits and Loops

easyFREEAgent Loop Control & PlanningAI AgentsAI Agents 1

Problem Statement

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.

Background

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.

Your Task

Implement:

def audit_trace(steps, max_steps, repeat_limit):
  • steps: list of {"tool": str, "args": dict} - args may be absent, meaning {}.

Return {"ok": bool, "steps_used": int, "violations": list[str]} where violations are:

  • "step_limit:<len(steps)>" when the trace overran
  • "repeat_loop:<signature>@<start_index>" for each maximal run of length >= repeat_limit

Sort the violations list ascending before returning. ok is True only when it is empty.

Input/Output Format

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.

Sample

steps = [{"tool": "search", "args": {"q": "x"}}] * 3
print(audit_trace(steps, 10, 3)["violations"])
# ['repeat_loop:search|q=x@0']

Example

Input
steps = [{'tool': 'search', 'args': {'q': 'x'}}] * 3
print(audit_trace(steps, 10, 3)['violations'])
Output
['repeat_loop:search|q=x@0']
Reasoning
  • Inputs: steps is a trace of 3 actions, each the tool search called with the single argument q=xq = x. The budget max_steps is 10 and repeat_limit is 3.
  • Signatures: each step becomes the tool name, a pipe, then its arguments as key=value pairs in ascending key order. With one argument, all three steps read search|q=x, so positions 0, 1 and 2 are identical.
  • Runs: the identical signatures sit back to back with nothing in between, so they form one maximal run covering indices 0 to 2, of length 3. Since 3≥33 \ge 3, it is a loop, reported once at its first index: repeat_loop:search|q=x@0.
  • Step limit: the trace length is 3 and 3≤103 \le 10, so no budget breach is added.
  • Output: the violations list holds exactly one entry. Notice that with repeat_limit set to 4 the same trace would be clean, because a run of 3 falls short, giving ok true and no violations.

Constraints

  • 0 <= len(steps) <= 1000; max_steps >= 0; repeat_limit >= 2
  • Signature keys are sorted ascending; values are stringified with str()
  • Only consecutive identical signatures count as a loop
  • Each maximal run yields exactly one violation, at its start index
  • The step-limit check is strict: len(steps) > max_steps
  • The violations list is sorted ascending

Learn this in

More from AI Agents 1

solution.py

Test results

Sign in to run your code against the test cases.