/** * In-memory session store for diagram chat sessions. * Stores conversation history and entity snapshots. */ import { v4 as uuidv4 } from 'uuid'; // Session structure: // { // id: string, // diagramId: string, // conversationHistory: Array<{role, content, toolResults?, timestamp}>, // entities: Array<{id, template, text, color, position}>, // createdAt: Date, // lastAccess: Date // } const sessions = new Map(); // Session timeout (1 hour of inactivity) const SESSION_TIMEOUT_MS = 60 * 60 * 1000; /** * Create a new session for a diagram */ export function createSession(diagramId) { const id = uuidv4(); const session = { id, diagramId, conversationHistory: [], entities: [], createdAt: new Date(), lastAccess: new Date() }; sessions.set(id, session); return session; } /** * Get a session by ID */ export function getSession(sessionId) { const session = sessions.get(sessionId); if (session) { session.lastAccess = new Date(); } return session || null; } /** * Find existing session for a diagram */ export function findSessionByDiagram(diagramId) { for (const [, session] of sessions) { if (session.diagramId === diagramId) { session.lastAccess = new Date(); return session; } } return null; } /** * Update entities snapshot for a session */ export function syncEntities(sessionId, entities) { const session = sessions.get(sessionId); if (!session) return null; session.entities = entities; session.lastAccess = new Date(); return session; } /** * Add a message to conversation history */ export function addMessage(sessionId, message) { const session = sessions.get(sessionId); if (!session) return null; session.conversationHistory.push({ ...message, timestamp: new Date() }); session.lastAccess = new Date(); return session; } /** * Get conversation history for API calls (formatted for Claude) */ export function getConversationForAPI(sessionId) { const session = sessions.get(sessionId); if (!session) return []; // Convert to Claude message format return session.conversationHistory.map(msg => ({ role: msg.role, content: msg.content })); } /** * Clear conversation history but keep session */ export function clearHistory(sessionId) { const session = sessions.get(sessionId); if (!session) return null; session.conversationHistory = []; session.lastAccess = new Date(); return session; } /** * Delete a session */ export function deleteSession(sessionId) { return sessions.delete(sessionId); } /** * Clean up expired sessions */ export function cleanupExpiredSessions() { const now = Date.now(); for (const [id, session] of sessions) { if (now - session.lastAccess.getTime() > SESSION_TIMEOUT_MS) { sessions.delete(id); } } } // Run cleanup every 15 minutes setInterval(cleanupExpiredSessions, 15 * 60 * 1000); /** * Get session stats (for debugging) */ export function getStats(includeDetails = false) { return { activeSessions: sessions.size, sessions: Array.from(sessions.values()).map(s => ({ id: s.id, diagramId: s.diagramId, messageCount: s.conversationHistory.length, entityCount: s.entities.length, lastAccess: s.lastAccess, // Include full details if requested ...(includeDetails && { entities: s.entities, conversationHistory: s.conversationHistory }) })) }; }