Module scenario.voice.adapters.livekit
LiveKitAgentAdapter: join a LiveKit room as a participant and exchange audio.
Source §5.2. Publishes user-simulator audio to the room; subscribes to the agent-under-test's audio track.
Expand source code
"""
LiveKitAgentAdapter: join a LiveKit room as a participant and exchange audio.
Source §5.2. Publishes user-simulator audio to the room; subscribes to the
agent-under-test's audio track.
"""
from __future__ import annotations
from typing import ClassVar, Optional
from ..adapter import VoiceAgentAdapter
from ..audio_chunk import AudioChunk
from ..capabilities import AdapterCapabilities
from ._stub import PendingTransportError
class LiveKitAgentAdapter(VoiceAgentAdapter):
capabilities: ClassVar[AdapterCapabilities] = AdapterCapabilities(
streaming_transcripts=True,
native_vad=True,
dtmf=False,
input_formats=["pcm16/48000"],
output_formats=["pcm16/48000"],
)
def __init__(self, url: str, api_key: str, api_secret: str, room: str):
super().__init__()
self.url = url
self.api_key = api_key
self.api_secret = api_secret
self.room = room
self._room: Optional[object] = None
def __repr__(self) -> str: # redact credentials
return f"LiveKitAgentAdapter(url={self.url!r}, room={self.room!r}, api_key='***', api_secret='***')"
async def connect(self) -> None:
self._room = object()
async def disconnect(self) -> None:
self._room = None
async def send_audio(self, chunk: AudioChunk) -> None:
if self._room is None:
raise RuntimeError("LiveKitAgentAdapter: not connected")
raise PendingTransportError("LiveKitAgentAdapter")
async def recv_audio(self, timeout: float) -> AudioChunk:
if self._room is None:
raise RuntimeError("LiveKitAgentAdapter: not connected")
raise PendingTransportError("LiveKitAgentAdapter")
Classes
class LiveKitAgentAdapter (url: str, api_key: str, api_secret: str, room: str)-
Abstract base for voice agents that exchange audio with the agent under test.
Subclasses implement
connect,disconnect,send_audio, andrecv_audio. The defaultcallimplementation threads audio extracted from the last incoming message through the transport and wraps the response back into an assistant message.Attributes
capabilities- Declaration of what the adapter can and cannot do. Each concrete subclass must set this as a class attribute.
response_timeout-
Seconds to wait for agent audio after sending user audio. Defaults to 60 seconds.
60 seconds covers a typical real-world STT → LLM → TTS round-trip including backoff/retry inside each provider, tool calls, and RAG lookups. If you see TimeoutError flakes against a fast LLM-only chain, you can lower this; if your agent does heavy processing (MCP roundtrips, multi-step tool chains), consider raising it.
Override per-adapter at construction time::
adapter = MyVoiceAdapter() adapter.response_timeout = 90.0 # slow tool-call chain
Expand source code
class LiveKitAgentAdapter(VoiceAgentAdapter): capabilities: ClassVar[AdapterCapabilities] = AdapterCapabilities( streaming_transcripts=True, native_vad=True, dtmf=False, input_formats=["pcm16/48000"], output_formats=["pcm16/48000"], ) def __init__(self, url: str, api_key: str, api_secret: str, room: str): super().__init__() self.url = url self.api_key = api_key self.api_secret = api_secret self.room = room self._room: Optional[object] = None def __repr__(self) -> str: # redact credentials return f"LiveKitAgentAdapter(url={self.url!r}, room={self.room!r}, api_key='***', api_secret='***')" async def connect(self) -> None: self._room = object() async def disconnect(self) -> None: self._room = None async def send_audio(self, chunk: AudioChunk) -> None: if self._room is None: raise RuntimeError("LiveKitAgentAdapter: not connected") raise PendingTransportError("LiveKitAgentAdapter") async def recv_audio(self, timeout: float) -> AudioChunk: if self._room is None: raise RuntimeError("LiveKitAgentAdapter: not connected") raise PendingTransportError("LiveKitAgentAdapter")Ancestors
- VoiceAgentAdapter
- AgentAdapter
- abc.ABC
Class variables
var capabilities : ClassVar[AdapterCapabilities]
Inherited members