Full-duplex voice evaluation via provider-specific realtime APIs. Each provider connects to a different voice AI service and exposes the same DiscreteTimeAdapter interface to the simulation framework.
| Provider | Type | API | Model |
|---|---|---|---|
| openai | Native audio | OpenAI Realtime API | gpt-realtime-1.5 |
| gemini | Native audio | Google Gemini Live | gemini-3.1-flash-live-preview |
| xai | Native audio | xAI Grok Voice Agent | xai-realtime |
| nova | Native audio | Amazon Nova Sonic | amazon.nova-2-sonic-v1:0 |
| qwen | Native audio | Alibaba Qwen Omni | qwen3-omni-flash-realtime |
| livekit | Cascaded (STT→LLM→TTS) | LiveKit + Deepgram + OpenAI | Configurable |
DiscreteTimeAdapter (adapter.py) ← shared base class
├── _async_run_tick() ← template method: buffering, transcript, timing
├── _send_audio_chunked() ← shared VoIP send helper
├── StreamingTelephonyConverter ← shared audio format conversion (audio_converter.py)
│
├── gemini/discrete_time_adapter.py ← implements _execute_tick + _flush_pending_tool_results
├── openai/discrete_time_adapter.py
├── xai/discrete_time_adapter.py
├── qwen/discrete_time_adapter.py
├── nova/discrete_time_adapter.py
└── livekit/discrete_time_adapter.py ← own run_tick (cascaded pipeline, different interaction model)
Each provider has:
provider.py— WebSocket/API client (connect, send audio, receive events)events.py— Pydantic models for provider-specific event typesdiscrete_time_adapter.py— Implements_execute_tick(): convert audio, send, receive, process events
The base class handles: TickResult creation, audio buffering/capping, proportional transcript distribution, barge-in buffer clearing, tool result queuing, tick timing enforcement, and cumulative state tracking.
- Create
provider.pywithconnect(),send_audio(),receive_events_for_duration(),send_tool_result() - Create
events.pywith typed event models and aparse_*_event()function - Create
discrete_time_adapter.pyextendingDiscreteTimeAdapter:__init__: set up converter, chunk size, provider_execute_tick: convert audio, send + receive concurrently, process events_flush_pending_tool_results: send queued tool results to APIconnect/disconnect/run_tick/is_connected: lifecycle (useBackgroundAsyncLoop)
- Register in
adapter.pycreate_adapter()factory - Add to
config.py(model, sample rates, endpoints) - Run
test_provider_suite.pyto validate
# Run suite for all available providers
uv run tests/test_voice/test_audio_native/run_provider_suite.py
# Run for a specific provider
uv run pytest tests/test_voice/test_audio_native/test_provider_suite.py -v -k geminiSee test_provider_suite.py docstring for architecture details.