Routing
AIR decides which registered provider handles a request in one of three ways, depending on the request and configuration.
1. Explicit provider selection
If ChatRequest.provider is set (or AIRConfig.default_provider is set and the request does not override it), AIR calls that provider directly with get_provider(name) and no routing logic runs. There is no fallback in this path. If the provider raises, the exception propagates to the caller unchanged. If the name is not registered, ProviderNotFoundError is raised.
Session.chat(message, provider="groq") sets this per call while keeping the rest of routing available for other calls in the same session. See core/sessions.md.
2. Priority routing (default, routing="priority")
If no explicit provider is set, AIR builds a list of registered providers ordered by their configured priority (lower number first; providers registered without an explicit priority get the next unused integer in registration order). AIR then tries them in that order, skipping or falling back as described in core/fallback.md, until one succeeds or all have been tried.
3. Intelligent routing (routing="intelligent")
Set with AIR(routing="intelligent") or AIRConfig(routing="intelligent"). Before applying the priority list, AIR:
- Classifies the request with
air.routing.intelligent.classify_request, using simple keyword based rules, not another model call:- If any message contains
```or one ofdef,class,function,stack trace,traceback,compile error, the request requires thecodingcapability. - If any message contains
step by step,explain why,prove that, orwalk through your reasoning,reasoningis a preferred (not required) capability. - If the estimated token count is under 200 and reasoning was not already preferred,
speedbecomes a preferred capability. ChatRequest.requires(aset[str]) is merged directly into the required capability set, so you can force a requirement such as{"vision"}that AIR's own heuristics do not detect.
- If any message contains
- Scores each currently registered provider with
select_provider, skipping any provider that:- has health status
exhausted, - is missing a required capability (
coding,vision, ortool_use) declared viaadd_provider(..., capabilities={...}), - has a configured
context_tokenscapability lower than the request's estimated tokens, - has a known or estimated remaining capacity (see features/capacity-tracking.md) lower than the request's estimated tokens.
- has health status
- Among the remaining candidates, picks the highest scoring one. Score increases for each satisfied required capability, for satisfying preferred
reasoningorspeedcapabilities, for being inavailablehealth status, and for having known or estimated (not just unknown) capacity. Ties keep the earlier one in priority order. - If a provider was picked, AIR puts it first, then falls back through the rest of the priority ordered list exactly as in priority routing if it fails.
- If no provider satisfies the required capabilities, intelligent routing selects nothing and AIR falls back to plain priority order.
ChatResponse.selection_reason is set to a short string (for example "coding capability, healthy, sufficient estimated capacity") when intelligent routing's pick is the provider that actually answered. It is None otherwise, including in plain priority routing.
Provider eligibility summary
A provider is skipped before ever being called (in either routing mode) if either of these is true:
- Its tracked health status is
exhausted(see core/fallback.md for what sets this). - A token limit is configured for it (
limits={"tokens": ...}) and AIR estimates the request needs more tokens than the provider's known or estimated remaining capacity.
Both of these skips still count as an attempt for the purposes of ProvidersExhaustedError.attempts, and both emit a structured capacity_skipped event. See features/structured-events.md.
All providers unavailable
If every provider is skipped or fails, AIR raises ProvidersExhaustedError (see reference/exceptions.md) and emits an all_exhausted event. No response is returned in this case.
What routing does not do
AIR does not call another AI model to decide which model to use. Intelligent routing is deterministic, local, and keyword based. AIR also does not automatically retry a provider whose health is exhausted on its own; see core/fallback.md for how recovery works.