Skip to content

Sessions

A session is the unit of conversation persistence in Agentrail. It holds the message history for a single user's ongoing conversation with an agent.

What a Session Is

Each session has:

  • a unique sessionId (UUID)
  • an owner identity: tenantId + userId + agentId
  • an ordered list of messages (the conversation history)
  • a cumulative token usage record

Sessions are created on the first request and resumed on subsequent requests by passing the sessionId in the request body. If no sessionId is provided, a new session is created automatically.

Session Lifecycle

First request (no sessionId)


getOrCreate → new session created → sessionId returned in response


Client stores sessionId and sends it on subsequent requests


getOrCreate → existing session resumed

Session Store Contract

The host layer depends on the AgentrailSessionStore contract rather than any concrete storage implementation. This means you can swap out the storage backend without changing your host code.

The required contract includes:

MethodCalled when
getOrCreateEvery request — creates or resumes the session
loadMessagesWithBudgetEvery request — loads history trimmed to the token budget
loadAllMessagesDuring compaction — loads full history to assess whether to compact
appendMessagesAfter agent completes — persists the new turn's messages
recordTurnAfter agent completes — persists token usage
compactIfNeededDuring each request — summarizes old history if token threshold is exceeded

Additional optional methods (readMemoryDocument, writeMemoryDocument, readToolResultArtifact, writeToolResultArtifact) unlock memo tools and tool-result compaction. When also passing your store as memoProvider to SandboxManager, implement listToolResultArtifactIds as part of the SandboxMemoProvider contract to enable full /workspace/memo/** sandbox access. See Session Store Reference for the complete interface.

Default Implementation: SessionManager

The default session store is SessionManager from @agentrail/app. It uses the local filesystem to persist sessions, with one directory per session:

ts
import { SessionManager } from "@agentrail/app";

const sessionManager = new SessionManager("/tmp/agentrail-sessions");

The path is the root directory under which all tenant/session data is stored. In production, point dataDir at a persistent volume so sessions survive container restarts. For multi-instance deployments, mount a shared filesystem (NFS, EFS, etc.) at the same path on all instances.

Turn Persistence

A turn is one complete interaction: a user message followed by the agent's full response (which may involve multiple LLM calls and tool executions).

After each turn, the host:

  1. Calls appendMessages to write the new user and assistant messages
  2. Calls recordTurn to record token usage for billing or observability

During streaming, appendMessages is called incrementally after each internal reasoning turn (one LLM call plus any tool executions it triggers), rather than once at the end of the full interaction. This means messages are durable on disk as soon as each reasoning step completes, not only after the SSE stream closes. recordTurn is still called once when the entire interaction finishes. Plugins can react to this via the onTurnPersisted hook.

Note: "internal reasoning turn" here refers to the runtime's turn.complete event, which is distinct from the public session concept of a "turn" (one full user interaction).

History Loading with Token Budget

The host does not load unlimited history. On each request, it calls loadMessagesWithBudget to retrieve as many recent messages as fit within the model's context window (minus room for the current turn and context providers).

This ensures the context window is never overflowed by long sessions. The contextWindow field on the profile controls the token limit used for this calculation.

For long-running single requests, Agentrail can also apply in-loop reactive compaction before the next model call. That path rewrites only the in-memory request history; persisted session files are still managed by request-boundary compaction.

Implementing a Custom Store

For most deployments, SessionManager with a persistent or shared volume is the recommended approach. For advanced use cases where the AgentrailSessionStore interface needs to be implemented from scratch (for example, integrating with an existing message persistence layer or adding custom access controls), any object satisfying the interface can be passed via sessionStore.

See the Session Store Reference for the full interface and Build a Storage Backend for a complete implementation guide.

Released under the Apache 2.0 License.