Example: structured events
python
import asyncio
from air import AIR, ChatRequest, ChatResponse, Provider
from air.exceptions import RateLimitError
received_events = []
def forward_event(event):
# In a real backend, send this over your own WebSocket/SSE connection,
# write it to a log, or feed it to analytics. No console or TTS involved.
received_events.append({"type": event.type, "provider": event.provider, "reason": event.reason})
class FlakyProvider(Provider):
name = "flaky"
async def chat(self, request: ChatRequest) -> ChatResponse:
raise RateLimitError("simulated rate limit", provider=self.name)
class BackupProvider(Provider):
name = "backup"
async def chat(self, request: ChatRequest) -> ChatResponse:
return ChatResponse(content="ok", provider=self.name, model="demo")
async def main():
air = AIR()
air.on_event(forward_event)
air.add_provider(FlakyProvider(), priority=1)
air.add_provider(BackupProvider(), priority=2)
response = await air.chat("Hello")
print("via callback:", received_events)
print("via response.structured_events:", [e.type for e in response.structured_events])
if __name__ == "__main__":
asyncio.run(main())Both received_events (populated by the on_event callback) and response.structured_events reflect the same underlying events for this call, including a provider_switch event from flaky to backup. See ../features/structured-events.md.