Agen
How-to guides / Budgets and limits

Budgets and limits

Budgets stop an agent from spending more than you meant it to. They are set in x-agen/config.json (or per deployment with UpdateDeployment):

{
  "budget": { "maxTokensPerRun": 50000, "maxUsdPerRun": 0.10, "maxUsdPerDay": 5 }
}
Budget Enforced by What happens
maxTokensPerRun the engine Once the run’s input + output tokens reach the limit, it stops and reports (see below).
maxUsdPerRun the engine The same, by cost. Needs a provider that reports cost (OpenRouter does; direct OpenAI does not).
maxUsdPerDay the Hub Once today’s (UTC) spend of the deployment reaches it, no new work starts until the next UTC day: no task leases, no wake-ups, no scale-up (callers get 503 with the reset time). Runs already in flight finish.

How close the limits are

  • Before each model call, the output limit (max_tokens) is lowered to what is left of maxTokensPerRun, so a single answer cannot jump far past it. This applies to maxOutputTokens (8192 by default for bundles). An SDK agent defined in code without maxOutputTokens sends the remaining budget only once it is below 8192 tokens, because some providers reject or pre-charge large limits.
  • The input of the next call still counts, so a run can end slightly over maxTokensPerRun. Keep maxOutputTokens modest for tight budgets.
  • maxUsdPerDay is checked when work starts, so the day’s spend can overshoot by the runs already in flight (at most maxUsdPerRun × concurrency).

Stopping at a limit

A run that reaches maxTurns, maxRunDuration, maxTokensPerRun or maxUsdPerRun, or keeps repeating itself (stuckRepeats), is not cut off empty-handed. It gets one more model call, without tools and with at most limits.reportTokens (default 1024) output tokens, asking it to report what it did, what it found and what is left. The run then ends succeeded with the outcome partial and a reason (max_turns, duration, budget or stuck), and the report is its output. That last call can take a run slightly past a token or cost budget (by its input plus reportTokens).

Set reportTokens to 0 to have runs fail at a limit instead, with outcome failed and the same reason.

The Hub records a budget.threshold event when a deployment has spent 50, 80 and 100% of maxUsdPerDay, each once per UTC day, so a notification target can hear about it.

Budget pressure

Once a deployment has spent 80% of its maxUsdPerDay, the tasks it leases carry budget_pressure. An agent on a routing model then runs at its router.budgetTier (default low), or lower if the task asked for less, so the rest of the day’s budget goes further. Other models are not affected.

The console’s Overview warns when a daily budget is 80% spent and when it is used up, and a task’s details show its tier and whether it ran under budget pressure.

Seeing spend

Each run records its tokens and cost: agen logs <name> prints them per run, ListRuns returns them, and the web UI shows them per deployment. agen ps marks a deployment whose daily budget is used up. The console’s Costs page also breaks calls down by the model that served them, with fallbacks, latency, tokens and cost (GetMetrics models).

Limits

Limits stop a run that goes wrong (a loop, a hung tool, a runaway delegation) even without a budget. Every limit has a default; set one to 0 to turn it off.

{
  "limits": { "maxRunDuration": "2h", "maxIdenticalToolCalls": 10, "maxQueuedTasks": 5000 }
}
Limit Where Default What happens
maxTurns x-agen/agent.md 16 Model calls per run; past it the run stops and reports.
maxOutputTokens x-agen/harness.json 8192 The most one model answer may produce.
maxRunDuration limits 1h Working time of a run, not counting approval waits; past it the run stops and reports.
reportTokens limits 1024 Output limit of the report call at a limit; 0: no report, the run fails.
maxIdenticalToolCalls limits 5 The same tool with the same arguments in one run; further identical calls are refused and the model is told to change course. A call that failed 3 times in a row with the same error is refused the same way.
stuckRepeats limits 4 Turns in a row with the same calls and the same results count as stuck: the run is told once to change approach, and if it goes on repeating it stops and reports with reason stuck.
modelRequestTimeout limits 10m One model request; it fails past it.
toolTimeout limits 10m One tool call (not call_agent, which the callee’s limits bound); the model gets a timeout error.
maxQueuedTasks limits 1000 Queued tasks per deployment; more are refused (RESOURCE_EXHAUSTED, webhooks get 429).
maxDelegationDepth, maxFanOut, maxTotalDelegations limits 3, 20, 50 See Connecting agents.
approvalTimeout permissions 1h How long an ask waits; at most 168h.

A deployment’s page in the console shows where it stands against its spend and queue limits.