# Escalation

> When a cheap model's answer fails the bar: how escalation works and what it costs.

Choosing a cheaper model is only a saving if its answers hold up. When one does not, the call is escalated to a more capable model, and the cost of that second call is charged against the cheap model whose failure bought it.

## When escalation happens

When an answer **fails its check**: the agent’s own check on its output (a schema, a citation, a grounding check, a rule), decided by the agent’s code. The router does not judge answers itself. The agent asks the gateway for the next step:

```python
step = gateway.escalated(decision, env, failed_model=model, spent_usd=result.cost_usd)
if step is not None and step.available:
    result = await gateway.acall(prompt, env=env, model=step.model, system=system)
```

Escalating automatically on a failed check, for agents in the library: \[Coming]

## How it works

- **Up the capability ladder.** The next model is the most capable one this call was allowed to use: not excluded, within your allow list and residency rule, available, and not dropped for a hard reason. Where your policy names an escalation target for the task class (`escalate_to`), that model is used instead.
- **At most a set number of steps**: one by default (`escalate` in your policy). Set it to zero to turn escalation off. When the steps are used up, or nothing is above, the escalation says so (`escalation_exhausted`, `nothing_above`) and nothing more is called.
- **Through the gateway**, like any call: the second call is checked against your caps and kill switch, priced, recorded and screened in the same way.

## What it costs, and who is charged

The escalation’s cost is **charged to the cheap model** (`charge_to`). The decision is recorded again with `escalation_usd`, so:

- the [routing lever](/cost/savings/#model-routing-against-the-top-model) takes the escalation off the saving that choice bought: a cheap model that needed a dear retry did not save what the first decision estimated;
- the next time the benchmark and the routing figures look at that model, its cost per successful task includes the clean-up its failures caused.

`GET /api/v1/routing` reports `escalated` (how many decisions were escalated) and `escalation_usd` (what the escalations cost) in its totals and in every breakdown. `saving_usd` is already net of it.

## Escalation is priced in before the choice

The router anticipates escalation when it chooses. Each candidate is ranked on its **expected** cost:

```text
expected = direct + (1 − quality) × the direct cost of the next model up
```

A worked example of the arithmetic, on the card of [A decision, worked](/router/decision/): Haiku 4.5’s direct cost for the lookup question is $0.011451, and the next model up, Sonnet 4.5, would cost $0.034601. At quality 1.00, Haiku’s expected cost is its direct cost. **If** Haiku’s measured quality on the class were 0.90, its expected cost would be $0.011451 + 0.10 × $0.034601 = $0.014911: still well below Sonnet’s, so still chosen. A model has to fail often, or be close in price, for the escalation term to change the order.

Note the two “next models” differ. The expected-cost term uses the direct cost of the next model up by capability; an actual escalation goes to the most capable model the call may use, unless `escalate_to` names one. With one step allowed, the actual escalation can therefore cost more than the term assumed: on the card above, Haiku would escalate to Opus 4.6 ($0.057613), not Sonnet. Set `escalate_to` for a class to the next model up to make the two the same.

Source: https://docs.atlanticagenticlabs.com/router/escalation/
