UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and

154 lines (153 loc) 5.99 kB
/** * Conversation Memory Manager for NeuroLink * Handles in-memory conversation storage, session management, and context injection */ import { ConversationMemoryError } from "../types/conversationTypes.js"; import { DEFAULT_MAX_TURNS_PER_SESSION, DEFAULT_MAX_SESSIONS, MESSAGES_PER_TURN, } from "../config/conversationMemoryConfig.js"; import { logger } from "../utils/logger.js"; export class ConversationMemoryManager { sessions = new Map(); config; isInitialized = false; constructor(config) { // Trust that config is already complete from applyConversationMemoryDefaults() this.config = config; } /** * Initialize the memory manager */ async initialize() { if (this.isInitialized) { return; } try { this.isInitialized = true; logger.info("ConversationMemoryManager initialized", { storage: "in-memory", maxSessions: this.config.maxSessions, maxTurnsPerSession: this.config.maxTurnsPerSession, }); } catch (error) { throw new ConversationMemoryError("Failed to initialize conversation memory", "CONFIG_ERROR", { error: error instanceof Error ? error.message : String(error) }); } } /** * Store a conversation turn for a session * ULTRA-OPTIMIZED: Direct ChatMessage[] storage with zero conversion overhead */ async storeConversationTurn(sessionId, userId, userMessage, aiResponse) { await this.ensureInitialized(); try { // Get or create session let session = this.sessions.get(sessionId); if (!session) { session = this.createNewSession(sessionId, userId); this.sessions.set(sessionId, session); } // ULTRA-OPTIMIZED: Direct message storage - no intermediate objects session.messages.push({ role: "user", content: userMessage }, { role: "assistant", content: aiResponse }); session.lastActivity = Date.now(); // Enforce per-session turn limit (each turn = MESSAGES_PER_TURN messages: user + assistant) const maxMessages = (this.config.maxTurnsPerSession || DEFAULT_MAX_TURNS_PER_SESSION) * MESSAGES_PER_TURN; if (session.messages.length > maxMessages) { session.messages = session.messages.slice(-maxMessages); } // Enforce global session limit this.enforceSessionLimit(); logger.debug("Conversation turn stored", { sessionId, messageCount: session.messages.length, turnCount: session.messages.length / MESSAGES_PER_TURN, // Each turn = MESSAGES_PER_TURN messages userMessageLength: userMessage.length, aiResponseLength: aiResponse.length, }); } catch (error) { throw new ConversationMemoryError(`Failed to store conversation turn for session ${sessionId}`, "STORAGE_ERROR", { sessionId, error: error instanceof Error ? error.message : String(error), }); } } /** * Build context messages for AI prompt injection (ULTRA-OPTIMIZED) * Returns pre-stored message array with zero conversion overhead */ buildContextMessages(sessionId) { const session = this.sessions.get(sessionId); if (!session || session.messages.length === 0) { return []; } // ULTRA-OPTIMIZED: Direct return - no processing needed! return session.messages; } /** * Get memory statistics (simplified for pure in-memory storage) * ULTRA-OPTIMIZED: Calculate turns from message count (each turn = MESSAGES_PER_TURN messages) */ async getStats() { await this.ensureInitialized(); const sessions = Array.from(this.sessions.values()); const totalTurns = sessions.reduce((sum, session) => sum + session.messages.length / MESSAGES_PER_TURN, 0); return { totalSessions: sessions.length, totalTurns, }; } /** * Clear all conversations for a specific session */ async clearSession(sessionId) { const session = this.sessions.get(sessionId); if (!session) { return false; } // Remove from memory this.sessions.delete(sessionId); logger.info("Session cleared", { sessionId }); return true; } /** * Clear all conversations (reset memory) */ async clearAllSessions() { const sessionIds = Array.from(this.sessions.keys()); // Clear memory this.sessions.clear(); logger.info("All sessions cleared", { clearedCount: sessionIds.length }); } // Private methods async ensureInitialized() { if (!this.isInitialized) { await this.initialize(); } } createNewSession(sessionId, userId) { return { sessionId, userId, messages: [], createdAt: Date.now(), lastActivity: Date.now(), }; } enforceSessionLimit() { const maxSessions = this.config.maxSessions || DEFAULT_MAX_SESSIONS; if (this.sessions.size <= maxSessions) { return; } // Sort sessions by last activity (oldest first) const sessions = Array.from(this.sessions.entries()).sort(([, a], [, b]) => a.lastActivity - b.lastActivity); // Remove oldest sessions const sessionsToRemove = sessions.slice(0, sessions.length - maxSessions); for (const [sessionId] of sessionsToRemove) { this.sessions.delete(sessionId); } logger.debug("Session limit enforced", { removedSessions: sessionsToRemove.length, remainingSessions: this.sessions.size, }); } }