ExAthena.Budget (ExAthena v0.3.1)

Copy Markdown View Source

Usage + cost accounting and budget checks for agent runs.

Aggregates Usage (input/output/total tokens) across loop iterations and computes cost in USD from provider metadata. A run can be capped by :max_budget_usd; the loop tests Budget.exceeded?/2 before each iteration and trips :error_max_budget_usd when the cap is hit.

Shape

%Budget{
  usage: %{input_tokens: _, output_tokens: _, total_tokens: _},
  cost_usd: float | nil,
  started_at: integer,       # monotonic ms
}

Summary

Functions

Merge a single turn's usage + optional cost into the accumulator.

Wall-clock milliseconds since budget was opened.

Test whether the budget has exceeded an optional cap.

New budget accumulator.

Types

t()

@type t() :: %ExAthena.Budget{
  cost_usd: float() | nil,
  started_at: integer() | nil,
  usage: usage_map()
}

usage_map()

@type usage_map() :: %{
  optional(:input_tokens) => non_neg_integer(),
  optional(:output_tokens) => non_neg_integer(),
  optional(:total_tokens) => non_neg_integer()
}

Functions

add(budget, incoming_usage, cost_usd)

@spec add(t(), usage_map() | nil, float() | nil) :: t()

Merge a single turn's usage + optional cost into the accumulator.

Missing keys on the incoming usage are treated as 0. Cost additions that start from nil become a float.

duration_ms(budget)

@spec duration_ms(t()) :: non_neg_integer()

Wall-clock milliseconds since budget was opened.

exceeded?(budget, cap)

@spec exceeded?(t(), float() | nil) :: boolean()

Test whether the budget has exceeded an optional cap.

When max_budget_usd is nil, budget is never exceeded. When non-nil, returns true as soon as cost_usd meets or exceeds it.

new()

@spec new() :: t()

New budget accumulator.