cd /news/ai-agents/who-spent-all-the-tokens-real-time-r… · home topics ai-agents article
[ARTICLE · art-95668] src=commandline.microsoft.com ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Who spent all the tokens? Real-time, run-scoped cost control for AI agents

TokenOps, an open-source system from The Agent Plane, provides real-time, run-scoped cost control for AI agents, addressing the problem of runaway token spend across multi-call runs. Unlike traditional budget caps and gateways that operate per request or after the fact, TokenOps tracks costs per run, enabling live stopping or redirecting of expensive agent executions. The system attributes every call to a run and supports budgets at run, agent type, and user segment levels, with in-path enforcement and steering capabilities.

read18 min views2 publishedAug 13, 2026
Who spent all the tokens? Real-time, run-scoped cost control for AI agents
Image: Commandline (auto-discovered)

An agent run can make many model calls, and each one costs tokens. And while one call is cheap, a run can require hundreds. It’s easy to lose track of the sum across the whole run. If an agent gets a weak result from a tool, it might retry, then retry again. A few hundred model calls later, that run may have spent more tokens than the task was worth. No single model call looks wrong, and when the monthly bill arrives, there’s no way to say which run caused it to balloon.

We’re getting past the era of tokenmaxxing, where the common fix for a weak run was to give it more: more reasoning, more retries, more sub-agents, more context. But this additive reflex has become the default.

The goal should be to get a high-quality result. But you also want to keep your agent runs efficient. To do that, you need to have two systemic capabilities: seeing where a run’s money went and stopping or redirecting a run while it’s still live.

This post is about creating that real-time, per-run cost control, using a system we built called TokenOps as the example.

Why a budget cap isn’t enough #

The usual control is a monthly budget cap on an API key or a team. But a budget cap can’t stop a runaway, for a simple reason: it acts on a total that is only known after the fact. The cap trips after the month’s spend is tallied, which happens after the run that overspent has already finished.

In the end, a budget cap is a fail-safe. It’s meant to prevent your cost from going over a limit, but it’s by no means an optimization strategy. And when you want to extract more value out of the tokens you’re paying for, you need to optimize the run as a whole rather than just bound it.

Four facts anchor our argument:

Tokens are the unit of cost. Track both cost per token and value per token.Cost is created at each call. If you can’t see a call, you can’t control it.Without attribution, there’s no control. Every call should be tagged to its run and attributed to some component of your agent loop. LLM calls don’t happen on their own; they are a byproduct of your agent setup, your RAG quality, your tool structures, etc.The bill lags. To stop overspending, you must act during the run, not after it.

A gateway observes an isolated request. A run spans many. #

Most cost guard tools are gateways, which see only one unit: a completion request, keyed by an API key. A gateway caps, routes, and meters per request. That’s the right unit when a request is the whole job.

But an agent run isn’t one request. It’s a graph: a loop that retries, context that grows, sub-agents, a hand-off to a second service over the network. A gateway has no model of that graph. It sees isolated requests hitting an endpoint and doesn’t know that they belong to the same run, especially when the run spans several keys, providers, processes, or queues. That’s the core limit, and it isn’t a missing feature: the gateway’s unit of accounting is the key, and the money is spent by the run.

The fix is to carry a run id with the execution graph, so every call, wherever it runs, is attributed to the same run and counted against one budget. Here’s how some common tools scope their budgets today:

LiteLLM Portkey Cloudflare AI Gateway Langfuse TokenOps
Scope Request / project / user Request / key / workspace Request / user / team / app Trace / session / user Run / agent type / user segment
Budget Project / user Key / workspace / provider User / team / app / model / provider Run / agent type / user segment
Stop Yes Yes Yes No Yes
Steer Routing / fallback Routing / fallback Routing / fallback No Full
Enforce In-path In-path In-path Out-of-band In-path

LiteLLM is the closest to the landscape we describe above. Its per-team budgets can cap a multi-step loop, not just one call as long as the calls use the same key for the team.

Another thing to note is that much of the savings comes from routing, not pure rate-limiting. FrugalGPT [2] sends easy work to cheaper models by trying them first, RouteLLM does the same by predicting difficulty up front, and Cost-of-Pass finds that inference-time tricks often don’t pay for themselves. Routing lowers the expected bill, but it doesn’t bound the worst case—the runaway—which is what cost control is for. The two are complementary.

