// Conversation memory handler for DubAPI bot class MemoryHandler { constructor(options = {}) { // Maximum number of messages to remember per user this.maxMessagesPerUser = options.maxMessagesPerUser || 50; // Maximum age of messages to keep (in milliseconds) this.maxMemoryAge = options.maxMemoryAge || 30 * 60 * 1000; // Default: 30 minutes // Memory storage: Map of username -> array of message objects this.memories = new Map(); console.log(`Memory handler initialized (max ${this.maxMessagesPerUser} messages per user, ${this.maxMemoryAge/60000} minutes retention)`); // Set up periodic cleanup this.startCleanupInterval(); } /** * Add a message to a user's conversation history * @param {string} username - The username of the person speaking * @param {string} message - The message content * @param {boolean} isBot - Whether this message was from the bot */ addMessage(username, message, isBot = false) { // Normalize username to lowercase for consistent lookups const normalizedUsername = username.toLowerCase(); // Get or create user's memory array if (!this.memories.has(normalizedUsername)) { this.memories.set(normalizedUsername, []); } const userMemory = this.memories.get(normalizedUsername); // Add new message with timestamp userMemory.push({ timestamp: Date.now(), message: message, isBot: isBot }); // Trim to max size if needed if (userMemory.length > this.maxMessagesPerUser) { userMemory.shift(); // Remove oldest message } } /** * Get conversation history for a user * @param {string} username - The username to get history for * @param {number} limit - Maximum number of messages to retrieve (defaults to all) * @returns {Array} - Array of conversation messages */ getConversationHistory(username, limit = null) { const normalizedUsername = username.toLowerCase(); if (!this.memories.has(normalizedUsername)) { return []; } const userMemory = this.memories.get(normalizedUsername); const result = limit ? userMemory.slice(-limit) : userMemory; return result; } /** * Format conversation history for use in AI prompt * @param {string} username - The username to get history for * @param {number} limit - Maximum number of messages to include * @returns {string} - Formatted conversation history */ getFormattedHistory(username, limit = 5) { const history = this.getConversationHistory(username, limit); if (history.length === 0) { return ""; } let formatted = "Previous conversation:\n"; history.forEach(item => { const speaker = item.isBot ? "Bot" : username; formatted += `${speaker}: ${item.message}\n`; }); return formatted; } /** * Remove old messages from memory that exceed the age limit */ cleanupOldMessages() { const now = Date.now(); const cutoffTime = now - this.maxMemoryAge; // Check each user's memory for (const [username, messages] of this.memories.entries()) { // Filter out old messages const freshMessages = messages.filter(msg => msg.timestamp >= cutoffTime); if (freshMessages.length === 0) { // Remove empty memory arrays this.memories.delete(username); } else if (freshMessages.length < messages.length) { // Update with only fresh messages this.memories.set(username, freshMessages); } } } /** * Start automatic cleanup interval */ startCleanupInterval() { // Run cleanup every 5 minutes setInterval(() => { this.cleanupOldMessages(); }, 5 * 60 * 1000); } /** * Get stats about the memory system * @returns {Object} - Stats about memory usage */ getStats() { return { userCount: this.memories.size, totalMessages: Array.from(this.memories.values()) .reduce((total, messages) => total + messages.length, 0), oldestMessage: this.getOldestMessageTime() }; } /** * Get the timestamp of the oldest message in memory * @returns {number|null} - Timestamp or null if no messages */ getOldestMessageTime() { let oldest = null; for (const messages of this.memories.values()) { for (const msg of messages) { if (oldest === null || msg.timestamp < oldest) { oldest = msg.timestamp; } } } return oldest; } } module.exports = MemoryHandler;