Session Management
Overview
Session Management is a critical module responsible for managing user-agent interaction sessions within the system. Its primary role is to persist session state and maintain a history of interaction events, enabling stateful multi-turn conversations and tracking of user-agent dialogues over time. The module supports pluggable storage backends, offering both in-memory and database-backed implementations to accommodate various deployment scenarios, from ephemeral local sessions during testing to persistent, scalable session storage in production environments.
This module ensures consistency and accessibility of session data, including session state, event history, and associated metadata, and provides APIs for creating, retrieving, listing, updating, and deleting sessions. It also manages the merging of state scoped at different levels: application-wide, user-specific, and session-specific, while filtering out transient or temporary state information.
Core Concepts and Design
Session and Event
Session: Represents a conversation or interaction context identified uniquely by a composite key consisting of an application name (
AppName), a user identifier (UserID), and a session identifier (SessionID). Each session maintains:A mutable state map holding key-value pairs relevant to the session.
An ordered list of events, which are discrete interaction records representing messages, LLM responses, or tool invocations.
A timestamp tracking the last update time.
Event: Encapsulates an individual interaction step within a session, containing:
Event metadata such as author, timestamp, invocation ID.
Action deltas that modify session state (
StateDelta).LLM response data including content, grounding, usage, and error information.
Flags such as
Partial, indicating incomplete events that should not be persisted.
State Scoping and Persistence
Session state is organized into three layered scopes:
Application State: Shared global state for all users and sessions within the same application (app: prefix keys).
User State: Specific to a given user across all their sessions (
user:prefix keys).Session State: Specific to an individual session without any prefix.
The module merges these scopes on retrieval so that clients see a composite view of state, while updates are segregated and persisted in their respective scopes. Temporary state keys prefixed with temp: are excluded from persistence and stripped from events before storage, ensuring ephemeral data does not pollute permanent storage.
Pluggable Backends
The module defines a Service interface that abstracts session storage operations such as Create, Get, List, Delete, and AppendEvent.
In-Memory Backend: Suitable for development or transient use cases, it stores sessions in thread-safe in-memory maps with locking for concurrency control. It maintains separate maps for app-level and user-level state and keeps the full event history in memory.
Database Backend: Uses GORM ORM to persist sessions and events in a relational database. It supports migrations, transactional updates, and efficient querying with filtering on event timestamps and limits.
Both implementations strictly adhere to the interface, allowing seamless switching or extension to other storage types.
Functionality and Workflows
Session Creation (Create)
Generates or accepts a client-provided session ID.
Initializes session state, merging any provided initial state with existing app and user state.
In the database backend, this operation is wrapped in a transaction to ensure atomicity when creating the session record and updating app/user state tables.
Session Retrieval (Get)
Retrieves a session by app name, user ID, and session ID.
Supports optional filtering of events by timestamp (After) and limiting the number of recent events returned (NumRecentEvents).
Merges app, user, and session states to provide a unified state view.
In the database implementation, events are queried and sorted by timestamp in descending order for efficient retrieval, then reversed before returning to clients.
Session Listing (List)
Lists all sessions for a given app and optional user.
Returns a slice of sessions without their full event histories.
Merges states similarly to
Getto reflect current state at the session level.
Event Appending (AppendEvent)
Adds a new event to an existing session.
Ignores partial events to avoid persisting incomplete interaction steps.
Before persisting, filters out temporary state keys from the event's state delta.
Updates session state according to the event's state delta.
In the database backend, this is performed within a transaction to ensure event insertion and session state update consistency.
Validates against stale sessions by comparing last update timestamps to prevent overwriting more recent data.
State Updates
State deltas extracted from events are separated into app, user, and session scopes based on key prefixes.
Each state scope is updated independently, enabling efficient sharing and isolation of state data.
Temporary keys are excluded from persistence.
Concurrency and Thread Safety
The in-memory implementation uses read-write mutexes to guard access to sessions and state maps.
The database implementation relies on transactional semantics provided by GORM and the underlying database to ensure consistency.
Interaction with Other Components
The session service is a fundamental dependency for the [Agent Execution Runner](None - Agent Execution Runner), which uses sessions to maintain conversation context and persist interaction events.
It interacts with the [Artifact Management](None - Artifact Management) indirectly by preserving state and events that may reference artifacts.
The session events stored and retrieved are used to reconstruct conversation history for agents, tools, and LLM calls, enabling contextual understanding.
The service supports pluggable backends allowing for flexible deployment configurations depending on persistence and scalability requirements.
Key Files and Their Roles
File | Role |
|---|---|
Defines the | |
Implements the in-memory backend with thread-safe session and state management. | |
Implements the database backend using GORM with transactional session and event logic. | |
Defines internal session representations and state update utilities for the database. | |
Defines GORM models for sessions, events, and app/user states, and mapping functions. |
Illustrative Code Snippet: Appending an Event in the In-Memory Service
func (s *inMemoryService) AppendEvent(ctx context.Context, curSession Session, event *Event) error {
if event.Partial {
return nil // Do not store partial events
}
sess, ok := curSession.(*session)
if !ok {
return fmt.Errorf("unexpected session type %T", sess)
}
s.mu.Lock()
defer s.mu.Unlock()
storedSession, ok := s.sessions.Get(sess.id.Encode())
if !ok {
return fmt.Errorf("session not found, cannot apply event")
}
// Append the event and update session state
if err := sess.appendEvent(event); err != nil {
return err
}
storedSession.events = append(storedSession.events, event)
storedSession.updatedAt = event.Timestamp
// Update app and user states separately
appDelta, userDelta, sessionDelta := sessionutils.ExtractStateDeltas(event.Actions.StateDelta)
s.updateAppState(appDelta, curSession.AppName())
s.updateUserState(userDelta, curSession.AppName(), curSession.UserID())
maps.Copy(storedSession.state, sessionDelta)
return nil
}
Session State Update and Filtering Logic
Temporary state keys prefixed with temp: are filtered out before persisting:
func trimTempDeltaState(event *Event) *Event {
if len(event.Actions.StateDelta) == 0 {
return event
}
filteredStateDelta := make(map[string]any)
for key, value := range event.Actions.StateDelta {
if !strings.HasPrefix(key, KeyPrefixTemp) {
filteredStateDelta[key] = value
}
}
event.Actions.StateDelta = filteredStateDelta
return event
}
Visual Representation
flowchart TD
UserInput[User Input]
CreateOrGetSession[Create or Get Session]
LoadSessionState["Load Session State (App/User/Session)"]
AppendEvent[Append Event to Session]
FilterTempState[Filter Temporary State Keys]
UpdateStateDeltas[Update App, User, Session States]
PersistEvent[Persist Event and State]
ReturnSession[Return Updated Session]
UserInput --> CreateOrGetSession
CreateOrGetSession --> LoadSessionState
LoadSessionState --> AppendEvent
AppendEvent --> FilterTempState
FilterTempState --> UpdateStateDeltas
UpdateStateDeltas --> PersistEvent
PersistEvent --> ReturnSession
This flowchart shows the high-level flow of handling a session event:
A user input triggers creation or retrieval of a session.
The combined session state is loaded from app, user, and session scopes.
The new event is appended, filtering out transient state keys.
State deltas are separated and applied to their respective scopes.
The event and updated states are persisted.
The updated session is returned to the caller.
Session Management is foundational for maintaining continuity in user-agent interactions, providing a robust and extensible infrastructure for managing session lifecycle, persistent state, and event histories across diverse storage backends. For specific implementations of storage backends, see the subtopics: [In-Memory Session Service](/In-Memory Session Service) and [Database Session Service](/Database Session Service).