Transports
Get audio in and out — console, WebSocket, WebRTC (roomio), and bindings.
A transport provides the audio (and text) I/O an AgentSession binds to. The
session is transport-oblivious — the same agent code runs over any of them, so
picking one is a wiring decision, not an agent rewrite.
console
PCM over stdin/stdout. Zero setup — ideal for local dev and tests.
websocket
Raw WebSocket audio. The seam telephony (Twilio media streams) uses.
roomio (WebRTC)
LiveKit room audio + transcription. Production real-time voice.
console
Pipes signed-16-bit mono PCM. Everything runs inside console.Run, which hands
your entrypoint a *console.Transport exposing tr.Input() / tr.Output().
import "github.com/webdeveloperben/agents-go/transport/console"
console.Run(ctx, console.RunOptions{
Reader: os.Stdin, Writer: os.Stdout,
Entrypoint: func(ctx context.Context, tr *console.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: tr.Input()},
Output: agents.SessionOutput{Audio: tr.Output()},
})
return session.Start(ctx, agents.StartOptions{Agent: agent})
},
})See Build a voice agent for the full console walkthrough.
websocket
The generic WebSocket transport carries audio over a socket — this is what the
Twilio telephony path builds on. Each
connection becomes one session; websocket.NewSessionHandoff bridges an accepted
socket to a session function.
roomio (WebRTC)
roomio joins a LiveKit room and binds the room's audio I/O and transcription to
a session. It carries the WebRTC/media stack, so it's a plugin and builds
behind the livekit build tag (native Opus/SoXR):
import "github.com/webdeveloperben/agents-go/plugins/livekit/roomio"
// Binding form — the room connects and binds inside Start:
connectOpts := transport.RoomConnectOptions{URL: url, Token: token, ParticipantName: "agents-go"}
err := session.Start(ctx, agents.StartOptions{
Agent: agent,
Transport: roomio.Bind(connectOpts, roomio.Options{}),
})
// Or the explicit form, when you need the RoomIO handle (e.g. rio.Room()):
rio := roomio.NewRoomIO(session, roomio.Options{})
err = rio.Start(ctx, connectOpts, agent)go run -tags livekit ./examples/roomioWhere the URL, Token, and identity come from — and whether you mint the token
yourself or the dispatcher hands it to you — is covered in
Connecting to a room.
roomio is the only transport that needs a build tag, because it pulls the
WebRTC/media stack. Console and WebSocket are pure Go and always available.
Bindings
A Binding lets a transport connect and hand its I/O to Start (rather than you
wiring Input/Output by hand): Start calls Connect first, and closes the
binding if start fails afterward. roomio.Bind above is the built-in binding;
console and WebSocket keep their own Run/Handler entrypoints. See
Reference → Transport for the interface.
Choosing
- Local dev / tests → console.
- Phone calls → websocket + the Twilio plugin.
- Browser / app real-time voice → roomio.
Related
- Plugins: LiveKit · Twilio — per-transport config.
- Reference: Transport
- Architecture — why the session is transport-oblivious.