A sample that enables your ElevenLabs Conversational AI agent to only respond when people are talking to it, and stay silent to side conversations or background voices.
ElevenLabs runs its agent inside its own sealed WebRTC room, so this sample uses the streaming SDK:
- ElevenLabs' Python SDK exposes
AudioInterface, a clean 16-bit-PCM seam for the user mic and the agent's TTS. - The sample wraps it and feeds the user mic to SAA via
attenlabs-saa'sfeed_audio()(the SDK is in feed mode:enable_audio=False, it captures nothing itself). - SAA classifies each frame and emits
prediction/vad/interruptevents. - The sample gates the agent on those events: it forwards only device-directed audio onward and nothing between turns, then streams a short silence tail once SAA reports the turn is done so ElevenLabs' turn model endpoints and replies.
| Sample | Stack | Run |
|---|---|---|
voice_agent/ |
ElevenLabs Conversational AI (managed speech-to-speech), SAA-gated via feed_audio |
python agent.py |
Needs Python 3.10 to 3.12 and an ElevenLabs agent ID.
git clone https://github.com/attenlabs/saa-sdk.git
cd saa-sdk/examples/elevenlabs
cp .env.example .env # fill SAA_API_KEY, ELEVENLABS_API_KEY, ELEVENLABS_AGENT_ID
cd voice_agent
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ../../../packages/saa-py # local dev against this repo
pip install -r requirements.txt
python agent.pyThe sample auto-loads examples/elevenlabs/.env, so the command is identical on Windows, macOS, and Linux.
attenlabs-saa is pure Python and installs cleanly. The only Windows friction is pyaudio
(pulled in by elevenlabs[pyaudio] for microphone capture), which has no wheels for the
newest Python and otherwise compiles from source against PortAudio.
- Use Python 3.11 or 3.12.
- Install
pyaudiofrom a wheel, not source, beforepip install -r requirements.txt:pip install pipwin && pipwin install pyaudio, or- Conda:
conda install -c anaconda pyaudio, or - download a matching
.whlandpip install path\to\PyAudio...whl.
- If a long-path error appears when cloning into a deep folder, enable long paths once in an Administrator PowerShell, then retry:
or clone closer to the drive root.
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1
saa = AttentionClient(token=SAA_API_KEY, enable_audio=False, enable_video=False)
attn = SAAFeedAudioInterface(DefaultAudioInterface(), saa) # tee + feed_audio + gate
@saa.on_prediction
def _(ev): attn.update_gate(ev.cls) # only device-directed audio reaches the agent
conversation = Conversation(..., audio_interface=attn)
saa.start(); conversation.start_session()SAAFeedAudioInterface also drives saa.mark_responding() from the agent's TTS, so SAA knows when the agent is the one speaking. See voice_agent/README.md for the full walk-through and tradeoffs.
One env file, .env in this directory:
| Key | Purpose |
|---|---|
SAA_API_KEY |
Your attention labs API key. Get one at attentionlabs.ai/dashboard. |
ELEVENLABS_API_KEY |
ElevenLabs API key |
ELEVENLABS_AGENT_ID |
The agent to talk to |
- Audio-only, ElevenLabs gives SAA no video, so class-1 ("talking to a human") is weaker than on the multimodal LiveKit / Pipecat paths.
- The gate opens ~250 ms after device-directed speech starts (classifier latency); a hard gate can clip an utterance's first syllable. See the sample README for the softer
register_user_activityalternative. - Interjection is JS-only today, so it isn't wired in this Python sample.
- Barge-in is handled by ElevenLabs' own VAD.
Try three send thresholds and keep the one that performs best: 0.5, 0.7, 0.8.
Raise it for fewer false triggers, lower it to catch borderline speech. Set SAA_CLASS2_THRESHOLD, or call saa.set_threshold(v) live.