agents-go
Building agents

Agent sessions

The runtime that drives one conversation — build it, start it, observe it.

An AgentSession runs one live conversation. It binds to a transport's I/O, resolves the effective models, drives the turn loop, owns the active agent, and emits events. It is transport-oblivious — the same session runs over console, WebRTC, or a phone call — which is what lets one agent scale from a laptop to a fleet without changing its code.

Build a session

The ergonomic constructor is NewSession. Models are named with "provider/model[:variant]" strings (resolved once you import the provider plugin — see Models & providers), or passed as concrete model values.

import (
    "github.com/webdeveloperben/agents-go/agents"

    _ "github.com/webdeveloperben/agents-go/plugins/openai"
)

session, err := agents.NewSession(agents.Config{
    STT: "openai/gpt-4o-mini-transcribe",
    LLM: "openai/gpt-4o",
    TTS: "openai/tts-1:alloy",
    // VAD, Turn, Tools, Input, Output, UserData, ... also live on Config
})

Config model fields take a spec string or a concrete model (openai.NewLLM(...)), so you can drop to full provider options anytime. MustNewSession is the panic-on-error form for setup code. Under the hood it builds AgentSessionOptions and calls the fully-typed NewAgentSession — nothing in the typed path is hidden from you.

Start it on an agent

Start makes an agent active (running its OnEnter) and begins the turn loop. Audio I/O comes from the session's Input/Output, from StartOptions, or from a transport binding.

agent := agents.MustNewAgent(agents.AgentOptions{
    Instructions: "You are a friendly booking assistant.",
})

if err := session.Start(ctx, agents.StartOptions{Agent: agent}); err != nil {
    return err
}
defer func() { _ = session.Close(context.Background()) }()

For a quick text turn (or a test), session.Run generates one reply and blocks until it finishes, returning a RunResult:

result, _ := session.Run(ctx, agents.RunOptions{UserInput: "Hello!"})
fmt.Println(result.FinalOutput())

The state machine

A session runs a small state machine — initializing → idle → listening → thinking → speaking → closed — plus a user state (listening / speaking / away). You mostly observe these; the runtime drives them.

Observe a session

SubscribeEvents returns a subscription you range over; the buffer sizes its channel (events drop for a slow consumer past the buffer). This is the primary way to log or react to a session:

sub := session.SubscribeEvents(ctx, 32)
defer sub.Close()
for ev := range sub.Events {
    switch ev.Type {
    case agents.EventItemAdded:
        log.Printf("item: %v", ev.Item)
    case agents.EventError:
        log.Printf("session error: %v", ev.Error)
    case agents.EventClose:
        return
    }
}

Event types include item_added, agent_state_changed, user_state_changed, user_input_transcribed, metrics_collected, usage_updated, speech_created, agent_false_interruption, user_turn_exceeded, error, and close. SubscribeAgentState / SubscribeUserState are narrower streams of just the state transitions.

Next

On this page