Placed on two axes, enforcement in-path vs. observability out-of-band and per-request vs. per-run, most existing enforcement tools operate at the request level. TokenOps occupies the in-path, run-scoped quadrant: it evaluates cumulative cost across an agent run and can enforce policy before the next action executes. The shape isn’t new: CaMeL uses a deterministic layer outside the model to enforce security constraints. TokenOps applies the same architectural idea to cost.

Per request Per run
Enforcement in-path LiteLLM / Portkey / Cloudflare AI Gateway TokenOps
Observability out-of-band Langfuse

Deciding out of band, enforcing in the path #

The design separates two things: deciding what to do and doing it.

The deciding is reading the run’s spend, evaluating policies, choosing an action. It’s prepared out of band, off the request’s critical path. The doing is a thin wrapper around the model client, the tool methods, the RAG pipelines, and other nodes of your agent graph. Before each call, the wrapper reads the run’s current spend and applies the decision the policies have generated: allow the call, shrink it, reroute it, or refuse it.

This is where latency has to be taken into account. The wrapper does read the run’s spend before every call. In a single process, that read is in memory and effectively free. Across processes, the count lives in a shared store, so a strict, fail-closed check costs one read of that store per call—a network round trip you can measure. The default avoids that on the hot path: it reads a local copy of the count and reconciles the true spend to the shared store just after the call, which is cheap but eventually consistent. Either way, the policy evaluation is precomputed, so the in-path work is a counter read and a comparison, not a policy run.

The control plane does three things with the events the agents emit: instrument (record each call), account (add it to the run’s ledger), enforce (apply a policy). Enforcement has two moves:

STEER keeps the run going by changing the next call: a cheaper model, a shorter prompt, fix a broken loop.HALT is a circuit breaker. Once it trips for a run, every later call on that run is refused until an operator resumes it.

Steering runs first. A halt is the last resort because halting a legitimate run causes the outage you were trying to avoid.

from tokenops.control.integration import wrap_complete 
from tokenops.control.config import build_governor 

governor = build_governor(store.governance_config_for(agent), price, ApplyControls()) 
complete = wrap_complete( 
    governor, controls, attr, 
    provider=provider, model=model, 
    dispatch=provider.complete, service="planner", 
) 

def governed(p, m, messages): 
    controls.begin_call() 
    request = CallRequest(attr=attr, provider=provider, model=m, 
                           estimated_input_tokens=estimate(messages), 
                           max_output_tokens=controls.call.max_output_tokens) 
    governor.pre_call(request)          # read spend, apply STEER/HALT decision 

    use_model = controls.call.model_override or m 
    messages = consume_carry(controls, messages)   # apply queued INJECT text 

    governor.ledger.admit(seg) 
    try: 
        response = traced(p, use_model, messages, 
                           max_output_tokens=controls.call.max_output_tokens) 
        return response 
    finally: 
        governor.ledger.complete(seg)   # record true cost back to the shared ledger

Because every call goes through the tokenops wrapper, every call is tagged with its run, its agent, and its step and then written to the shared ledger. That’s what lets you read a run’s spend back as a tree, which agent and which call spent what, instead of a single number on a bill. We call that token lineage.

The first bug: Two agents, one run, two budgets #

The test bench we used runs two agents in separate processes: a research agent that loops on a search tool and then hands its findings to a summarizer agent over HTTP. They shared one run id, and the run had a budget. It passed every test, but there was a bug.

Each process kept its own spend counter in memory. Both started at zero, and both saw the full run budget, so a $2 run cap was really $2 for the research agent and $2 more for the summarizer. Together they could spend twice the cap while every local check passed. It’s a distributed-systems bug: a budget with no single source of truth.

The fix was to move the counter out of each process into one shared ledger that every agent reads and writes, so the budget is measured against the run, not against each agent’s private view. After the fix, the research agent’s spend lands in the shared ledger as soon as it’s made, so when the summarizer starts, the remaining budget already reflects what research has spent. If the worst case of the summarizer’s next call wouldn’t fit what’s left, the “pre_call_worst_case” policy refuses that call and halts the run before the summarizer spends anything.

The general lesson: in a multi-agent run, a budget that each agent counts on its own is not a run budget. A run budget must be counted in one shared place so that you can attribute it to a broader use-case that drives value.

What a run’s cost is made of #

Before any policy, count what a run costs. The bill is the sum of a completion call’s input and output tokens at their prices, multiplied by the number of calls your agent run makes:

cost of a run  =  sum over calls of ( input tokens x input price  +  output tokens x output price ) 

