budget

js/ai/budget.ts

fino:ai/budget — enforceable token, cost, and wall-clock limits.

A Budget is an explicit capability. Create one per run, share one across a durable session, or inject the same instance into every agent for a tenant. Reservations are synchronous and atomic within a realm, so concurrent model calls cannot all spend the same remaining capacity.

import { agent } from 'fino:ai/agent';
import { Budget } from 'fino:ai/budget';

const tenantBudget = new Budget({
  tokens: 100000,
  usd: 5,
  wallClockMs: 60000,
  onExhausted: 'suspend',
});
const bot = agent({ model, budget: tenantBudget, defaults: { maxTokens: 1000 } });

Interfaces

interface BudgetLimits {

Limits enforced by a Budget.

Properties

tokens?: number

Maximum combined input and output tokens.

usd?: number

Maximum recorded provider cost in US dollars.

wallClockMs?: number

Maximum elapsed milliseconds from budget creation.

interface BudgetOptions extends BudgetLimits {

Construction options for a budget.

Properties

onExhausted?: 'error' | 'suspend'

Exhaustion behavior. error throws BudgetExceededError; suspend throws SuspendSignal with a serializable budget snapshot.

clock?: () => number

Deterministic clock hook for tests and virtual schedulers.

interface BudgetGrant extends BudgetLimits {

Audited increase to an existing budget.

Properties

grantedAt: number

Timestamp at which the grant was applied.

approvedBy?: string

Operator or system identity that approved the increase.

reason?: string

Human-readable approval rationale.

interface BudgetSnapshot {

Serializable budget state suitable for durable session metadata.

Properties

limits: BudgetLimits

Current ceilings, including approved increases.

onExhausted: 'error' | 'suspend'

Exhaustion behavior retained across restore.

startedAt: number

Budget creation timestamp used for wall-clock enforcement.

usedTokens: number

Committed input plus output tokens.

usedUsd: number

Committed provider cost in US dollars.

reservedTokens: number

Capacity currently reserved by in-flight calls.

reservedUsd: number

Cost currently reserved by in-flight calls.

grants: BudgetGrant[]

Append-only approval history.

Classes

class BudgetExceededError extends Error {

Error thrown when a budget configured with onExhausted: 'error' is spent.

Readonly Properties

readonly limit: 'tokens' | 'usd' | 'wallClockMs'

Limit that rejected the operation.

readonly snapshot: BudgetSnapshot

Durable state at the point of rejection.

Constructors

constructor(limit: 'tokens' | 'usd' | 'wallClockMs', snapshot: BudgetSnapshot)

Create an exhaustion error. Applications normally receive this from a budget check.

class BudgetLease {

Capacity held for one in-flight model call.

Call commit() exactly once on a successful provider response or release() when the provider fails before reporting usage. Both operations are idempotent.

Methods

commit(usage: Usage, usd = 0): void

Replace the reservation with actual provider usage and cost.

release(): void

Return reserved capacity after a provider failure or cancellation.

class Budget {

Stateful enforcement surface for AI spend.

Constructors

constructor(options: BudgetOptions)

Create a new unspent budget.

Static Methods

static fromSnapshot(snapshot: BudgetSnapshot, options: { clock?: () => number } = {}): Budget

Restore a budget after restart.

In-flight reservations are cleared because no provider call survives the process. Committed usage, elapsed-time origin, limits, and grants remain.

Methods

check(): void

Check committed usage and elapsed time without reserving capacity.

reserve(predicted: { tokens?: number; usd?: number } = {}): BudgetLease

Atomically reserve predicted capacity before a model call.

grant( increase: BudgetLimits, audit: { approvedBy?: string; reason?: string } = {}, ): BudgetSnapshot

Increase ceilings after human or policy approval.

The grant is append-only audit data and does not change committed usage.

snapshot(): BudgetSnapshot

Return a detached serializable state snapshot.