AIR

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:

  1. Classifies the request with air.routing.intelligent.classify_request, using simple keyword based rules, not another model call:
    • If any message contains ``` or one of def , class , function, stack trace, traceback, compile error, the request requires the coding capability.
    • If any message contains step by step, explain why, prove that, or walk through your reasoning, reasoning is a preferred (not required) capability.
    • If the estimated token count is under 200 and reasoning was not already preferred, speed becomes a preferred capability.
    • ChatRequest.requires (a set[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.
  2. Scores each currently registered provider with select_provider, skipping any provider that:
    • has health status exhausted,
    • is missing a required capability (coding, vision, or tool_use) declared via add_provider(..., capabilities={...}),
    • has a configured context_tokens capability 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.
  3. Among the remaining candidates, picks the highest scoring one. Score increases for each satisfied required capability, for satisfying preferred reasoning or speed capabilities, for being in available health status, and for having known or estimated (not just unknown) capacity. Ties keep the earlier one in priority order.
  4. 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.
  5. 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.