Lesson 7 / 25

Detecting No Progress

Catch repetition and oscillation with a small guard that remembers recent tool calls.

Busy but stuck

An agent can stay within every limit yet make no progress, for example calling the same tool with the same arguments again and again, or flipping between two states. The simplest guard remembers the last few calls and stops when the same call repeats several times.

A repeat guard

This ran as shown. The same read_file call on the third time trips the guard. sort_keys=True makes the arguments compare equal regardless of key order.

from collections import deque
import json

class RepeatGuard:
    def __init__(self, window=6, limit=3):
        self.recent = deque(maxlen=window)
        self.limit = limit

    def seen_too_often(self, name, args):
        key = (name, json.dumps(args, sort_keys=True))
        self.recent.append(key)
        return self.recent.count(key) >= self.limit

g = RepeatGuard()
for _ in range(3):
    print(g.seen_too_often("read_file", {"path": "a.txt"}))

Output:

False
False
True

Some repeats are fine

Polling a job status may legitimately repeat a call. Allow it with a larger limit or a wait between calls, but still cap the total.

Quick check: What does the RepeatGuard detect?

  • Slow network speeds
  • The same tool call with the same arguments repeating
  • Spelling mistakes
  • Missing API keys
Answer

The same tool call with the same arguments repeating — It counts identical recent calls and flags a loop that is going nowhere.