Skip to main content

Tool Budget

Use tool-budget to block a request when max_tokens is more than a configured tool limit. The policy checks declared tools. It does not meter actual use.

It does not observe actual tool calls or token use. It does not calculate request cost.

Outcome

ConditionVerdictCause code
A minimum of one listed tool exceeds its token ceilingblocktool-budget.exceeded
No listed tool exceedsallowtool-budget.ok

The nested policy-result details contain:

{
"exceeded_tools": [
"web_search"
]
}

An allowed chain keeps last cause ok. Examine tool-budget.ok for policy evidence. A block occurs before the upstream call. It returns an HTTP 400 policy-violation response.

Prerequisites

  • Add tool-budget to the effective request chain.
  • Use exactly the same tool names as the client sends in request.tools.
  • Make sure that clients send a non-negative integer in max_tokens. This policy does not read other token-limit fields.
  • Use Usage, key-budget, rate-limit, or billing controls for actual or cumulative consumption.

Configuration

pack:
name: tool-budget-example-1
version: "1.0.0"
enabled: true

policies:
chain:
- tool-budget

policy:
tool-budget:
budgets:
web_search:
max_tokens: 5000
database_query:
max_tokens: 2000

Supported fields

FieldTypeDefaultNotes
budgetsobject{}Maps tool names to limit objects.
budgets.<tool>.max_tokensinteger ≥ 1Enforced against the request's top-level max_tokens.

tool-budget does not accept max_cost_usd. Use max_tokens here. Use the supported Usage or billing controls for cost governance.

Specified evaluation

The evaluator does these steps:

  1. Reads top-level request.max_tokens as an unsigned integer.
  2. Reads each item in top-level request.tools.
  3. Gets tools[*].function.name. If this field is missing, it gets tools[*].name.
  4. Looks up each name in policy.tool-budget.budgets.
  5. Adds the name to exceeded_tools when request.max_tokens > budgets.<name>.max_tokens.

The comparison is strict. A request equal to the configured limit is allowed.

Request shapes

The policy recognizes the two tool-name forms:

{
"max_tokens": 250,
"tools": [
{
"type": "function",
"function": {
"name": "web_search"
}
},
{
"name": "database_query"
}
]
}

The list contains tools available to the request. It does not contain tool calls that the model executed.

Missing and other fields

The policy reads these cases as a zero-token request. They do not exceed a positive limit:

  • Missing max_tokens.
  • Negative, fractional, or string max_tokens.
  • request families that send only max_completion_tokens or max_output_tokens.

A missing or non-array tools field gives no examined tools. This policy allows unconfigured tool names.

Do not use these allow paths as safe defaults. Normalize the request to the supported fields. For other fields, use the owning control.

Test the blocking contract

Create tests/blocks-search-over-budget.json:

{
"name": "blocks-search-over-budget",
"input": {
"messages": [
{
"role": "user",
"content": "Search the documentation."
}
],
"request": {
"model": "replace-with-model-id",
"max_tokens": 250,
"tools": [
{
"type": "function",
"function": {
"name": "web_search"
}
}
]
}
},
"expected": {
"verdict": "block",
"reason_code": "tool-budget.exceeded"
}
}

With web_search.max_tokens: 100, run:

verdictan policy lint --file policy-config.yaml
verdictan policy test --json

Examine details.policy_results[]. Make sure that it contains exceeded_tools: ["web_search"].

Add boundary fixtures for:

  • max_tokens: 100 gives allow / ok.
  • max_tokens: 101 gives block / tool-budget.exceeded.
  • An unconfigured tool gives allow / ok.
  • Missing max_tokens gives allow / ok.
  • Multiple tools where only one exceeds the limit.

What this policy does not give

  • Cumulative session, user, team, agent, or organization counters.
  • Actual prompt, completion, or tool-execution token metering.
  • Limits on the number of tool calls.
  • Validation of tool arguments, schemas, safety, or authorization.
  • Enforcement against tool calls returned subsequently in a model response.

Use tool-validation, tool-security, agent-firewall, token rate limits, and the product's Usage/budget surfaces for those different purposes.

Rollout guidance

  1. Capture the specified tools and token-limit shape from each client library.
  2. Normalize tool names and case. Budget lookup uses a specified map-key match.
  3. Set each limit to the maximum permitted completion size for that available tool.
  4. Add equality, one-above-limit, missing-field, and multi-tool fixtures.
  5. Send a live request. Verify the HTTP response and nested exceeded_tools details.
  6. Monitor false blocks when applications include many tools that are not used in each request.

Troubleshooting

SymptomLikely causeResolution
Large request was allowedThe client used max_completion_tokens/max_output_tokens, did not send max_tokens, or sent a non-integer value.Send supported top-level max_tokens or use a control that owns the other request family.
Tool was not examinedIts name was missing, nested differently, or did not exactly match a budget key.Examine request.tools and align function.name or name.
Request blocked although no tool was calledThe policy checks tools declared as available, not model-emitted invocations.Decrease the request tool list or select a different control for actual calls.
Config with max_cost_usd fails validationRemoved cost-budget field is configured in a tool entry.Replace it with max_tokens here, or move the requirement to the product's supported Usage/billing workflow.
Equality did not blockThe evaluator uses > rather than >=.Set the ceiling one unit lower if that is the specified contract and retest.
Allowed event has last cause okAllow-only nested causes do not replace the last decision cause.Examine the nested result for tool-budget.ok.

Next steps