Include Luna AI Assistant design docs covering channels, configuration, core architecture, memory, scheduler, and skills. Add reference docs from OpenClaw and ZeroClaw projects, plus Mistral and OpenAI API specs.
6.0 KiB
Session Management
OpenClaw employs a centralized, file-based session management system that handles persistence, lifecycle events, and automated store maintenance. Unlike simple memory-only stores, this system is designed for high-concurrency environments with atomic write guarantees and strict disk budget enforcement.
SessionEntry type
The SessionEntry structure in src/config/sessions/types.ts is the core data model, containing nearly 80 fields that track everything from model overrides to granular token usage and skill snapshots.
export type SessionEntry = {
sessionId: string;
updatedAt: number;
sessionFile?: string;
// Model and Provider Overrides
modelProvider?: string;
model?: string;
providerOverride?: string;
modelOverride?: string;
thinkingLevel?: string;
// Token Tracking and Context
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
totalTokensFresh?: boolean;
compactionCount?: number;
// Delivery and Origin
deliveryContext?: DeliveryContext;
lastChannel?: SessionChannelId;
origin?: SessionOrigin;
// Meta and Snapshots
skillsSnapshot?: SessionSkillSnapshot;
systemPromptReport?: SessionSystemPromptReport;
acp?: SessionAcpMeta; // Agent Control Plane metadata
queueMode?: "steer" | "followup" | "collect" | "queue" | "interrupt";
};
Key features of the type system:
- Model Overrides: Allows per-session binding to specific models or providers, bypassing global defaults.
- Token Intelligence: Tracks
totalTokensFreshto determine if usage displays need a refresh. - ACP Meta: Preserves state for the Agent Control Plane, ensuring persistent agent behaviors across turns.
- Skill Snapshots: Captures the state of available Skills at the time of the session turn.
Store Maintenance
Automated maintenance is handled in src/config/sessions/store-maintenance.ts to prevent unbounded growth of the session file and ensure performance.
Pruning and Capping
pruneStaleEntries(): Removes sessions older than a configured threshold (default: 30 days). It iterates through the store and deletes entries whereupdatedAtis before the cutoff.capEntryCount(): Enforces a maximum number of sessions (default: 500). It sorts sessions byupdatedAtdescending and keeps only the most recentNentries.
File Rotation
The rotateSessionFile() function monitors the sessions.json file size. If it exceeds the limit (default: 10MB), the system:
- Renames the current file to
sessions.json.bak.{timestamp}. - Maintains a maximum of 3 rotation backups, unlinking older ones.
Maintenance Configuration
The resolveMaintenanceConfig() function aggregates parameters from Configuration:
pruneAfterMs: Max age before eviction.maxEntries: Hard limit on session count.rotateBytes: File size trigger for rotation.maxDiskBytes: Total disk budget for session transcripts.
Session Store
The SessionStore in src/config/sessions/store.ts manages the I/O layer with a focus on reliability and cross-platform compatibility.
Key Features
- Atomic Writes: Uses
writeTextAtomicto prevent file corruption during crashes. - Write Locks: Implements a
withSessionStoreLockmechanism using a file-based lock to prevent race conditions between concurrent agent turns. - Normalization: Session keys are case-insensitive and trimmed via
normalizeStoreSessionKey(). Legacy keys are automatically migrated to the normalized format on load. - Windows Retry Semantics: Includes specialized retry logic for Windows to handle transient file locks during the "truncate and write" phase.
- ACP Metadata Preservation: Specifically protects
acpmetadata during updates, ensuring agent state isn't lost if a partial patch is applied.
export async function updateSessionStore<T>(
storePath: string,
mutator: (store: Record<string, SessionEntry>) => Promise<T> | T,
opts?: SaveSessionStoreOptions,
): Promise<T> {
return await withSessionStoreLock(storePath, async () => {
const store = loadSessionStore(storePath, { skipCache: true });
const previousAcpByKey = collectAcpMetadataSnapshot(store);
const result = await mutator(store);
preserveExistingAcpMetadata({
previousAcpByKey,
nextStore: store,
});
await saveSessionStoreUnlocked(storePath, store, opts);
return result;
});
}
Session Lifecycle Events
A lightweight pub/sub system in src/sessions/session-lifecycle-events.ts allows other subsystems to react to session changes.
export type SessionLifecycleEvent = {
sessionKey: string;
reason: string;
parentSessionKey?: string;
label?: string;
};
export function onSessionLifecycleEvent(listener: SessionLifecycleListener): () => void {
SESSION_LIFECYCLE_LISTENERS.add(listener);
return () => { SESSION_LIFECYCLE_LISTENERS.delete(listener); };
}
export function emitSessionLifecycleEvent(event: SessionLifecycleEvent): void {
for (const listener of SESSION_LIFECYCLE_LISTENERS) {
listener(event);
}
}
This system is used to trigger Memory indexing, update Channels status, or log audit trails when sessions are created or deleted.
Relevance to Luna
Luna's current SessionManager is a basic dictionary-backed store that lacks persistence and maintenance. To reach parity with OpenClaw, Luna should adopt several patterns:
- Atomic Persistence: Implement a background saver for Core sessions that uses atomic file swaps to prevent data loss.
- Maintenance Tasks: Add a background service to prune old sessions and cap the total count to prevent memory leaks in the .NET runtime.
- Locking: Use a
SemaphoreSlimor file-system lock for session updates to support concurrent requests from different Channels. - Detailed Metadata: Expand Luna's session objects to include token tracking and model overrides, allowing for better cost management and user customization.
Refer to Core for the current implementation status of Luna's session handling.