Run-level safety net: caps on requests, token usage, tool calls and cost, enforced at well-defined points in the agent loop.
Any nil field is unchecked. When a limit is exceeded the run terminates with
{:error, {:usage_limit_exceeded, which, value}} instead of looping or burning
cost.
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). Requires an:estimate_costrun option.
Example
alias ExAgent.{CostGuard, UsageLimits}
agent =
ExAgent.new(
model: "openai:gpt-4o",
usage_limits: %UsageLimits{
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}}.
Types
@type t() :: %ExAgent.UsageLimits{ input_tokens_limit: pos_integer() | nil, max_budget_cents: number() | nil, output_tokens_limit: pos_integer() | nil, request_limit: pos_integer() | nil, tool_calls_limit: pos_integer() | nil, total_tokens_limit: pos_integer() | nil }
Functions
@spec check_before_request( t(), ExAgent.Message.Usage.t(), non_neg_integer(), number() ) :: :ok | {:error, {:usage_limit_exceeded, atom(), number()}}
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 requests already issued (0 before the
first). cost_cents is the estimated cost so far (0 when no estimator is in
use).
@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 number of tool calls already run this run. Following
pydanticAI, if executed + incoming would exceed the limit, none of the
incoming calls are executed.