UNPKG

contextual-agent-sdk

Version:

SDK for building AI agents with seamless voice-text context switching

194 lines (162 loc) 5.78 kB
import { StorageProvider, StorageConfig, SessionFilter, StorageStats, StorageEvent, StorageEventHandler } from '../types/storage'; import { SessionState } from '../types'; /** * In-memory storage provider for development and testing * DO NOT use in production - sessions are lost on restart */ export class MemoryStorageProvider implements StorageProvider { private sessions: Map<string, SessionState> = new Map(); private readonly eventHandlers: Set<StorageEventHandler> = new Set(); private cleanupTimer?: NodeJS.Timeout; constructor(config?: StorageConfig) { // Start cleanup timer if configured if (config?.cleanupInterval && config?.maxAge) { this.cleanupTimer = setInterval(() => { this.cleanup(config.maxAge!).catch(error => { this.emitEvent({ type: 'error', error }); }); }, config.cleanupInterval); } } async createSession(sessionId: string, session: SessionState): Promise<void> { this.sessions.set(sessionId, { ...session, startTime: new Date(session.startTime), lastActivity: new Date(session.lastActivity) }); this.emitEvent({ type: 'session_created', sessionId }); } async getSession(sessionId: string): Promise<SessionState | null> { const session = this.sessions.get(sessionId); if (!session) return null; return this.cloneSession(session); } async updateSession(sessionId: string, session: SessionState): Promise<void> { this.sessions.set(sessionId, { ...session, startTime: new Date(session.startTime), lastActivity: new Date(session.lastActivity) }); this.emitEvent({ type: 'session_updated', sessionId }); } async deleteSession(sessionId: string): Promise<boolean> { const deleted = this.sessions.delete(sessionId); if (deleted) { this.emitEvent({ type: 'session_deleted', sessionId }); } return deleted; } async getSessions(filter?: SessionFilter): Promise<SessionState[]> { let sessions = Array.from(this.sessions.values()) .map(session => this.cloneSession(session)); if (filter) { sessions = sessions.filter(session => { if (filter.userId && session.userId !== filter.userId) return false; if (filter.modality && session.currentModality !== filter.modality) return false; const startTime = session.startTime.getTime(); if (filter.startTime?.from && startTime < filter.startTime.from.getTime()) return false; if (filter.startTime?.to && startTime > filter.startTime.to.getTime()) return false; const lastActivity = session.lastActivity.getTime(); if (filter.lastActivity?.from && lastActivity < filter.lastActivity.from.getTime()) return false; if (filter.lastActivity?.to && lastActivity > filter.lastActivity.to.getTime()) return false; return true; }); } return sessions; } async deleteSessions(filter?: SessionFilter): Promise<number> { const sessionsToDelete = await this.getSessions(filter); let deleted = 0; for (const session of sessionsToDelete) { const success = await this.deleteSession(session.sessionId); if (success) deleted++; } return deleted; } async cleanup(maxAge: number): Promise<void> { this.emitEvent({ type: 'cleanup_started' }); const now = Date.now(); let deleted = 0; for (const [sessionId, session] of this.sessions.entries()) { const age = now - session.lastActivity.getTime(); if (age > maxAge) { const success = await this.deleteSession(sessionId); if (success) deleted++; } } this.emitEvent({ type: 'cleanup_completed', deletedCount: deleted }); } async healthCheck(): Promise<boolean> { return true; // Memory storage is always healthy } async getStats(): Promise<StorageStats> { const now = Date.now(); const oneDayAgo = now - 24 * 60 * 60 * 1000; const sessions = Array.from(this.sessions.values()); const activeSessions = sessions.filter(s => s.lastActivity.getTime() > oneDayAgo ); const durations = sessions.map(s => s.lastActivity.getTime() - s.startTime.getTime() ); const avgDuration = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0; const modalityCount = sessions.reduce( (acc, s) => { acc[s.currentModality]++; return acc; }, { text: 0, voice: 0 } ); // Estimate storage size const storageSize = sessions.reduce((size, session) => { return size + JSON.stringify(session).length; }, 0); return { totalSessions: sessions.length, activeSessionsLast24h: activeSessions.length, averageSessionDuration: avgDuration, modalityDistribution: modalityCount, storageSize }; } // Event handling public on(handler: StorageEventHandler): void { this.eventHandlers.add(handler); } public off(handler: StorageEventHandler): void { this.eventHandlers.delete(handler); } private emitEvent(event: StorageEvent): void { this.eventHandlers.forEach(handler => handler(event)); } // Helper methods private cloneSession(session: SessionState): SessionState { return { ...session, startTime: new Date(session.startTime), lastActivity: new Date(session.lastActivity), context: { ...session.context, memoryBank: session.context.memoryBank.map(memory => ({ ...memory, timestamp: new Date(memory.timestamp) })) } }; } public async shutdown(): Promise<void> { if (this.cleanupTimer) { clearInterval(this.cleanupTimer); } this.sessions.clear(); } }