llm-budget
Hard spend limits for LLM agents in Rust: every call is charged against a per-agent budget and refused once the cap is hit, instead of alerting after the bill arrives.
When you run many agents at once, one runaway loop can burn a day's budget in minutes. llm-budget gives each agent a hard USD cap, a fleet-wide cap on top, a kill switch, and an automatic model downgrade (Premium to Standard to Economy to Local) as an agent's remaining budget gets low.
Features
AgentBudget: per-agent USD limit.charge(input_tokens, output_tokens, ..)estimates the cost from the agent's current model tier and rejects the charge withBudgetError::AgentExhaustedif it would cross the limit.- Automatic downgrade cascade (
ModelCascade,ModelTier): when the remaining fraction of the budget drops below a threshold, the agent steps down one tier andchargetells you which tier to use next. - Kill switch:
kill(reason)on one agent, orFleetAllocator::kill_allfor the whole fleet; later charges fail withKillSwitchActivated. FleetAllocator: registers agents against a fleet-wide cap and refuses allocations that would oversubscribe it (AllocationFailed).- Lock-free accounting: spend is stored as atomic micro-dollars (
AtomicBudget), so concurrent charges from many tasks are safe without a mutex on the hot path. - Audit trail: every accepted charge is kept as a
SpendRecord(agent, task, session, tier, tokens, cost, timestamp). - Persistence:
BudgetStoresaves and loads fleet snapshots as JSON files per session. - Typed errors only: the crate denies
unwrap,expectandpanicvia Clippy lints.
Quick start
use ;
async
Saving state between runs:
use ;
async
How it works
| File | What it holds |
|---|---|
src/budget/mod.rs |
AtomicBudget (micro-dollar atomics), BudgetEnvelope (agent/task/session scope, kill switch, audit log), AgentBudget, BudgetSnapshot |
src/model.rs |
ModelTier with built-in per-1K-token prices, ModelCascade downgrade logic |
src/fleet/mod.rs |
FleetBudget (fleet-wide cap), FleetAllocator (agent registry on a DashMap) |
src/persistence/mod.rs |
BudgetStore, JSON snapshots on disk with an in-memory cache |
src/error.rs |
BudgetError |
A charge is a single fetch_add on an AtomicU64; if the new total crosses the limit it is rolled back with fetch_sub and the call returns an error, so the limit is never exceeded.
Status and limitations
Version 0.1, early. Things to know before relying on it:
- Costs come from four fixed tiers with approximate prices (
ModelTier::cost_per_1k_input/output), not from per-model price tables. FleetAllocator::reallocatevalidates the request but does not move budget between agents yet.- Fleet-level spend recorded by
charge_agentis approximate; per-agent limits are the exact ones.
Run the tests and benchmarks with:
License
MIT, see LICENSE.
Part of a set of Rust crates for LLM agents, see rust-crates.