agents-go
Transports

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

FieldWhat it isWhere it comes from
URLYour LiveKit server's WebSocket URLConfig — wss://<project>.livekit.cloud (Cloud) or wss://<host>:7880 (self-hosted)
TokenA LiveKit access token (JWT) granting join to one room, carrying the agent's identityMinted by your backend from your LiveKit API key + secret — or handed to a worker by the dispatcher
ParticipantIdentityWhich remote participant (the caller) the agent links its audio to; empty = the first one to publishYou choose
ParticipantNameThe agent's display name in the roomYou 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/roomio

roomio.Options also controls transcription publishing and subscription; see Reference → Transport.

On this page