Database Session Service
Purpose
The Database Session Service provides a robust, persistent implementation of the session management functionality within the broader Session Management topic. Unlike the in-memory alternative, this subtopic addresses the need for durable storage of user-agent interaction sessions by leveraging a SQL database through the GORM ORM library. It ensures session data—including state, event history, and metadata—is reliably saved and retrieved across application restarts and distributed deployments.
This service is specifically designed to handle transactional consistency and concurrent updates to session state, supporting complex multi-turn conversations with durable state persistence. It also manages separate namespaces of state (application-level, per-user, and per-session) with clear transactional boundaries, enabling scalable and consistent session management.
Functionality
Key Features
Transactional Session Creation and Updates: Uses GORM's transaction support to atomically create sessions, update state deltas, and append events while ensuring no stale data overwrites occur.
Composite Primary Keys: Sessions and events are uniquely identified by a composite key of
AppName,UserID, and SessionID, enabling multi-tenant and multi-user isolation.State Namespacing and Merging: State is split into three namespaces:
App State: Global to the application.
User State: Specific to a user within an app.
Session State: Specific to an individual session.
These are merged on retrieval with prefixing (e.g., app:,
user:) to avoid collisions.Event History Persistence: All session events are stored in the database with rich metadata and JSON-encoded fields, supporting event replay, auditing, and debugging.
Stale Session Detection: When applying events, the service detects and rejects stale session updates using timestamp comparisons, ensuring data integrity.
Filtering and Pagination: Supports retrieval of events filtered by timestamp (After) and limited by count (NumRecentEvents), facilitating efficient event history queries.
Core Workflows
Session Creation
When a new session is created, the service:
Generates or uses the provided session ID.
In a transaction, fetches or initializes app and user state records.
Applies any initial state deltas to app and user state.
Creates a new session record with the merged initial state.
Returns a session object with combined namespaces visible.
func (s *databaseService) Create(ctx context.Context, req *session.CreateRequest) (*session.CreateResponse, error) {
// Transactionally create session and update app/user state
err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// fetch app and user states
storageApp, err := fetchStorageAppState(tx, req.AppName)
storageUser, err := fetchStorageUserState(tx, req.AppName, req.UserID)
// extract and apply state deltas
appDelta, userDelta, sessionState := extractStateDeltas(req.State)
maps.Copy(storageApp.State, appDelta)
maps.Copy(storageUser.State, userDelta)
// save app and user states
tx.Save(&storageApp)
tx.Save(&storageUser)
// create session with sessionState
tx.Create(createdSession)
return nil
})
}
Event Appending and State Updates
Appending events involves:
Ignoring partial events (not persisted).
Trimming temporary state keys from event deltas to avoid persisting ephemeral state.
In a transaction:
Fetching the latest session record.
Checking for stale session updates via
UpdateTime.Fetching and updating app, user, and session states with the event's state delta.
Persisting the event as a new record.
Updating the session's update timestamp and state.
Updating the in-memory session object to reflect new state and event history.
func (s *databaseService) AppendEvent(ctx context.Context, curSession session.Session, event *session.Event) error {
if event.Partial {
return nil
}
err := s.applyEvent(ctx, curSession.(*localSession), event)
if err != nil {
return err
}
return curSession.(*localSession).appendEvent(event)
}
Session Retrieval
Fetching a session retrieves:
The session record by composite key.
The filtered list of events, optionally limited and sorted.
The current app and user states.
Merges all states with appropriate prefixes and combines the event list in chronological order.
func (s *databaseService) Get(ctx context.Context, req *session.GetRequest) (*session.GetResponse, error) {
// Query session record
s.db.Where(...).First(&foundSession)
// Query events with filters
s.db.Where(...).Order("timestamp DESC").Limit(...).Find(&storageEvents)
// Fetch app and user state
storageApp, _ := fetchStorageAppState(...)
storageUser, _ := fetchStorageUserState(...)
// Merge states and reorder events
mergedState := mergeStates(storageApp.State, storageUser.State, sessionState)
}
State Delta Extraction and Merging
The service handles state delta maps by splitting keys based on prefixes to isolate app, user, and session state updates, ignoring temporary keys starting with temp:.
Merging re-applies prefixes to app and user state keys when returning the combined state map to clients.
func extractStateDeltas(delta map[string]any) (appDelta, userDelta, sessionDelta map[string]any) {
for key, value := range delta {
if cleanKey, found := strings.CutPrefix(key, session.KeyPrefixApp); found {
appDelta[cleanKey] = value
} else if cleanKey, found := strings.CutPrefix(key, session.KeyPrefixUser); found {
userDelta[cleanKey] = value
} else if !strings.HasPrefix(key, session.KeyPrefixTemp) {
sessionDelta[key] = value
}
}
return
}
func mergeStates(appState, userState, sessionState map[string]any) map[string]any {
merged := make(map[string]any)
maps.Copy(merged, sessionState)
for k, v := range appState {
merged[session.KeyPrefixApp+k] = v
}
for k, v := range userState {
merged[session.KeyPrefixUser+k] = v
}
return merged
}
Integration
The Database Session Service is a concrete implementation of the session management interface defined by the parent Session Management topic. It fits into the architecture as a pluggable backend alongside the in-memory alternative. This allows the system to support both ephemeral session storage (for fast prototyping or testing) and durable persistence (for production scenarios requiring reliability).
It is utilized by the Agent Execution Runner and other components that interact with session state and event history to maintain conversational context. The session data managed here can be augmented by artifacts from Artifact Management and can be accessed or extended by workflow agents in Agent Workflow Management.
The service also supports telemetry and observability through consistent event recording, enabling tracing of session state changes over time as seen in Telemetry and Observability.
Diagram
sequenceDiagram
participant Client
participant DBService as DatabaseSessionService
participant DB as SQL Database
Client->>DBService: CreateSession(request)
DBService->>DB: Begin Transaction
DBService->>DB: Fetch or Init AppState, UserState
DBService->>DB: Apply Initial State Deltas
DBService->>DB: Save AppState, UserState, Session
DBService->>DB: Commit Transaction
DBService->>Client: Return Created Session
Client->>DBService: AppendEvent(session, event)
DBService->>DB: Begin Transaction
DBService->>DB: Fetch Session Record
DBService->>DB: Check for Stale Session
DBService->>DB: Fetch AppState, UserState
DBService->>DB: Apply Event State Deltas
DBService->>DB: Save Event Record
DBService->>DB: Update Session Timestamp and State
DBService->>DB: Commit Transaction
DBService->>Client: Acknowledge Event Append
Client->>DBService: GetSession(sessionKey, filters)
DBService->>DB: Query Session Record
DBService->>DB: Query Events (with filters)
DBService->>DB: Fetch AppState, UserState
DBService->>DBService: Merge States with Prefixes
DBService->>Client: Return Session with Events and Merged State
This sequence diagram visualizes the core transactional workflows of the Database Session Service, highlighting the interaction between client calls, the service logic, and the underlying SQL database operations. It captures how session creation, event appending, and session retrieval are handled atomically to maintain data consistency and integrity.