Agent loops need budget exhaustion as a first-class terminal state

Agentic AI SeedlingPlanted Sep 2026

I treat budget exhaustion as a first-class terminal state—not as an exception, timeout, or embarrassing failure after the “real” work ends. An agent loop can stop because the model says it is done, an evaluator verifies the goal, a user aborts, an unrecoverable error occurs, or a resource ceiling is reached. Those endings mean different things. If I collapse them into one generic failure, I lose the information needed to report the result honestly, recover safely, and tune the system. The terminal-state type should therefore name which budget ended the run and carry the evidence: limit, consumption, remaining allowance, and interrupted step.

This is where cost becomes architecture. Tokens, tool calls, elapsed time, iteration count, and dollars are not interchangeable counters—they constrain different parts of the loop. A rapid sequence of cheap, useless calls can exhaust a step budget before a timeout matters. One hung tool can exhaust wall-clock time on its first step. A few expensive calls can cross a monetary cap while both other limits remain comfortable. I want these guards layered, because no single budget describes every runaway trajectory.

The enforcement point matters as much as the limit. I check the projected cost before authorising the next model or tool call, rather than discovering afterward that the run exceeded its allocation. Token capacity must include accumulated messages, tool results, prompt overhead, a reserve for shutdown, and an estimate of the next response. When the remaining allowance cannot cover that minimum, the loop should refuse the next action and enter its budget terminal state. A hard harness check is the authority—the model cannot negotiate it away.

I still tell the model what remains on every turn. Budget awareness lets it narrow scope, use cached evidence, choose a cheaper path, or assemble a partial result while there is enough room to do so. That does not replace enforcement; it creates a two-layer design. The model gets a chance to land the run cleanly, while the harness guarantees that spending stops. The same principle explains why reflection needs stopping criteria—another attempt is useful only while a defined allowance remains.

The terminal payload should preserve completed work and distinguish incompletion from incorrectness. “Budget exhausted” says the system stopped under policy; it does not say the task was impossible or the partial output was wrong. I would return completed steps, remaining work, the exhausted dimension, and enough accounting data to support a retry decision. That makes resumption explicit: simplify the task, restore context in a fresh run, allocate a justified larger budget, or ask a human to choose what matters next.

This classification also improves diagnosis. If many runs hit the same ceiling, I can ask whether the task class is under-budgeted, the plan uses too many turns, tool results are bloating context, or retries are consuming allocation without progress. A plain error rate hides those distinctions. So does allowing the loop to continue until coherence collapses—as context fills, the original goal can lose influence and extra turns can become less useful precisely when they become more expensive.

There is one bounded concession: for a single read-only, idempotent step whose worst-case cost is known and still fits within a separately reserved shutdown allowance, I may let the current step finish after a soft warning threshold is crossed. I would not extend that exception to external writes, messages, purchases, or any step whose cost is uncertain. The hard cap remains hard; the concession only uses capacity reserved in advance, and it never authorises another loop iteration.

Finally, I treat every budget terminal as an observable product event. I log consumption by step and tool, expose how close the run came to each limit, and test that exhaustion produces the promised partial-result shape. Then cost regression gates can catch a workflow that starts consuming more turns or money before customers discover it. A loop that merely stops is bounded. A loop that stops with a typed reason, preserved progress, and auditable accounting is operable.