Quick start
This example configures two providers and sends one request. AIR tries them in priority order and falls back automatically if the first one fails.
python
import asyncio
import os
from air import AIR
from air.providers.xai import XAIProvider
from air.providers.gemini import GeminiProvider
async def main():
air = AIR()
air.add_provider(
XAIProvider(api_key=os.environ["XAI_API_KEY"], model="grok-4-0709"),
priority=1,
)
air.add_provider(
GeminiProvider(api_key=os.environ["GEMINI_API_KEY"], model="gemini-2.5-flash"),
priority=2,
)
response = await air.chat("Hello")
print(response.content)
print(response.provider, response.model)
asyncio.run(main())air.chat(...) accepts either a plain string, which becomes a single user message, or a ChatRequest for more control over model, temperature, max_tokens, and other fields. See reference/models.md.
Adding a provider
add_provider(provider, priority=None, limits=None, capabilities=None):
provideris an instance of a class implementingair.providers.base.Provider(any of the four built in providers, or your own).priorityis an integer. Lower numbers are tried first. If omitted, AIR assigns the next unused priority in registration order.limitsis an optional dict such as{"tokens": 100_000, "reserve": 5_000}. See features/capacity-tracking.md.capabilitiesis an optional dict such as{"coding": True, "context_tokens": 128_000}, used only by intelligent routing. See features/intelligent-routing.md.
Registering the same provider name twice raises ProviderAlreadyRegisteredError.
Sending a request
await air.chat(request) where request is a str or a ChatRequest. It returns a ChatResponse with the answer, which provider and model produced it, and routing metadata. See reference/air.md and reference/models.md.
Next steps
- core/routing.md to understand how AIR picks a provider.
- core/sessions.md to keep conversation history across turns.
- features/structured-events.md to observe routing decisions programmatically.