agents-go
Transports

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 one AgentSession.

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.

On this page