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
- Agents & handoffs — the persona the session drives.
- Speech & the turn — what
Run/GenerateReplydo. - Chat context & history — read and seed the conversation.
- Full API: Reference → AgentSession.