---
description: "Token and cost budgets with automatic agent stopping"
tags:
  - runtime
  - budget
---

# Token Budget & Cost Limits

**Import:** `from selectools import AgentConfig`
**Stability:** beta

```python title="budget_demo.py"
from selectools import Agent, AgentConfig, LocalProvider, tool

@tool(description="Count words in text")
def word_count(text: str) -> str:
    return f"Word count: {len(text.split())}"

agent = Agent(
    tools=[word_count],
    provider=LocalProvider(),
    config=AgentConfig(
        max_total_tokens=50000,
        max_cost_usd=0.25,
    ),
)
result = agent.run("Count words in 'hello world'")
print(result.content)
```

!!! tip "See Also"
    - [Cancellation](CANCELLATION.md) -- cooperative agent stopping
    - [Token Estimation](TOKEN_ESTIMATION.md) -- pre-run token and cost estimates
    - [Usage & Cost Tracking](USAGE.md) -- actual token counts after execution

**Added in:** v0.17.3
**File:** `src/selectools/agent/config.py`, `src/selectools/agent/core.py`

## Overview

The budget system prevents runaway costs by enforcing hard limits on token usage and dollar spend per agent run. When a limit is hit, the agent stops gracefully and returns a partial result.

## Quick Start

```python
from selectools import Agent, AgentConfig

config = AgentConfig(
    max_total_tokens=50000,  # stop after 50k cumulative tokens
    max_cost_usd=0.20,       # stop after $0.20 cumulative cost
    max_iterations=12,       # existing iteration limit still applies
)

agent = Agent(tools=[...], provider=provider, config=config)
result = agent.run("Analyze this dataset")

# Check if budget was the reason for stopping
if "budget exceeded" in result.content.lower():
    print(f"Stopped early — used {result.usage.total_tokens} tokens, ${result.usage.total_cost_usd:.4f}")
```

## How It Works

The budget check runs at the **start of each iteration**, after the previous iteration's tokens have been counted. If cumulative usage exceeds either limit:

1. A `BUDGET_EXCEEDED` trace step is recorded
2. The `on_budget_exceeded` observer event fires
3. The agent returns an `AgentResult` with partial content from completed iterations

```
Iteration 1: 15,000 tokens → total: 15,000 (under 50,000) ✓
Iteration 2: 20,000 tokens → total: 35,000 (under 50,000) ✓
Iteration 3: budget check → 35,000 < 50,000 → continue
             18,000 tokens → total: 53,000
Iteration 4: budget check → 53,000 ≥ 50,000 → STOP
```

## Configuration

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `max_total_tokens` | `Optional[int]` | `None` | Cumulative token limit. `None` = no limit. |
| `max_cost_usd` | `Optional[float]` | `None` | Cumulative cost limit in USD. `None` = no limit. |

Both fields are `None` by default, preserving backward compatibility.

## Observer Event

```python
from selectools import AgentObserver

class MyObserver(AgentObserver):
    def on_budget_exceeded(self, run_id: str, reason: str, tokens_used: int, cost_used: float):
        log.warning(f"Budget exceeded: {reason} (tokens={tokens_used}, cost=${cost_used:.4f})")
```

## Trace Step

Budget stops are recorded as `StepType.BUDGET_EXCEEDED` in the execution trace:

```python
for step in result.trace.steps:
    if step.type == "budget_exceeded":
        print(step.summary)  # "Token budget exceeded: 53000/50000 tokens"
```

## Interaction with Other Limits

If both `max_iterations` and `max_total_tokens` are set, whichever limit is hit first wins. Budget is checked before the LLM call, so no tokens are wasted on a call that would exceed the budget.

## See Also

- [Usage & Cost Tracking](USAGE.md) — per-call and per-run token/cost tracking
- [Agent](AGENT.md) — `AgentConfig` reference

## Related Examples

| # | Script | Description |
|---|--------|-------------|
| 05 | [`05_cost_tracking.py`](https://github.com/johnnichev/selectools/blob/main/examples/05_cost_tracking.py) | Token and cost tracking per run |
| 43 | [`43_token_budget.py`](https://github.com/johnnichev/selectools/blob/main/examples/43_token_budget.py) | Token budget enforcement demo |
| 47 | [`47_token_estimation.py`](https://github.com/johnnichev/selectools/blob/main/examples/47_token_estimation.py) | Pre-run token estimation |
