import { MiddlewareExecuteContext } from "../../contracts/middleware/middleware-context.type.mjs"; import { AgentMiddleware } from "../../contracts/middleware/middleware.contract.mjs"; import { BudgetContract, BudgetContractDimension, BudgetContractFallback, BudgetContractViolation, BudgetContractViolationMode } from "./budget-contract.type.mjs"; //#region ../ai/src/middleware/builtins/budget.d.ts /** * Per-model pricing used to compute USD cost from token counts. * Caller-supplied — no bundled table. Keys are model names (the * `ModelContract.name` value); values are input / output token * prices expressed as **USD per 1K tokens** to match every major * provider's published pricing sheet. */ type BudgetPricing = Record; /** * Configuration for `budget()`. At least one of `maxTokens` or * `maxCostUSD` must be supplied — a budget with no cap is a no-op. */ type BudgetOptions = { /** * Hard cap on cumulative total tokens (input + output, summed * across every trip of the run). Inclusive — exceeding triggers * the configured `onExceeded`. */ maxTokens?: number; /** * Hard cap on cumulative USD cost. Requires `pricing` for the * agent's configured model — without a pricing entry the USD check * silently skips (tokens-only enforcement still applies). */ maxCostUSD?: number; /** * Per-model pricing table used to compute USD cost. Only consulted * when `maxCostUSD` is set. Model names must match the running * agent's `ModelContract.name` exactly. */ pricing?: BudgetPricing; /** * Behavior when a cap is breached. `"abort"` throws * `BudgetExceededError` — surfaces on `result.error`, stops the * run at the next trip boundary. `"warn"` logs a warning and * lets the run continue (useful for observability-first rollouts * before flipping the switch to abort). Default `"abort"`. */ onExceeded?: "abort" | "warn"; /** * Override the middleware name. Useful when two budgets coexist * (e.g. a per-request cap plus a session-wide cap via different * instances). Default `"budget"`. */ name?: string; /** * Declarative SLO / cost contract enforced on top of (and * independently of) the legacy `maxTokens` / `maxCostUSD` caps. * Adds a wall-clock `maxLatencyMs` dimension and a per-contract * `onViolation` reaction (`"abort"` hard-stops, `"fallback"` records * a signal + fires `fallback` and lets the run continue). Omit to * keep the classic budget behavior unchanged. * * Read a recorded fallback signal back with * {@link readBudgetFallbackSignal}. */ contract?: BudgetContract; }; /** * Recorded contract fallback signal, stashed under the `.fallback` * state key when a `"fallback"` clause trips. A fallback orchestrator * reads it via {@link readBudgetFallbackSignal} to decide how to degrade. */ type BudgetFallbackSignal = BudgetContractViolation; /** * Read the contract fallback signal recorded by a `budget()` middleware * running under `contract.onViolation: "fallback"`. Returns `undefined` * when no clause was breached. * * **Role.** The middleware cannot itself switch models on a soft breach, * so it records a typed {@link BudgetFallbackSignal} in the shared state * bag and lets the run continue. A fallback orchestrator (or the * `execute.after` hook of an outer middleware) reads it back here and * decides how to degrade the next run — cheaper model, cached answer, * truncated context. * * @param state - The middleware state bag (`ctx.state`). * @param name - The budget middleware's name. Default `"budget"`, * matching `BudgetOptions.name`'s default. * * @example * const guard = budget({ contract: { maxCostUSD: 0.05, onViolation: "fallback" } }); * * // In an outer middleware's execute.after, after the run: * const signal = readBudgetFallbackSignal(ctx.state); * if (signal?.dimension === "cost") { * await rerunOnCheaperModel(); * } */ declare function readBudgetFallbackSignal(state: MiddlewareExecuteContext["state"], name?: string): BudgetFallbackSignal | undefined; /** * Enforced token and / or USD budget for an agent run. * * **Role.** Guards against runaway tool loops, misconfigured * prompts, and unexpected provider price swings by capping * cumulative usage across every LLM trip of a single execution. * Aborts the run with a typed `BudgetExceededError` the moment a cap * is breached, rather than letting the damage grow trip by trip. * * **Scope.** Per-execution. A fresh counter is created at * `execute.before` and lives in the middleware state bag until the * run ends. Two concurrent `agent.execute()` calls on the same * agent therefore enforce the cap independently. * * **Token accounting.** After each successful trip, the middleware * adds `response.usage.total` to its running total and checks * against `maxTokens`. Synthetic trips (cache hits) contribute * `usage.total` as returned by the cache — cache middleware is * expected to surface zero usage on a hit, which naturally excludes * those trips from the budget. * * **USD accounting.** When `maxCostUSD` + `pricing[modelName]` are * both present, the middleware converts per-trip input / output * tokens to USD and accumulates. Missing pricing silently degrades * to tokens-only — explicit rather than guessing. * * **Warn mode.** `onExceeded: "warn"` logs a single warning the first * time a cap is breached and lets the run continue. Useful for * measuring real-world traffic against a proposed cap before flipping * to `"abort"` in production. * * **Contract / SLO mode.** Pass `contract` to enforce a declarative * service-level objective — `maxCostUSD`, `maxLatencyMs`, `maxTokens` — * on top of the legacy caps, with a single `onViolation` reaction: * `"abort"` hard-stops with `BudgetExceededError`; `"fallback"` records * a typed signal (read it via {@link readBudgetFallbackSignal}), fires * the optional `fallback` callback, and lets the run continue so an * outer layer can degrade gracefully. The contract's clauses are * evaluated independently of — and after — the top-level caps; the * top-level caps stay fully functional with or without a contract. * * @example * const budgetMiddleware = budget({ maxTokens: 50_000 }); * * const myAgent = agent({ * model, * middleware: [budgetMiddleware], * }); * * @example * // With USD cap and custom pricing * const guard = budget({ * maxCostUSD: 0.5, * pricing: { * "gpt-4o": { inputPer1K: 0.005, outputPer1K: 0.015 }, * }, * }); * * @example * // SLO contract — soft-fallback on any breach * const sloGuard = budget({ * pricing: { "gpt-4o": { inputPer1K: 0.005, outputPer1K: 0.015 } }, * contract: { * maxCostUSD: 0.05, * maxLatencyMs: 8_000, * maxTokens: 40_000, * onViolation: "fallback", * fallback: (violation) => routeToCheaperModel(violation.dimension), * }, * }); */ declare function budget(options: BudgetOptions): AgentMiddleware; //#endregion export { BudgetFallbackSignal, BudgetOptions, BudgetPricing, budget, readBudgetFallbackSignal }; //# sourceMappingURL=budget.d.mts.map