ExAgent.UsageLimits (ExAgent v0.3.0)

Copy Markdown View Source

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 (see ExAgent.CostGuard). Requires an :estimate_cost run 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

t()

@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

check_before_request(limits, usage, request_count, cost_cents \\ 0)

@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).

check_tool_calls(usage_limits, executed, incoming)

@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.