Skip to main content
SONZAI

Sessions

A session is one continuous conversation between an agent and a user. Sonzai uses session boundaries to scope fact extraction, consolidation, and recall.

What a Session Is

A session is one continuous conversation between an agent and a user, identified by a session_id you control. Sessions are Sonzai's unit of consolidation: when a session ends, the platform extracts facts from the transcript, tags every fact with its source session_id, and runs the memory pipeline (dedup, cluster, decay) before the next session begins.

Sessions are not a wrapper around individual messages — they're how Sonzai knows which messages belong together for extraction. A session can last seconds or days.

You always have a session

Every /chat call belongs to a session. If you don't start one explicitly, the platform creates one for you. Session IDs flow through to extracted facts either way — you never lose attribution.

Two Ways to Use Sessions

Auto-session (simplest)

Just call agents.chat without touching the sessions API. The platform creates a session on the first message, keeps it open while the conversation is active, and closes it automatically when the conversation goes idle. This is the right default for most apps.

Explicit session

Call sessions.start before the first message and sessions.end when the conversation is definitively over. Use this when you need to:

  • Register custom tools for a specific conversation (tool_definitions on sessions.start).
  • Control boundary timing — e.g. end a coaching call exactly when the user hangs up, not when the idle timer fires.
  • Replay historical transcripts — pass the full message list to sessions.end(messages=...) to ingest a canned conversation verbatim, which is how data migration and benchmarks work.
  • Scope memory extraction around a meaningful unit (a support case, a daily stand-up, a D&D game night).

Session Lifecycle

1. sessions.start         — Register session_id (+ optional tools); get ready to accept messages
2. agents.chat (× N)      — Stream turns through the session; facts extracted inline
3. sessions.end           — Close the session; triggers consolidation, dedup, diary, clustering
                          → every extracted fact carries this session_id

If you skip step 1, the first agents.chat call will auto-register a session. If you skip step 3, the session closes on idle timeout (configurable per tenant).

Starting and Ending a Session

import { Sonzai } from "@sonzai-labs/agents";

const sonzai = new Sonzai({ apiKey: process.env.SONZAI_API_KEY! });
const AGENT_ID = "agent_abc";
const USER_ID = "user_123";
const SESSION_ID = crypto.randomUUID();

// 1. Start
await sonzai.agents.sessions.start(AGENT_ID, {
user_id: USER_ID,
session_id: SESSION_ID,
user_display_name: "Mia",
});

// 2. Chat turns
const reply = await sonzai.agents.chat({
agent: AGENT_ID,
user_id: USER_ID,
session_id: SESSION_ID,
messages: [{ role: "user", content: "Hi, quick question..." }],
});

// 3. End — triggers fact extraction + consolidation
await sonzai.agents.sessions.end(AGENT_ID, {
user_id: USER_ID,
session_id: SESSION_ID,
total_messages: 2,
});

Session IDs on Extracted Facts

Every fact Sonzai extracts carries its source session_id and source_id. You can use these to:

  • Reconstruct a conversation's memory footprint — "what did the agent learn from session X?" via GET /memory/timeline (grouped by session) or GET /memory/facts (filter client-side by session_id).
  • Score retrieval at session granularity — benchmarks like LongMemEval evaluate whether retrieved facts come from the correct source session.
  • Surface recency context — "conversations from last Tuesday" resolves via the session's created_at plus its attributed facts.

Facts that exist outside a specific conversation — agent-global wisdom, manually inserted facts, migrated priming content — carry empty session_id and are attributed through source_type instead (e.g. "manual", "agent_global").

Registering Session-Scoped Tools

Custom tool definitions can be scoped to a single session. Pass them on sessions.start, or update them mid-session via sessions.set_tools. Character-level (agent-wide) tools are always merged in — session tools layer on top for the duration of the session.

sonzai.agents.sessions.start(
    AGENT_ID,
    user_id=USER_ID,
    session_id=SESSION_ID,
    tool_definitions=[
        {
            "name": "check_patient_chart",
            "description": "Read the active patient's medication list.",
            "parameters": {
                "type": "object",
                "properties": {"patient_id": {"type": "string"}},
                "required": ["patient_id"],
            },
        }
    ],
)

Tool names starting with sonzai_ are reserved for platform-built-in tools.

When to Be Explicit

SituationAuto-sessionExplicit start / end
Simple chat app, one conversation per user per day
Multi-session app (support cases, tickets, coaching calls)
Need per-session custom tools✅ (pass tool_definitions on start)
Replaying a canned transcript (migration, eval, benchmark)✅ (pass messages on end)
Want consolidation to fire on your trigger, not idle timeout
Voice calls with well-defined start/end signals

What Happens on sessions.end

The end call is where Sonzai does its heavy lifting. In the background, the platform runs:

  • Fact extraction from the transcript with coverage validation.
  • Grounding verification — every fact is checked against the actual messages to prevent hallucinated memories.
  • Session-end consolidation — a session summary is stored; facts are deduped against existing memory via SPO triples and embedding similarity.
  • Clustering + polarity checks — new facts find their thematic cluster; contradictions are flagged.
  • Diary and insights (if enabled) — the agent's internal narrative is updated.

None of this blocks the sessions.end response — it's asynchronous. The call returns as soon as the transcript is queued.

What's next

On this page