Telephony with Twilio
Answer phone calls over a media stream.
The Twilio plugin turns an inbound phone call into an AgentSession bound to the
call's audio. Twilio connects a Media Stream (a WebSocket carrying μ-law
audio) to your server; each call becomes one session over the generic WebSocket
transport.
The shape
Two endpoints:
- Voice webhook (
POST) — Twilio hits this when a call comes in; you answer with TwiML telling Twilio to open a bidirectional media stream. - Media WebSocket (
GET) — each call's audio; bound to oneAgentSession.
Serve the webhook
The plugin builds the TwiML and provides an HTTP handler:
import "github.com/webdeveloperben/agents-go/plugins/twilio"
http.Handle("/twilio/voice", twilio.WebhookHandler(twilio.WebhookConfig{
// StreamURL: wss://<host>/twilio/media (derived from the request if empty)
}))twilio.BuildTwiML(streamURL, params) is available if you build the response
yourself.
Bind media to a session
Run a worker whose entrypoint builds the session, and hand each media WebSocket
to it over the WebSocket transport. websocket.NewSessionHandoff bridges an
accepted socket to a session function — its Entrypoint adapts a
websocket.SessionFunc (func(ctx, *websocket.Transport) error) into the
worker.EntrypointFunc the worker expects:
handoff := websocket.NewSessionHandoff()
w, _ := worker.New(worker.WorkerOptions{
Entrypoint: handoff.Entrypoint(func(ctx context.Context, t *websocket.Transport) error {
session, _ := agents.NewSession(agents.Config{
LLM: "openai/gpt-4o", STT: "openai/gpt-4o-mini-transcribe", TTS: "openai/tts-1",
Input: agents.SessionInput{Audio: t.Input()}, // Twilio media in
Output: agents.SessionOutput{Audio: t.Output()}, // agent audio out
})
agent := agents.MustNewAgent(agents.AgentOptions{Instructions: "You answer the phone."})
return session.Start(ctx, agents.StartOptions{Agent: agent})
}),
})The runnable examples/twiliovoice wires both endpoints end to end using the
in-repo fakes, so it runs with no cloud accounts.
Run it
Expose your server
Twilio needs a public HTTPS URL. In development, tunnel it — e.g. ngrok http 8080.
Point your number at the webhook
Set the Twilio number's Voice webhook to https://<tunnel>/twilio/voice.
Call the number
The webhook answers with TwiML, Twilio opens the media stream, and your agent picks up.
The session code is identical to any other transport — only the I/O binding differs. Swapping the fakes for real provider plugins doesn't touch the Twilio wiring.
Related
- Plugin: Twilio — webhook config and framing details.
- Transports · Architecture
- Deploy a worker