File size: 4,896 Bytes
e706de2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import fs from 'fs/promises';
import path from 'path';
import {fileURLToPath} from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

export class MemoryManager {
    constructor(memoryFileName = './memory.json') {
        this.memoryFilePath = path.resolve(__dirname, memoryFileName);
    }

    async loadMemories() {
        try {
            const data = await fs.readFile(this.memoryFilePath, 'utf-8');
            const json = JSON.parse(data);

            // 🔧 Migrate old schema if needed
            if (!json.memories) {
                const upgraded = {memories: [], conversationHistory: []};

                if (Array.isArray(json.facts)) {
                    for (const f of json.facts) {
                        upgraded.memories.push({
                            type: 'fact',
                            key: this.extractKey(f.content),
                            value: this.extractValue(f.content),
                            source: 'migration',
                            timestamp: f.timestamp || new Date().toISOString()
                        });
                    }
                }

                if (json.preferences && typeof json.preferences === 'object') {
                    for (const [key, val] of Object.entries(json.preferences)) {
                        upgraded.memories.push({
                            type: 'preference',
                            key,
                            value: this.extractValue(val),
                            source: 'migration',
                            timestamp: new Date().toISOString()
                        });
                    }
                }

                await this.saveMemories(upgraded);
                return upgraded;
            }

            if (!Array.isArray(json.memories)) json.memories = [];
            if (!Array.isArray(json.conversationHistory)) json.conversationHistory = [];

            return json;
        } catch {
            return {memories: [], conversationHistory: []};
        }
    }

    async saveMemories(memories) {
        await fs.writeFile(this.memoryFilePath, JSON.stringify(memories, null, 2));
    }

    // Add or update memory without duplicates
    async addMemory({type, key, value, source = 'user'}) {
        const data = await this.loadMemories();

        // Normalize for comparison
        const normType = type.trim().toLowerCase();
        const normKey = key.trim().toLowerCase();
        const normValue = value.trim();

        // Check if same key+type already exists
        const existingIndex = data.memories.findIndex(
            m => m.type === normType && m.key.toLowerCase() === normKey
        );

        if (existingIndex >= 0) {
            const existing = data.memories[existingIndex];
            // Update value if changed
            if (existing.value !== normValue) {
                existing.value = normValue;
                existing.timestamp = new Date().toISOString();
                existing.source = source;
                console.log(`Updated memory: ${normKey}${normValue}`);
            } else {
                console.log(`Skipped duplicate memory: ${normKey}`);
            }
        } else {
            // Add new memory
            data.memories.push({
                type: normType,
                key: normKey,
                value: normValue,
                source,
                timestamp: new Date().toISOString()
            });
            console.log(`Added memory: ${normKey} = ${normValue}`);
        }

        await this.saveMemories(data);
    }

    async getMemorySummary() {
        const data = await this.loadMemories();
        const facts = Array.isArray(data.memories)
            ? data.memories.filter(m => m.type === 'fact')
            : [];
        const prefs = Array.isArray(data.memories)
            ? data.memories.filter(m => m.type === 'preference')
            : [];

        let summary = "\n=== LONG-TERM MEMORY ===\n";

        if (facts.length > 0) {
            summary += "\nKnown Facts:\n";
            for (const f of facts) summary += `- ${f.key}: ${f.value}\n`;
        }

        if (prefs.length > 0) {
            summary += "\nUser Preferences:\n";
            for (const p of prefs) summary += `- ${p.key}: ${p.value}\n`;
        }

        return summary;
    }

    extractKey(content) {
        if (typeof content !== 'string') return 'unknown';
        const [key] = content.split(':').map(s => s.trim());
        return key || 'unknown';
    }

    extractValue(content) {
        if (typeof content !== 'string') return '';
        const parts = content.split(':').map(s => s.trim());
        return parts.length > 1 ? parts.slice(1).join(':') : content;
    }
}