Clients, agents, and sessions
The three-tier model every SDK shares — credential, reusable persona, one live run.
All three SDKs are built around the same three nouns:
| Tier | Holds | Lifetime |
|---|---|---|
| Client | credential (API key or token), base URL, transport | your process |
| Agent | the persona: instructions, model, voice, tools, skills, hooks | reusable, immutable |
| Session | one live run: LiveKit room, event stream, per-run options | connect → end |
The split matters because the pieces vary at different rates: your credential is process-wide, your persona is designed once and reused, and a session is one conversation. If a value wouldn't differ between two runs of the same agent (voice, greeting, tool set), it belongs on the agent. If it varies run-to-run (resume id, whether to record), it's a session option.
client = CosmoRealtime(api_key=os.environ["COSMO_API_KEY"])
agent = client.agent(
instructions="You are Alex, a support agent at Acme.",
voice="Puck",
tools=[lookup_order],
greeting="Hi, this is Alex — how can I help?",
)
async with agent.start(store_recording=False) as session:
async for event in session:
...const client = new RealtimeClient({ token: endUserJwt });
const agent = client.agent({
instructions: 'You are Alex, a support agent at Acme.',
voice: 'Puck',
tools: [lookupOrder],
greeting: 'Hi, this is Alex — how can I help?',
});
const session = await agent.start();In Swift the agent tier is the SessionConfig value you pass to RealtimeSession.start(_:config:) — build one SessionConfig and reuse it across sessions.
Inline agents
client.agent(...) defines the persona in code. Everything is explicit: instructions, model, model_options, voice, tools, greeting, interruption_sensitivity, audio, skills, hooks. How the agent sounds rides under voice (name, speaking_style); the audio pipeline rides under audio (output, noise_cancellation, ambience). Anything you omit gets a server default (for example, the workspace's default model and voice) — with one exception: an inline agent that leaves audio.noise_cancellation unset sends an explicit true, overriding the protocol's own false default. Pass it explicitly to opt out.
Derive variants without mutating: agent.with_(voice="Kore") in Python, agent.with({ voice: 'Kore' }) in TypeScript. The original agent is untouched.
Catalog agents
A catalog agent's configuration lives server-side, created and edited in the dashboard (Realtime agents). Your code launches it by its machine handle:
agent = client.catalog_agent(
"support-triage",
inputs={"customer_name": "Dana"}, # fills {{customer_name}} in the stored prompt
voice="Puck", # per-run cosmetic override
)const agent = client.catalogAgent('support-triage', {
inputs: { customer_name: 'Dana' },
voice: 'Puck',
});var config = SessionConfig()
config.agentName = "support-triage"
config.agentInputs = ["customer_name": "Dana"]Only per-run ride-alongs are accepted alongside a catalog handle — inputs, a voice override, extra tools, hooks. Sending stored-config fields like instructions or model with a catalog agent is a schema error: the stored config is the source of truth, and the server rejects the ambiguity rather than guessing.
Catalog agents are how you iterate on a shipped product without an app release: the client names the agent; prompt, model, voice, and server-tool changes land from the dashboard.
Session options
Per-run options ride on start(), not on the agent:
| Option | Effect |
|---|---|
resume_session_id | continue a prior session's conversation (experimental — see Session limits & resume) |
store_recording | persist audio/transcript/tool artifacts server-side (see Recording & privacy) |
max_session_seconds | request a wall-clock cap; server enforces the minimum of yours and its own (exposed on Swift's SessionConfig today) |
on_state_change (Python) | callback for idle → connecting → connected ↔ reconnecting → disconnected |
The server resolves the final configuration at session start and reports it on the ready event: the resolved agent summary (for catalog handles), any rejected_tools, and the effective max_session_seconds. Trust ready, not your request, as the statement of what the session actually got.