Skip to content

TwilioAgentAdapter

Connects to a Twilio phone number over Media Streams (WebSocket) and drives a full inbound or outbound call. Supports DTMF detection and the full Twilio call-state lifecycle.

Constructor

python
import os
import scenario
 
adapter = scenario.TwilioAgentAdapter(
    account_sid=os.environ["TWILIO_ACCOUNT_SID"],
    auth_token=os.environ["TWILIO_AUTH_TOKEN"],
    phone_number=os.environ["TWILIO_PHONE_NUMBER"],
    http_port=8765,
)

All arguments are keyword/option-named. Beyond the core ones: public_base_url / publicBaseUrl, allowed_callers, on_dtmf, http_port / httpPort (default 8765), role (default AgentRole.AGENT), validate_signature (default True — set to False only when running against a local test harness that can't sign webhook requests).

Test harness (recommended)

For end-to-end tests you need a public HTTPS URL that routes Twilio's webhook to this machine.

python
# Python: TwilioHarness spins up a cloudflared quick tunnel, configures the
# Twilio webhook for the lifetime of the `async with` block, and tears down on exit.
import os
from scenario.voice.testing import TwilioHarness
 
async with TwilioHarness(
    account_sid=os.environ["TWILIO_ACCOUNT_SID"],
    auth_token=os.environ["TWILIO_AUTH_TOKEN"],
    phone_number=os.environ["TWILIO_PHONE_NUMBER"],
    http_port=8766,
) as adapter:
    # Pass `adapter` to `scenario.run(...)`.
    ...

Capabilities

streaming_transcriptsnative_vaddtmfinterruptioninput_formatsoutput_formats
mulaw/8000mulaw/8000

DTMF tones: send them with scenario.dtmf("1") in your script step (same step name in both SDKs).

VAD: Twilio has no native VAD; the SDK falls back to webrtcvad. See Troubleshooting → VAD didn't fire.

Worked examples

  • Python: dtmf_ivr.py — DTMF-driven IVR menu test from dial-in to hang-up; twilio_inbound.py — inbound call test; twilio_outbound.py — dialer-side outbound test.
  • TypeScript: the Twilio tunnel + adapter path is covered by the @ts-twilio-tunnel binding in specs/voice-agents.feature (real-phone demos are gated manual — they need a tunnel + a second number).

Common failures