ExAgent. UsageLimits
(ExAgent v2.2.0)
View Source
Execution-tree safety net: each run's limits also constrain its framework
descendants. Admission is serialized by ExAgent.ExecutionScope; these
functions provide the pure checks. Token/cost thresholds are retrospective,
so already in-flight requests can exceed them.
Any nil threshold is unchecked. When a limit is exceeded the run terminates with
a RunError with reason {:usage_limit_exceeded, which, value}.
request_limit/total_tokens_limit/input_tokens_limit/output_tokens_limit— checked before each model request.tool_calls_limit— checked before a batch of tool calls is executed (pydanticAI semantics: if the model returned parallel calls that would exceed the limit, none run).max_budget_cents— checked before each model request against an estimated cost (seeExAgent.CostGuard). An explicit:estimate_costcallback takes precedence over a qualified public upstream estimate; unknown/error never silently falls back. Neither is provider billing.
accounting: :strict (default) requires sufficient Model-reported metrics for
enabled thresholds. A declared normalized-only contract rejects before IO;
unknown contracts are checked against actual reports before later effects.
accounting: :estimated opts into available subtotals and may continue without
metrics/pricing, but metric limits require a finite request_limit in this scope
or an ancestor. Host-only limits require no accounting. A child's policy cannot
weaken its ancestors. In-flight operations can exceed retrospective thresholds.
Example
Here model is an explicitly configured ExAgent.Models.ReqLLM instance;
normalized metrics require opt-in estimated thresholds and a finite request bound.
alias ExAgent.{CostGuard, UsageLimits}
agent =
ExAgent.new(
model: model,
usage_limits: %UsageLimits{
accounting: :estimated,
request_limit: 5,
total_tokens_limit: 2000,
tool_calls_limit: 10,
max_budget_cents: 25
}
)
pricing = CostGuard.estimator(%{input_per_1k_cents: 250, output_per_1k_cents: 1000})
ExAgent.run(agent, "research this", estimate_cost: pricing)
Summary
Functions
Check the request/token/budget limits against accumulated usage, the
upcoming request count, and the estimated cost_cents. Returns :ok or
{:error, {:usage_limit_exceeded, which, value}}.
Check the tool_calls_limit before executing a batch of incoming tool
calls. Returns :ok or {:error, {:usage_limit_exceeded, :tool_calls, n}}.
Validate nonnegative integral counters and a nonnegative monetary threshold.
Types
@type t() :: %ExAgent.UsageLimits{ accounting: :strict | :estimated, input_tokens_limit: non_neg_integer() | nil, max_budget_cents: number() | nil, output_tokens_limit: non_neg_integer() | nil, request_limit: non_neg_integer() | nil, tool_calls_limit: non_neg_integer() | nil, total_tokens_limit: non_neg_integer() | nil }
Functions
@spec check_before_request( t(), ExAgent.Message.Usage.t(), non_neg_integer(), number() | nil ) :: :ok | {:error, term()}
Check the request/token/budget limits against accumulated usage, the
upcoming request count, and the estimated cost_cents. Returns :ok or
{:error, {:usage_limit_exceeded, which, value}}.
request_count is the number of Model attempts already admitted (0 before the
first). cost_cents is the known estimate so far, or nil when unknown; an
strict monetary budget rejects unknown cost; estimated thresholds use available
subtotals, with host-bound enforcement in ExecutionScope.
@spec check_tool_calls(t(), non_neg_integer(), non_neg_integer()) :: :ok | {:error, {:usage_limit_exceeded, :tool_calls, non_neg_integer()}}
Check the tool_calls_limit before executing a batch of incoming tool
calls. Returns :ok or {:error, {:usage_limit_exceeded, :tool_calls, n}}.
executed is the historical parameter name for admitted/reserved tool calls,
not dispatched calls, successes or external effects. Following
pydanticAI, if executed + incoming would exceed the limit, none of the
incoming calls are executed.
Validate nonnegative integral counters and a nonnegative monetary threshold.