Connecting to a room
Use agents-go with LiveKit — the URL, token, and identity a room needs.
The roomio transport joins a LiveKit room and binds its audio (and
transcription) to a session. To join, it needs three things in
transport.RoomConnectOptions: a server URL, a join Token, and — optionally —
which participant to listen to. This page is where those come from.
session.Start(ctx, agents.StartOptions{
Agent: agent,
Transport: roomio.Bind(transport.RoomConnectOptions{
URL: url, // your LiveKit server
Token: token, // a join token minted by your backend (or handed to you by the dispatcher)
}, roomio.Options{}),
})What each field is
| Field | What it is | Where it comes from |
|---|---|---|
URL | Your LiveKit server's WebSocket URL | Config — wss://<project>.livekit.cloud (Cloud) or wss://<host>:7880 (self-hosted) |
Token | A LiveKit access token (JWT) granting join to one room, carrying the agent's identity | Minted by your backend from your LiveKit API key + secret — or handed to a worker by the dispatcher |
ParticipantIdentity | Which remote participant (the caller) the agent links its audio to; empty = the first one to publish | You choose |
ParticipantName | The agent's display name in the room | You choose |
The agent's own identity lives inside the Token, not in ParticipantIdentity.
ParticipantIdentity selects whose audio the agent subscribes to (the human);
leave it empty to link the first participant that speaks.
Two ways to get URL + Token
There are two paths, and which one you use decides whether you mint the token yourself.
Dispatched worker (recommended for production)
A worker registers with LiveKit; when a room needs an agent, the server dispatches a job and hands the worker the URL and a freshly-minted token. You don't mint anything.
Standalone (you drive the join)
Your app decides 'join this room now', mints a token, and calls roomio.Bind directly. Right for tools, tests, and simple setups.
Dispatched worker — token comes from the JobContext
In the worker model you never build the token.
The LiveKit server mints it per job and hands the worker URL and Token on the
JobContext:
w, _ := worker.New(worker.WorkerOptions{
Entrypoint: func(ctx context.Context, jc *worker.JobContext) error {
session, err := agents.NewSession(agents.Config{
STT: "openai/gpt-4o-mini-transcribe", LLM: "openai/gpt-4o", TTS: "openai/tts-1",
})
if err != nil {
return err
}
agent := agents.MustNewAgent(agents.AgentOptions{Instructions: "be helpful"})
return session.Start(ctx, agents.StartOptions{
Agent: agent,
Transport: roomio.Bind(transport.RoomConnectOptions{
URL: jc.URL, // handed to you by the dispatcher
Token: jc.Token, // minted by the LiveKit server for this job
}, roomio.Options{}),
})
},
})Standalone — mint the token in your backend
When your app drives the join itself, mint a token server-side with LiveKit's Go
server SDK (github.com/livekit/protocol/auth) from your API key and secret. The
secret never leaves your backend.
import "github.com/livekit/protocol/auth"
// Mint a join token for the agent to enter roomName as `identity`.
func agentToken(apiKey, apiSecret, roomName, identity string) (string, error) {
canPublish, canSubscribe := true, true
at := auth.NewAccessToken(apiKey, apiSecret)
at.SetVideoGrant(&auth.VideoGrant{
RoomJoin: true,
Room: roomName,
CanPublish: &canPublish, // the agent speaks
CanSubscribe: &canSubscribe, // the agent hears the caller
})
at.SetIdentity(identity) // becomes the agent's identity in the room
at.SetName("agents-go")
at.SetValidFor(time.Hour)
return at.ToJWT()
}Then pass the result straight into roomio.Bind. (Method names track your
livekit/protocol version; see LiveKit's server-SDK / authentication docs for the
exact surface. For a quick local test, lk token create … or the LiveKit Cloud
dashboard produce a token too — that's what the examples/roomio
LIVEKIT_TOKEN env expects.)
Never ship the API secret to a browser or mobile client. Tokens are minted on your server, scoped to one room, and short-lived. The frontend gets its own token (a different identity) the same way.
Build & run
roomio carries the WebRTC/media stack, so it builds behind the livekit build
tag (native Opus/SoXR):
LIVEKIT_URL=wss://your-host LIVEKIT_TOKEN=<join-jwt> \
go run -tags livekit ./examples/roomioroomio.Options also controls transcription publishing and subscription; see
Reference → Transport.
Related
- Plugin: LiveKit — roomio options and the dispatch source.
- Transports — the roomio overview and the
Bindingseam. - Deploy a worker — the dispatched-worker path.
- Architecture — LiveKit-optional dispatch.