calls per run  =  loop depth  x  fan-out breadth 
                  (sequential steps)     (parallel sub-agents)

So two things set the bill: the tokens in each call and the number of calls. The number of calls has two sources: a loop going around (depth) and sub-agents fanning out (breadth). And the ledger needs to see and attribute every call to its run.

That gives a short, closed list of things to guard: the tokens per call, the loop depth, the fan-out, and a ceiling on the total. “cost_budget” is the ceiling; the other nine policies each guard one part before the run cost explodes.

Policy Guards What goes wrong What it does
cost_budget the total run spend reaches the cap halt the run
pre_call_worst_case per-call the next call’s worst case would not fit the budget cap its output or halt
cost_guard per-call spend crosses about 80% of the budget steer cheaper (downgrade, trim), once per run
step_cap loop depth calls pass a per-run limit (a loop) halt the run
progress_guard loop depth the same action and result keep repeating inject a correction, then halt
output_runaway per-call a degenerate, repeating stream cancel, then a bounded retry
tool_fix loop depth a malformed or unknown tool call inject a synthetic error, halt on repeat
context_compaction per-call the prompt approaches the context ceiling dedup and pin the prompt
tool_output_cap per-call a tool returns an oversized payload store it, pass back a handle
concurrency_cap fan-out too many calls in flight at once queue or reject

The bug earlier was a failure of the substrate under this list: if the ledger can’t count the run, the ceiling is meaningless. Attribution comes first; every policy depends on it.

Enforcement is deterministic. Each policy is a detector and an action: the detector reads the ledger and raises a signal, and the action responds. No model runs in the enforcement path as of today because you don’t want the thing being governed deciding whether to stop itself. CaMeL [11] uses the same approach against prompt injection: a deterministic layer outside the model. Policies run before a call (pre_call), after each call (observe), or on a timer (tick) and choose one of eight actions: allow, mutate, inject, reject, queue, retry, cancel, halt.

Two of the per-call guards bound reasoning tokens, which is not a hack. Work on test-time compute (Snell et al., 2024) shows reasoning is a budget you can allocate, and s1’s budget forcing is a deterministic way to cap a model’s thinking. Overthinking is measured: on a trivial question, reasoning models have used about 20 times more tokens than a plain model with no gain in accuracy (Chen et al., ICML 2025).

The list was derived from cost, but it also matches the failure studies. OWASP’s Unbounded Consumption, Microsoft’s agentic-failure taxonomy (v2.0), and Berkeley’s MAST name the same modes: loops, no-progress repetition, degenerate output, oversized context and payloads, bad tool calls, and unbounded fan-out. Reaching the same list from two directions is good evidence that it isn’t missing an obvious mode. What it doesn’t cover is correctness: MAST found more than half of multi-agent failures are specification and verification problems, and a cost cap can’t tell a right answer from a wrong one. That needs a judge model, which we keep out of the enforcement path. These policies halt on spend, loops, and stalls, not on being wrong.

Running it against a real runaway #

To see it work, you need a real runaway. The test bench ships a leaky scenario to validate this: real web results from the search tool, but intentionally garbled, with text cut off and prices masked. The research agent can’t finish them, so it loops on the search tool. A plain step counter wouldn’t catch this well: the task might loop three times or 30, and one step can spend very different amounts depending on its context and tool output. Counting steps does not count dollars, and a reasoning-heavy step can burn thousands of tokens in a single step.

Under the policies, the run climbs toward the cap and the guards fire in order. One governed run’s event log:

governed run, event log 
  run <id>:  research -> summarize 
    observe               spend approaching the cap 
    cost_guard   ~80%     ->  downgrade model, inject "answer from what you have" 
    pre_call_worst_case   next call's max would exceed the remainder  ->  cap output 
    cost_budget  at cap   ->  HALT   (halt_reason: cost_budget)

The run id that carried the budget also carries the record, so the halt is explainable: the exact step and policy that ended the run, as well as the calls that led there.

Whether this is worth it is answered by numbers, not argument. Reported the way this field reports cost and quality, as a frontier, against the baseline that governs the demand for this post: no governance at all.

Cost: mean cost per completed run. 78.9% lower than no governance: $0.068 → $0.014 average spend per run (weighted total $1.839 → $0.388, N=27 scored trials across browser-use and MetaGPT scenarios).Completion: share of runs that finish under the cap, vs. no governance.+29pp: 67% → 96% within-cap success (18/27 → 26/27), N=27.

