-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory.js
More file actions
64 lines (55 loc) · 1.67 KB
/
memory.js
File metadata and controls
64 lines (55 loc) · 1.67 KB
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
import { readFile, writeFile, appendFile, readdir, mkdir } from 'fs/promises';
import { join, basename } from 'path';
import config from './config.js';
const DIR = config.dataDir;
async function ensureDir() {
await mkdir(DIR, { recursive: true });
}
function safe(name) {
return basename(name).replace(/[^a-zA-Z0-9._-]/g, '_');
}
export async function readMemory(file) {
try {
return await readFile(join(DIR, safe(file)), 'utf-8');
} catch {
return null;
}
}
export async function writeMemory(file, content) {
await ensureDir();
await writeFile(join(DIR, safe(file)), content, 'utf-8');
}
// Keep journal files under this character limit (~1.25M tokens).
// When exceeded, trim the oldest ~40% of content.
const MAX_JOURNAL_CHARS = 5_000_000;
export async function appendMemory(file, content) {
await ensureDir();
const filePath = join(DIR, safe(file));
const existing = await readMemory(file);
const sep = existing ? '\n\n' : '';
await appendFile(filePath, sep + content, 'utf-8');
if (file.endsWith('.md')) {
try {
const full = await readFile(filePath, 'utf-8');
if (full.length > MAX_JOURNAL_CHARS) {
const lines = full.split('\n');
const cutAt = Math.floor(lines.length * 0.4);
const trimmed = [
`[journal trimmed — oldest ${cutAt} lines archived at ${new Date().toISOString()}]`,
'',
...lines.slice(cutAt),
].join('\n');
await writeFile(filePath, trimmed, 'utf-8');
}
} catch {}
}
}
export async function listMemories() {
try {
return (await readdir(DIR)).filter(
(f) => f.endsWith('.md') || f.endsWith('.json'),
);
} catch {
return [];
}
}