import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; import { join } from 'path'; import { Message } from '../types'; import { getMemoryDir } from '../utils/helpers'; import { logger } from '../utils/logger'; /** * Interface for pluggable memory backends */ export interface MemoryInterface { addMessage(message: Message): void; getMessages(): Message[]; clear(): void; getMessageCount(): number; } /** * Default JSON file-based memory storage */ export class Memory implements MemoryInterface { private sessionId: string; private memoryPath: string; private messages: Message[] = []; private maxMessages: number; constructor(sessionId: string, maxMessages = 100) { this.sessionId = sessionId; this.maxMessages = maxMessages; const memoryDir = getMemoryDir(); if (!existsSync(memoryDir)) { mkdirSync(memoryDir, { recursive: true }); } this.memoryPath = join(memoryDir, `${sessionId}.json`); this.load(); } private load(): void { if (existsSync(this.memoryPath)) { try { const data = readFileSync(this.memoryPath, 'utf-8'); const parsed = JSON.parse(data) as Message[]; this.messages = parsed; logger.debug({ sessionId: this.sessionId, count: this.messages.length }, 'Memory loaded'); } catch (error) { logger.error({ error, sessionId: this.sessionId }, 'Failed to load memory'); this.messages = []; } } } private save(): void { try { const data = JSON.stringify(this.messages, null, 2); writeFileSync(this.memoryPath, data, 'utf-8'); logger.debug({ sessionId: this.sessionId, count: this.messages.length }, 'Memory saved'); } catch (error) { logger.error({ error, sessionId: this.sessionId }, 'Failed to save memory'); } } addMessage(message: Message): void { this.messages.push(message); if (this.messages.length > this.maxMessages) { const systemMessages = this.messages.filter((m) => m.role === 'system'); const otherMessages = this.messages .filter((m) => m.role !== 'system') .slice(-this.maxMessages); this.messages = [...systemMessages, ...otherMessages]; } this.save(); } getMessages(): Message[] { return [...this.messages]; } getRecentMessages(count: number): Message[] { return this.messages.slice(-count); } clear(): void { this.messages = []; this.save(); } updateLastMessage(content: string): void { if (this.messages.length > 0) { this.messages[this.messages.length - 1].content = content; this.save(); } } getMessageCount(): number { return this.messages.length; } }