What this doesn’t do: Decide if the spend was worth it #

To be clear about the boundary: everything above governs cost. It bounds what a run can spend, steers it when it starts to drift and stops it when it runs away. It does not decide whether the spend was worth it. A cost cap halts on dollars; it cannot see whether the dollars bought a correct answer.

That is the next layer that we’re building towards, and cost control is its prerequisite: you can only safely let a run spend more where it pays if you can also stop it when it does not. The direction is known. Cost-of-Pass (Stanford) measures the expected cost of a correct answer and finds that past a point, more spend rarely buys enough correctness to justify it. Given a value estimate per run, resolved ticket, passing test, accepted PR, the budget can scale with it: more room for a high-value run, less for an exploratory one. Test-time-compute work already puts more tokens where they change the answer, and stop-when-confident methods end a reasoning chain once more tokens stop improving a confidence signal. With those signals, cost_guard’s rule should eventually become: stop when the next dollar stops adding value.

We have not built that layer. The cost control ships today; the value layer is a direction with real parts, cost per outcome as the metric, utility-aware allocation as the mechanism, a confidence or verifier signal as the trigger, that no one has closed into a production loop yet, us included.

Where this sits in the stack #

Most of the cost stacks already exist. The run-enforcement and steer-before-halt layers were the ones that were missing.

Layer What it does Where it lives today
Accounting reconciles the bill after the fact FOCUS spec (token and virtual-currency lifecycle since v1.2; v1.4 ratified June 2026; token-type breakdown planned for a future release)
Observability counts tokens per call, trace, and agent span OpenTelemetry GenAI conventions (token metrics + invoke_agent / execute_tool spans; no cost or budget)
Request enforcement caps a key or team, per request LiteLLM, Portkey, Cloudflare gateways (cost is an estimate; the budget is per key)
Step bounds caps iterations, not dollars LangGraph recursion_limit, CrewAI max_iter (a single step can still spend heavily)
The threat names the attack OWASP LLM10: Unbounded Consumption / Denial of Wallet
Run enforcement one budget across the whole run TokenOps: out-of-band, deterministic, fail-closed-capable

From hand-tuned to self-tuning #

The policies here are hand-tuned and deterministic, which is what a breaker should be. They don’t have to stay hand-tuned. The next step is a loop that observes the system, measures which policies helped and which fired wrongly, and proposes changes: new policies from real traffic, thresholds tuned per workload. That’s also how the halt-accuracy and overhead numbers get measured over time.

The wider context: in June 2026, the Linux Foundation announced its intent to launch the Tokenomics Foundation, with the FinOps Foundation, to standardize how token spend is measured. The Tokenomics Foundation launched on August 4. Standards say what a token costs. They do not decide whether a given run should be spent on it. That decision is the layer this post describes.

The repository is open, the bench, the policies, the shared ledger, and the bug above: github.com/theagentplane/tokenops.

Appendix A. Deterministic control has precedent: CaMeL #

Keeping the model out of the enforcement path is not only our choice. CaMeL (Debenedetti and colleagues at Google, Google DeepMind, and ETH Zurich, 2025) defends against prompt injection by wrapping the model in a deterministic control layer: it extracts the control and data flow from the trusted query, so untrusted data the model reads cannot change what the program does. The threat is different from ours—injection rather than cost—but the design is the same: the enforcement point sits in code you can reason about, around the model, not inside the model you’re trying to constrain. CaMeL is also open that its safety carries a token overhead, which is the same reason a cost breaker has to cost less than the spend it prevents.

Appendix B. References #

Appendix C. Glossary #

Run. One task from the first model call to the last: every call, tool call, loop, and sub-agent under a single run id, with one cumulative bill.Token lineage. A run’s spend broken down by which agent, step, and call produced it.Ledger. The shared record of a run’s spend, in-flight calls, and halt state, tagged by run, agent, and step.STEER / HALT. STEER keeps a run alive by changing the next call; HALT stops the run and refuses further calls until an operator resumes it.Out-of-band vs. in-path. The policy logic runs off the request’s critical path; the enforcement point is a thin wrapper on the call itself.Tokenmaxxing / valuemaxxing. Tokenmaxxing is improving a run by spending more tokens. Valuemaxxing is spending where it pays and stopping where it does not; it needs cost control first.

── more in #ai-agents 4 stories · sorted by recency
── more on @tokenops 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/who-spent-all-the-to…] indexed:0 read:18min 2026-08-13 ·