chat-dev / server /memoryStore.js
incognitolm
New Features
15464c7
import crypto from 'crypto';
import path from 'path';
import { loadEncryptedJson, saveEncryptedJson } from './cryptoUtils.js';
const DATA_ROOT = '/data/memories';
const INDEX_FILE = path.join(DATA_ROOT, 'index.json');
const MAX_MEMORY_LENGTH = 220;
const state = {
loaded: false,
index: {
memories: {},
},
};
function ensureOwner(owner) {
if (!owner?.type || !owner?.id) throw new Error('Invalid memory owner');
return owner;
}
function nowIso() {
return new Date().toISOString();
}
function sanitizeText(text) {
return String(text || '').replace(/\s+/g, ' ').trim().slice(0, MAX_MEMORY_LENGTH);
}
async function ensureLoaded() {
if (state.loaded) return;
const stored = await loadEncryptedJson(INDEX_FILE);
state.index = {
memories: stored?.memories || {},
};
state.loaded = true;
}
async function saveIndex() {
await saveEncryptedJson(INDEX_FILE, state.index);
}
function matchesOwner(memory, owner) {
return memory.ownerType === owner.type && memory.ownerId === owner.id;
}
function sanitize(memory) {
return {
id: memory.id,
content: memory.content,
source: memory.source || 'assistant',
sessionId: memory.sessionId || null,
createdAt: memory.createdAt,
updatedAt: memory.updatedAt,
};
}
export const memoryStore = {
async list(owner) {
ensureOwner(owner);
await ensureLoaded();
return Object.values(state.index.memories)
.filter((memory) => matchesOwner(memory, owner))
.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())
.map(sanitize);
},
async create(owner, { content, sessionId = null, source = 'assistant' }) {
ensureOwner(owner);
await ensureLoaded();
const normalized = sanitizeText(content);
if (!normalized) return null;
const memory = {
id: crypto.randomUUID(),
ownerType: owner.type,
ownerId: owner.id,
content: normalized,
sessionId,
source,
createdAt: nowIso(),
updatedAt: nowIso(),
};
state.index.memories[memory.id] = memory;
await saveIndex();
return sanitize(memory);
},
async update(owner, id, content) {
ensureOwner(owner);
await ensureLoaded();
const memory = state.index.memories[id];
if (!memory || !matchesOwner(memory, owner)) return null;
const normalized = sanitizeText(content);
if (!normalized) return null;
memory.content = normalized;
memory.updatedAt = nowIso();
await saveIndex();
return sanitize(memory);
},
async delete(owner, id) {
ensureOwner(owner);
await ensureLoaded();
const memory = state.index.memories[id];
if (!memory || !matchesOwner(memory, owner)) return false;
delete state.index.memories[id];
await saveIndex();
return true;
},
};