service.go
Overview
service.go implements the Database Session Service, a persistent, transactional backend for managing user-agent interaction sessions within a relational database. It fulfills the session.Service interface and uses the GORM ORM to connect to SQL databases such as PostgreSQL, Spanner, or SQLite.
This service handles creation, retrieval, listing, deletion, and event appending for sessions with full transactional guarantees. It supports merging and isolating state across three namespaces — application, user, and session — while filtering out transient state keys. The file also manages event histories associated with sessions, ensuring data consistency and concurrency control through timestamp checks.
This database-backed implementation complements the Session Management topic by providing durable session storage suitable for production and scalable deployments.
Main Types and Structures
databaseService
Description: Concrete implementation of
session.Servicebacked by a GORM database connection.Fields:
db *gorm.DB— Database connection handle used for all data operations.
Core Functions and Methods
NewSessionService
func NewSessionService(dialector gorm.Dialector, opts ...gorm.Option) (session.Service, error)
Purpose: Constructs a new
databaseServiceconnected to the specified SQL database.Parameters:
dialector gorm.Dialector— GORM dialector defining the database type and connection details.opts ...gorm.Option— Optional GORM configuration options.
Returns:
session.Service— An instance ofdatabaseServiceimplementing session storage.error— Non-nil if database connection fails.
Usage: Called once during initialization to create the persistent session service.
AutoMigrate
func AutoMigrate(service session.Service) error
Purpose: Runs auto-migration to create or update database schema for session-related tables.
Parameters:
service session.Service— Must be a*databaseServiceinstance.
Returns:
error— If migration fails or incorrect service implementation is passed.
Notes: Relies on type assertion; fails if called on non-database implementations.
(*databaseService) Create
func (s *databaseService) Create(ctx context.Context, req *session.CreateRequest) (*session.CreateResponse, error)
Purpose: Creates a new session in the database, initializing session state and updating app/user states transactionally.
Parameters:
ctx context.Context— Context for cancellation and deadlines.req *session.CreateRequest— ContainsAppName,UserID, optionalSessionID, and initialState.
Returns:
*session.CreateResponsecontaining the created session.error— If required fields are missing or DB operations fail.
Implementation Details:
Generates a new UUID if
SessionIDis not provided.Uses a transaction to:
Fetch or create app and user state records.
Extract and apply state deltas to app, user, and session states.
Save updated states and create the session record.
Merges updated states before returning the session.
Example Usage:
resp, err := dbService.Create(ctx, &session.CreateRequest{
AppName: "myapp",
UserID: "user123",
State: map[string]any{"key": "value"},
})
if err != nil {
// handle error
}
createdSession := resp.Session
(*databaseService) Get
func (s *databaseService) Get(ctx context.Context, req *session.GetRequest) (*session.GetResponse, error)
Purpose: Retrieves a session by composite key (AppName, UserID, SessionID) along with filtered recent events.
Parameters:
ctx context.Contextreq *session.GetRequestwith required keys and optional event filters:After time.Time— fetch events after this timestamp.NumRecentEvents int— limit number of events returned.
Returns:
*session.GetResponsecontaining the session with merged state and event history.errorfor missing keys or DB errors.
Implementation Details:
Queries the session record.
Queries events with optional timestamp filtering and limits, ordered DESC by timestamp.
Fetches app and user states.
Merges states with correct prefixes before returning.
Reverses event order to chronological ASC for client consumption.
Error Handling: Returns system errors for any DB failure.
(*databaseService) List
func (s *databaseService) List(ctx context.Context, req *session.ListRequest) (*session.ListResponse, error)
Purpose: Lists all sessions for a given application, optionally filtering by user ID.
Parameters:
ctx context.Contextreq *session.ListRequestwithAppName(required) and optionalUserID.
Returns:
*session.ListResponsewith a slice of sessions (without event histories).errorfor missingAppNameor DB failure.
Implementation Details:
Queries sessions filtered by
AppNameand optionallyUserID.Fetches app state and user states (all or by user).
Maps storage sessions to session interfaces, merging states.
Note: Returns empty list (not error) if no sessions found.
(*databaseService) Delete
func (s *databaseService) Delete(ctx context.Context, req *session.DeleteRequest) error
Purpose: Deletes a session by composite key (AppName, UserID, SessionID).
Parameters:
ctx context.Contextreq *session.DeleteRequestwith required keys.
Returns:
erroron missing keys or DB failure.
Implementation Details:
Performs deletion inside a transaction for atomicity.
Uses GORM's
Deletemethod filtered by composite key.
(*databaseService) AppendEvent
func (s *databaseService) AppendEvent(ctx context.Context, curSession session.Session, event *session.Event) error
Purpose: Adds a new event to the session, updating state and persisting atomically.
Parameters:
ctx context.ContextcurSession session.Session— Must be a*localSession(internal type).event *session.Event— Event to append.
Returns:
errorif session or event is nil, event partial, or DB transaction fails.
Implementation Details:
Ignores partial events (not persisted).
Strips temporary state keys from event.
Calls internal
applyEventto:Validate session freshness (timestamps).
Fetch and update app/user/session states.
Persist event and update session record.
Appends event to in-memory session representation.
Example Usage:
err := dbService.AppendEvent(ctx, currentSession, newEvent)
if err != nil {
// handle error
}
applyEvent (private)
func (s *databaseService) applyEvent(ctx context.Context, session *localSession, event *session.Event) error
Purpose: Internal helper to apply state deltas from an event and persist changes in a transaction.
Process:
Starts a transaction.
Fetches the latest session record.
Checks for stale session update (rejects if DB session is newer).
Fetches app and user states.
Extracts and applies app, user, and session state deltas.
Creates and saves the event record.
Updates session's update timestamp and state.
Commits transaction or rolls back on error.
Helper Functions
fetchStorageAppState
Fetches or initializes the application-level state record for a given app name.
fetchStorageUserState
Fetches or initializes the user-level state record for a given app and user.
fetchAllAppStorageUserState
Retrieves all user states for a given app, returning a map keyed by user ID.
extractStateDeltas
func extractStateDeltas(delta map[string]any) (appStateDelta, userStateDelta, sessionStateDelta map[string]any)
Purpose: Splits a single state delta map into three separate maps based on key prefixes:
app:prefix keys →appStateDeltauser:prefix keys →userStateDeltaKeys without prefixes (except temporary keys) →
sessionStateDelta
Filtering: Ignores keys starting with the temporary prefix (
temp:).Use Case: Used when applying state updates from session creation or appended events.
mergeStates
func mergeStates(appState, userState, sessionState map[string]any) map[string]any
Purpose: Combines app, user, and session state maps into a single map for client consumption.
Implementation:
Copies sessionState keys as-is.
Prefixes appState keys with
app:.Prefixes userState keys with
user:.
Result: Provides a unified state map with appropriate prefixes to avoid key collisions.
Important Implementation Details and Algorithms
Transactional Integrity: All create, update, append operations are wrapped in GORM transactions to ensure atomicity and prevent partial updates.
Composite Key Usage: Sessions and events are uniquely identified by the tuple
(AppName, UserID, SessionID)for multi-tenant and multi-user safety.State Namespace Separation: State keys are scoped into app, user, and session namespaces using prefixes (
app:,user:, no prefix) and merged on retrieval.Temporary State Filtering: State keys starting with
temp:are considered ephemeral and are excluded from persistence.Stale Session Detection: When appending events, the stored session's last update timestamp is compared to the in-memory session's timestamp to avoid overwriting newer data.
Event Ordering: Events are stored and retrieved ordered by timestamp descending (newest first) but reversed to ascending order for client responses.
Error Handling: Differentiates between not found errors and system errors, returning appropriate responses or empty results.
Interaction with Other System Components
Implements the
session.Serviceinterface defined in the Session Management topic and is used wherever session persistence is required.Provides persistent session storage used by the Agent Execution Runner to maintain conversational context.
Merges with app and user states which may be influenced or queried by other components, such as Artifact Management.
Supports event histories that can be consumed for telemetry, debugging, and conversation playback in Telemetry and Observability.
Works with session state injection and manipulation as explained in related subtopics like Session State Injection.
Visual Diagram
classDiagram
class databaseService {
-db : *gorm.DB
+Create(ctx, req)
+Get(ctx, req)
+List(ctx, req)
+Delete(ctx, req)
+AppendEvent(ctx, session, event)
-applyEvent(ctx, session, event)
}
class storageSession {
+AppName
+UserID
+ID
+State
+UpdateTime
}
class storageEvent {
+AppName
+UserID
+SessionID
+Timestamp
+Actions
+Partial
}
class storageAppState {
+AppName
+State
}
class storageUserState {
+AppName
+UserID
+State
}
databaseService o-- storageSession : uses
databaseService o-- storageEvent : uses
databaseService o-- storageAppState : uses
databaseService o-- storageUserState : uses
This class diagram illustrates the databaseService struct as the core database session service implementation. It interacts with four primary storage models representing sessions, events, application state, and user state. The methods correspond to session lifecycle operations, including event appending and transactional state management.
References
See Session Management for core concepts of sessions and events.
See Agent Execution Runner for integration of session state in agent workflows.
See Artifact Management for related artifact state handling.
Related files defining storage models and session representations: storage_session.go, session.go within the
databasefolder.