# A Loop with Every Guard — Agent Loops, Stop Conditions and Token Budgets

Source: https://www.geekswithgeeks.com/en/agent-loops/loop-guarded-skeleton

> Combine step, token and time limits in one reusable budget object.

## One object owns the limits

Scattering `if` checks through the loop makes limits easy to forget. A small **Budget** object tracks steps, tokens and elapsed time, and answers one question: "may we continue, and if not, why?" The loop asks it once per turn.

## A Budget class

This ran as shown. Charging 3,000, 4,000 and 4,000 tokens trips the 10,000-token limit on the third step, and `reason()` says why.

```python
class Budget:
    def __init__(self, max_steps, max_tokens):
        self.max_steps, self.max_tokens = max_steps, max_tokens
        self.steps = self.tokens = 0

    def charge(self, tokens):
        self.steps += 1
        self.tokens += tokens

    def reason(self):
        if self.steps >= self.max_steps: return "step limit"
        if self.tokens >= self.max_tokens: return "token budget"
        return None

b = Budget(5, 10_000)
for used in (3000, 4000, 4000):
    b.charge(used)
    print(b.steps, b.tokens, b.reason())
```

Output:

```
1 3000 None
2 7000 None
3 11000 token budget
```

## Return a reason, not just a boolean

"Stopped" is useless in a log. "Stopped: token budget at step 3" tells you what to fix. Make every stop carry a reason string.

**Quiz:** Why centralise limits in one Budget object?

- [x] Scattered checks are easy to forget or apply inconsistently
- [ ] Python requires classes
- [ ] It makes the model smarter
- [ ] It removes the need for tests

*Answer:* Scattered checks are easy to forget or apply inconsistently. One owner of the limits keeps checks consistent and the stop reason easy to report.
