Skip to main content

Agent cost controls

LLM-driven agents can consume budget unboundedly if a single user message triggers an infinite tool-call loop, or if a long-running conversation crosses a cost ceiling you only want to hit once. Orbit gates every agent run on three independent ceilings, all configurable per agent.

The three ceilings

Both cost caps accept 010000 cents ($0$100); 10000 cents ($100) is the maximum — setting either field higher returns a 400 validation error. See Semantics for the full value table. When any ceiling is exceeded the agent emits a final error event and stops:
The corresponding codes are COST_LIMIT (per-run cost), CONVERSATION_COST_CAP_REACHED (per-conversation cost), API_CALL_LIMIT (per-run LLM-call cap), TOKEN_LIMIT (per-conversation token aggregate), and TOOL_ITERATION_LIMIT (tool-loop guard).

Configure on agent create

tool_loop_limit is the per-agent tool-iteration knob (bounds 1..50, default 10). It is persisted under config.tool_loop_limit; when unset it falls back to the platform default of 10. The run-wide hard envelope of 50 LLM API calls (AGENT_MAX_API_CALLS_PER_RUN) is always enforced on top of it and cannot be raised by agent config.

Configure on agent update

Both fields are persisted under config.max_cost_per_run_cents / config.max_cost_per_conversation_cents on the agent row.

Semantics

Both max_cost_per_run_cents and max_cost_per_conversation_cents accept a whole number of USD cents in the range 010000 ($0$100). 10000 cents ($100) is the maximum accepted value — a request that sets either field above it is rejected with a 400 validation error before the agent is created or updated. This input ceiling is independent of the platform hard cap that silently clamps the resolved per-conversation value (see below).

How accumulated cost is computed

  • Per-run: real-time accumulation across the streaming loop. Estimated from prompt + completion tokens at the model’s per-1K rate, plus a flat per-API-call overhead.
  • Per-conversation: tracked in Redis under a key keyed off agent_conversations.id. Each run debits the counter on completion; the next run’s iteration-0 probe reads the counter and refuses if it’s already over the cap.
  • The counter is reset only by deleting the conversation. Re-using a conversation_id after the cap will keep failing until you provision a fresh one.

Which cap participates in the org/env precedence chain

Only the per-conversation cap resolves through a fallback chain. The runtime calls resolveCostCapCents and takes the first non-null value (an explicit 0 kill-switch wins over a null further down):
  1. Per-agentagents.config.max_cost_per_conversation_cents
  2. Per-orgorganizations.settings.agent_runtime_cost_cap_cents
  3. Platform default — the DEVOTEL_AGENT_COST_CAP_CENTS_DEFAULT env var
The per-run cap (max_cost_per_run_cents) is a per-agent-only knob with no org or env fallback. The runtime enforces it directly off the agent definition (accumulated run cost >= the cap → COST_LIMIT); if you leave it unset on the agent it falls back to the platform default of $1.00 per run (not unbounded), regardless of any org-level or env-level setting. To allow more than $1.00 of spend in a single run, set max_cost_per_run_cents explicitly. There is no agent_runtime_cost_cap_cents equivalent for per-run spend.
A platform hard cap clamps the resolved per-conversation value — regardless of source. After the chain above resolves, the runtime applies DEVOTEL_LLM_PER_CONVERSATION_MAX_USD (see Platform budget governors, default **5/500cents)asafinalceiling.Anyresolvedvalueabovethehardcapincludinganexplicitperagentmaxcostperconversationcentsissilentlyloweredtoit;aresolvednull(unbounded)inheritsit.ThismeansaperagentcapyousetthroughtheAPIcanbeenforcedatalowernumberthanyouconfigured.Toletaperconversationcapabove5 / 500 cents**) as a final ceiling. Any resolved value **above** the hard cap — including an explicit per-agent `max_cost_per_conversation_cents` — is silently lowered to it; a resolved `null` (unbounded) inherits it. This means a per-agent cap you set through the API can be enforced at a *lower* number than you configured. To let a per-conversation cap above 5 take effect, an operator must raise DEVOTEL_LLM_PER_CONVERSATION_MAX_USD (or set it to 0 to disable the ceiling); no agent- or org-level setting can lift it.

