Set an agent's budget
A budget caps each turn of an agent: how many model calls it makes, what they cost, and how long it takes. A turn that runs out fails, and the run says which limit it hit.
// in agents/order-desk/index.ts budget: { maxSteps: 6, maxCostUsd: 0.05, maxWallMs: 60_000 },# in agents/order_desk.py budget={"maxSteps": 6, "maxCostUsd": 0.05, "maxWallMs": 60_000},| Field | Caps | Default |
|---|---|---|
maxSteps |
Model calls in the turn. | 8 |
maxCostUsd |
The turn's model spend, in US dollars. | none |
maxWallMs |
The turn's time, in milliseconds. | 120000 |
A step is one model call. The tool calls the model asks for run between steps, so a turn that looks an order up and then answers takes two. Repairing a typed answer takes a step too.
Cost is what the models' registered prices make of the tokens each call used (see Models); a model registered with a price of zero never uses the cost budget. It's an estimate from the vendor's published prices: your provider's invoice is what you pay.
When a turn runs out
Section titled “When a turn runs out”Each limit fails the turn with its own error. kindgi runs start prints it
and exits 1; the run, on stdout, has "status": "failed" and the error in
its failureMessage. These are from acme.order-desk with one limit set low
at a time, on a local llama3.1 registered with a price.
Steps. After a model call that asks for more tool calls, with no steps left:
Error [budget-exceeded]: Agent turn steps budget exceeded (limit 1, observed 1)Cost. Checked after each model call, against the turn's total so far:
Error [budget-exceeded]: Agent turn cost budget exceeded (limit 0.0001, observed 0.0001084)Time. A timer that starts with the turn; when it fires, the model call in flight is cancelled:
Error [agent-turn-aborted]: Agent turn aborted: Request was aborted.kindgi runs journal <run-id> shows how far the run got.
Leave room for real models: one call to a hosted model takes a second or more, and a model on your own machine can take ten. A turn with a tool call makes two calls.
Handle it in your app
Section titled “Handle it in your app”The failed turn comes back as an error, with the limit in its fields:
import { KindgiApiError, createClient } from '@kindgi/sdk/client';
const kindgi = createClient(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
try { await kindgi.runs.start({ agent: 'acme.order-desk', input: { userMessage: 'Where is my order A-1001?' }, });} catch (err) { if (!(err instanceof KindgiApiError)) throw err; const e = err.error; if (e.code === 'server' && e.serverCode === 'budget-exceeded') { console.log(e.fields?.kind, e.fields?.limit, e.fields?.observed, e.fields?.runId); } else { throw err; }}steps 1 1 2cc56724-92e7-42e8-aefd-14ad5c294d1ffrom kindgi.client import Kindgi, KindgiApiError
kindgi = Kindgi() # KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi devtry: kindgi.runs.start(agent="acme.order-desk", input={"userMessage": "Where is my order A-1001?"})except KindgiApiError as err: if err.server_code == "budget-exceeded": print(err.details["kind"], err.details["limit"], err.details["observed"], err.details["runId"]) else: raisesteps 1 1 3deffc12-053e-43e3-b735-9a415d95645fA turn that runs out of time has serverCode agent-turn-aborted instead,
with reason timeout.
In a flow
Section titled “In a flow”An agent step whose turn runs out fails, and the flow run fails with it. The run carries the reason:
kindgi runs start --flow=acme.notify-customer --input='{"orderId":"A-1001"}'{ … "flowId": "acme.notify-customer", … "status": "failed", … "failureMessage": "budget-exceeded: Agent turn cost budget exceeded (limit 0.00001, observed 0.00031)", "output": {}, …}Here the step's agent, acme.order-update from
Give an agent its input, had
budget: { maxCostUsd: 0.00001 }.