Documentation
¶
Overview ¶
Package budget implements hard execution budgets for an agent run (odek-extension/v1 — see docs/EXTENSIONS.md): a Limits struct describing the configured caps, a typed Error returned when a cap is exhausted, and a Checker the loop engine consults at each enforcement point.
Budgets are hard stops, not hints: once a limit is exhausted the loop emits a budget_exceeded event, persists the latest safe session state, and returns a typed *Error so callers (CLI dispatch, orchestrators) can tell a budget stop apart from a model or tool failure.
Index ¶
Constants ¶
const ( LimitRuntime = "runtime" LimitToolCalls = "tool_calls" LimitInputTokens = "input_tokens" LimitOutputTokens = "output_tokens" LimitCostUSD = "cost_usd" )
Limit names carried in Error.Limit and in budget_exceeded events (data.limit_name). These strings are part of the odek-extension/v1 contract and must match the events.Limit* constants.
Variables ¶
This section is empty.
Functions ¶
func MicroToUSD ¶
MicroToUSD converts a micro-USD value from an Error back to USD.
Types ¶
type Checker ¶
type Checker struct {
// contains filtered or unexported fields
}
Checker tracks consumption against a Limits set for a single run. The zero/nil Checker is safe to call and never reports exhaustion, so call sites need no nil guards beyond NewChecker returning nil for empty limits.
Checker is not safe for concurrent use; the loop engine consults it from the single loop goroutine only.
func NewChecker ¶
NewChecker returns a Checker enforcing l, measuring runtime from start. It returns nil when l configures no limits at all, letting callers skip every check cheaply.
func (*Checker) CheckRuntime ¶
CheckRuntime reports exhaustion of the wall-clock budget. Nil-safe.
func (*Checker) CheckToolBatch ¶
CheckToolBatch reports whether executing a batch of n further tool calls would exceed the tool-call budget. It is consulted BEFORE the batch is scheduled; on exhaustion no new tool work starts. Observed is the would-be total (already executed + this batch). Nil-safe.
func (*Checker) CheckUsage ¶
CheckUsage reports exhaustion of the token budgets and (when prices are configured) the estimated-cost budget, given the cumulative token totals. Nil-safe.
func (*Checker) RecordToolCalls ¶
RecordToolCalls accounts n executed tool calls against the budget.
func (*Checker) SetNowFunc ¶
SetNowFunc overrides the wall clock used for the runtime limit. Intended for tests.
type Error ¶
Error is the typed error returned when an execution budget is exhausted. Limit is one of the Limit* constants. Observed and Maximum are counts in the limit's natural unit (seconds, tool calls, tokens) — except for LimitCostUSD, where both are micro-USD (1e-6 USD) so the fields stay int64; use MicroToUSD to convert for display.
type Limits ¶
type Limits struct {
// MaxRuntimeSeconds caps the wall-clock duration of a run.
MaxRuntimeSeconds int64 `json:"max_runtime_seconds,omitempty"`
// MaxToolCalls caps the total number of tool calls executed.
MaxToolCalls int64 `json:"max_tool_calls,omitempty"`
// MaxInputTokens caps cumulative prompt tokens across LLM calls.
MaxInputTokens int64 `json:"max_input_tokens,omitempty"`
// MaxOutputTokens caps cumulative completion tokens across LLM calls.
MaxOutputTokens int64 `json:"max_output_tokens,omitempty"`
// MaxCostUSD caps the estimated spend of a run. Enforcement is active
// only when both resolved per-million prices (see ResolvePrices) are
// configured too.
MaxCostUSD float64 `json:"max_cost_usd,omitempty"`
// InputCostPerMillionUSD is the operator-configured price of one million
// input tokens. odek never hard-codes provider prices.
InputCostPerMillionUSD float64 `json:"input_cost_per_million_usd,omitempty"`
// OutputCostPerMillionUSD is the operator-configured price of one million
// output tokens. odek never hard-codes provider prices.
OutputCostPerMillionUSD float64 `json:"output_cost_per_million_usd,omitempty"`
// ModelPrices maps exact model IDs to per-model token prices. When the
// run's model ID matches a key exactly, that entry's prices override the
// flat pair above (per field — a missing price in the entry falls back
// to the flat value individually). See ResolvePrices.
ModelPrices map[string]ModelPrice `json:"model_prices,omitempty"`
}
Limits describes the hard execution budgets for a single agent run. All fields are optional: zero means "no limit" (or, for prices, "not configured"). Values come from the operator config layers — never from the LLM and never hard-coded per provider.
func (Limits) CostEnforcementActive ¶
CostEnforcementActive reports whether cost enforcement is in effect: the cost cap is set AND both per-million prices are configured. Without prices there is no way to estimate spend — odek never guesses provider prices — so the token budgets stay active while cost checks are disabled.
func (Limits) EstimatedCostUSD ¶
EstimatedCostUSD returns the estimated spend for the given cumulative token totals, using the configured per-million prices.
func (Limits) ResolveForModel ¶
ResolveForModel returns a copy of l with the flat prices replaced by the prices resolved for the given model ID (see ResolvePrices). The model is fixed per run, so callers resolve once at engine/checker setup; every downstream cost check (CostEnforcementActive, EstimatedCostUSD) then uses the effective prices unchanged.
func (Limits) ResolvePrices ¶
ResolvePrices returns the effective per-million input/output prices for the given model ID: an exact ModelPrices key match overrides the flat pair, with each missing (non-positive) price in the entry falling back to the flat value individually. No normalization or prefix matching.
type ModelPrice ¶
type ModelPrice struct {
InputCostPerMillionUSD float64 `json:"input_cost_per_million_usd,omitempty"`
OutputCostPerMillionUSD float64 `json:"output_cost_per_million_usd,omitempty"`
}
ModelPrice is the per-model token price entry in Limits.ModelPrices. A zero field means "fall back to the flat Limits price for that field".