Per-conversation token ceiling

In addition to the cost caps above, every conversation is bounded by an aggregate token ceiling. When the running token total for a conversation crosses this value the agent terminates gracefully and the run ends with a TOKEN_LIMIT error code. This guards against runaway loops where token usage grows non-linearly with context length even when the per-token cost is cheap. The 10000 default is a deliberately conservative back-compat value, not a hard platform cap. Set max_tokens_per_conversation on the agent (create or update) to raise (or lower) it — for example 50000 for long support resolutions or multi-step workflows. Send null to clear an override back to the default. When raising it, also raise max_cost_per_run_cents / max_cost_per_conversation_cents accordingly, since the tenant-configurable spend cap remains the primary ceiling.
It is persisted under config.max_tokens_per_conversation on the agent row; values must be a whole number of tokens between 1 and 1000000.

Hard platform ceilings (always enforced)

These are floor / ceiling values that no agent config can override: They exist to prevent runaway behaviour even when an agent’s per-run cap is set to a high value. MAX_TOOL_ITERATIONS_HARD_CEILING (50) is the absolute ceiling on tool_loop_limit — a per-agent override is clamped to this and cannot exceed it. The platform default of 10 (when tool_loop_limit is unset) is not a hard ceiling: it is the overridable starting value described in the tool_loop_limit knob above.

Platform budget governors (operator-facing)

The per-agent / per-conversation knobs above are tenant-configurable via the agents API. Underneath them sit platform-level spend and rate governors set by environment variable (defaults in packages/shared/src/env.ts, overridden per cluster via Secret Manager). These are the values an SRE greps when paged for a platform-wide 503 LlmPlatformCeilingExceeded or a tenant 429 RATE_LIMIT_EXCEEDED (scope: tenant_tpm). They are listed in .env.example under the LLM budget / cost governors block.
DEVOTEL_LLM_BUDGET_PLATFORM_MONTHLY_CEILING_USD is a hard 503 gate across ALL tenants — when it trips, every tenant’s agent traffic stops, not just the offending one. Raise it (or investigate the runaway tenant) before clearing the page; do not set it to 0 to silence an incident.

Observability

Cost-cap enforcement is observable through logs and metrics, not webhooks — there is no subscribable cost-cap webhook event. Every per-conversation cap fire emits a structured warn log line from the agent runtime carrying a metric field you can alert on:
Alert on the agent.conversation_cost_cap_hit metric to catch runs that hit the cap. Clients also receive the final error event with the matching code (COST_LIMIT, CONVERSATION_COST_CAP_REACHED, API_CALL_LIMIT, TOKEN_LIMIT, or TOOL_ITERATION_LIMIT) on the aborted run. There is no agent.run.aborted webhook — do not subscribe for one.
  • Tier-1 customer support agentmax_cost_per_run_cents=25, max_cost_per_conversation_cents=500.
  • Voice agent (longer turns, STT/TTS overhead)max_cost_per_run_cents=50, max_cost_per_conversation_cents=1000.
  • Internal QA / sandboxmax_cost_per_run_cents=10, max_cost_per_conversation_cents=50 to catch loops fast.
The voice-agent max_cost_per_conversation_cents=1000 (10)aboveexceedsthedefault10) above **exceeds the default 5 platform hard cap** (DEVOTEL_LLM_PER_CONVERSATION_MAX_USD). Unless an operator raises that env var, the effective per-conversation ceiling is silently halved to $5 — see the precedence-chain warning. Confirm the platform value is set to at least your intended cap before relying on it.

See also

  • Creating Agents — full agent-create reference.
  • Agents API — schema for max_cost_per_run_cents / max_cost_per_conversation_cents.
  • Webhooks → Events — full catalog of subscribable agent.* events (cost-cap aborts are not among them; use logs/metrics).