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

State Scoping and Persistence

Session state is organized into three layered scopes:

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.

Both implementations strictly adhere to the interface, allowing seamless switching or extension to other storage types.

Functionality and Workflows

Session Creation (Create)

Session Retrieval (Get)

Session Listing (List)

Event Appending (AppendEvent)

State Updates

Concurrency and Thread Safety

Interaction with Other Components

Key Files and Their Roles

File

Role

session/service.go

Defines the Service interface and request/response types for session operations.

session/inmemory.go

Implements the in-memory backend with thread-safe session and state management.

session/database/service.go

Implements the database backend using GORM with transactional session and event logic.

session/database/session.go

Defines internal session representations and state update utilities for the database.

session/database/storage_session.go

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:


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).