@memrosetta/core 0.2.20 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.js +80 -14
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ interface MemoryRow {
|
|
|
44
44
|
readonly access_count: number | null;
|
|
45
45
|
readonly last_accessed_at: string | null;
|
|
46
46
|
readonly compressed_from: string | null;
|
|
47
|
+
readonly use_count: number | null;
|
|
48
|
+
readonly success_count: number | null;
|
|
47
49
|
}
|
|
48
50
|
declare function rowToMemory(row: MemoryRow): Memory;
|
|
49
51
|
declare function serializeEmbedding(embedding: readonly number[] | Float32Array): Buffer;
|
|
@@ -242,6 +244,7 @@ declare class SqliteMemoryEngine implements IMemoryEngine {
|
|
|
242
244
|
compress(userId: string): Promise<CompressResult>;
|
|
243
245
|
maintain(userId: string): Promise<MaintenanceResult>;
|
|
244
246
|
setTier(memoryId: string, tier: MemoryTier): Promise<void>;
|
|
247
|
+
feedback(memoryId: string, helpful: boolean): Promise<void>;
|
|
245
248
|
quality(userId: string): Promise<MemoryQuality>;
|
|
246
249
|
/**
|
|
247
250
|
* Check the newly stored memory against existing similar memories
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,9 @@ CREATE TABLE memories (
|
|
|
24
24
|
activation_score REAL DEFAULT 1.0,
|
|
25
25
|
access_count INTEGER DEFAULT 0,
|
|
26
26
|
last_accessed_at TEXT,
|
|
27
|
-
compressed_from TEXT
|
|
27
|
+
compressed_from TEXT,
|
|
28
|
+
use_count INTEGER DEFAULT 0,
|
|
29
|
+
success_count INTEGER DEFAULT 0
|
|
28
30
|
);
|
|
29
31
|
|
|
30
32
|
CREATE INDEX idx_memories_user_id ON memories(user_id);
|
|
@@ -72,6 +74,10 @@ CREATE TRIGGER memories_au AFTER UPDATE ON memories BEGIN
|
|
|
72
74
|
INSERT INTO memories_fts(rowid, content, keywords) VALUES (new.id, new.content, new.keywords);
|
|
73
75
|
END;
|
|
74
76
|
`;
|
|
77
|
+
var SCHEMA_V5 = `
|
|
78
|
+
ALTER TABLE memories ADD COLUMN use_count INTEGER DEFAULT 0;
|
|
79
|
+
ALTER TABLE memories ADD COLUMN success_count INTEGER DEFAULT 0;
|
|
80
|
+
`;
|
|
75
81
|
function schemaV2(dim) {
|
|
76
82
|
return `CREATE VIRTUAL TABLE IF NOT EXISTS vec_memories USING vec0(embedding float[${dim}]);`;
|
|
77
83
|
}
|
|
@@ -106,7 +112,7 @@ function ensureSchema(db, options) {
|
|
|
106
112
|
db.exec(schemaV2(dim));
|
|
107
113
|
version = 2;
|
|
108
114
|
}
|
|
109
|
-
version =
|
|
115
|
+
version = 5;
|
|
110
116
|
db.prepare("INSERT INTO schema_version (version, embedding_dimension) VALUES (?, ?)").run(version, dim);
|
|
111
117
|
return;
|
|
112
118
|
}
|
|
@@ -132,6 +138,12 @@ function ensureSchema(db, options) {
|
|
|
132
138
|
}
|
|
133
139
|
db.prepare("UPDATE schema_version SET version = ?").run(4);
|
|
134
140
|
}
|
|
141
|
+
if (currentVersion < 5) {
|
|
142
|
+
if (currentVersion >= 1) {
|
|
143
|
+
db.exec(SCHEMA_V5);
|
|
144
|
+
}
|
|
145
|
+
db.prepare("UPDATE schema_version SET version = ?").run(5);
|
|
146
|
+
}
|
|
135
147
|
if (options?.vectorEnabled) {
|
|
136
148
|
const hasVecTable = db.prepare(
|
|
137
149
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='vec_memories'"
|
|
@@ -213,7 +225,9 @@ function rowToMemory(row) {
|
|
|
213
225
|
activationScore: row.activation_score ?? 1,
|
|
214
226
|
accessCount: row.access_count ?? 0,
|
|
215
227
|
...row.last_accessed_at != null ? { lastAccessedAt: row.last_accessed_at } : {},
|
|
216
|
-
...row.compressed_from != null ? { compressedFrom: row.compressed_from } : {}
|
|
228
|
+
...row.compressed_from != null ? { compressedFrom: row.compressed_from } : {},
|
|
229
|
+
useCount: row.use_count ?? 0,
|
|
230
|
+
successCount: row.success_count ?? 0
|
|
217
231
|
};
|
|
218
232
|
}
|
|
219
233
|
function deserializeEmbedding(buf) {
|
|
@@ -229,8 +243,8 @@ function serializeEmbedding(embedding) {
|
|
|
229
243
|
function createPreparedStatements(db) {
|
|
230
244
|
return {
|
|
231
245
|
insertMemory: db.prepare(`
|
|
232
|
-
INSERT INTO memories (memory_id, user_id, namespace, memory_type, content, raw_text, document_date, learned_at, source_id, confidence, salience, is_latest, embedding, keywords, event_date_start, event_date_end, invalidated_at, tier, activation_score, access_count, last_accessed_at, compressed_from)
|
|
233
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
246
|
+
INSERT INTO memories (memory_id, user_id, namespace, memory_type, content, raw_text, document_date, learned_at, source_id, confidence, salience, is_latest, embedding, keywords, event_date_start, event_date_end, invalidated_at, tier, activation_score, access_count, last_accessed_at, compressed_from, use_count, success_count)
|
|
247
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
234
248
|
`),
|
|
235
249
|
getById: db.prepare("SELECT * FROM memories WHERE id = ?"),
|
|
236
250
|
getByMemoryId: db.prepare("SELECT * FROM memories WHERE memory_id = ?"),
|
|
@@ -269,8 +283,12 @@ function storeMemory(db, stmts, input) {
|
|
|
269
283
|
// access_count
|
|
270
284
|
null,
|
|
271
285
|
// last_accessed_at
|
|
272
|
-
null
|
|
286
|
+
null,
|
|
273
287
|
// compressed_from
|
|
288
|
+
0,
|
|
289
|
+
// use_count
|
|
290
|
+
0
|
|
291
|
+
// success_count
|
|
274
292
|
);
|
|
275
293
|
const row = stmts.getByMemoryId.get(memoryId);
|
|
276
294
|
return rowToMemory(row);
|
|
@@ -312,8 +330,12 @@ async function storeMemoryAsync(db, stmts, input, embedder) {
|
|
|
312
330
|
// access_count
|
|
313
331
|
null,
|
|
314
332
|
// last_accessed_at
|
|
315
|
-
null
|
|
333
|
+
null,
|
|
316
334
|
// compressed_from
|
|
335
|
+
0,
|
|
336
|
+
// use_count
|
|
337
|
+
0
|
|
338
|
+
// success_count
|
|
317
339
|
);
|
|
318
340
|
if (embeddingVec && info.lastInsertRowid) {
|
|
319
341
|
const rowid = Number(info.lastInsertRowid);
|
|
@@ -379,8 +401,12 @@ async function storeBatchAsync(db, stmts, inputs, embedder) {
|
|
|
379
401
|
// access_count
|
|
380
402
|
null,
|
|
381
403
|
// last_accessed_at
|
|
382
|
-
null
|
|
404
|
+
null,
|
|
383
405
|
// compressed_from
|
|
406
|
+
0,
|
|
407
|
+
// use_count
|
|
408
|
+
0
|
|
409
|
+
// success_count
|
|
384
410
|
);
|
|
385
411
|
if (info.lastInsertRowid) {
|
|
386
412
|
db.prepare("INSERT INTO vec_memories(rowid, embedding) VALUES (CAST(? AS INTEGER), ?)").run(
|
|
@@ -619,7 +645,7 @@ function buildSearchSql(query) {
|
|
|
619
645
|
stateConditions.push("(m.is_latest = 1 AND m.invalidated_at IS NULL)");
|
|
620
646
|
}
|
|
621
647
|
if (filters.states.includes("superseded")) {
|
|
622
|
-
stateConditions.push("(m.is_latest = 0)");
|
|
648
|
+
stateConditions.push("(m.is_latest = 0 AND m.invalidated_at IS NULL)");
|
|
623
649
|
}
|
|
624
650
|
if (filters.states.includes("invalidated")) {
|
|
625
651
|
stateConditions.push("(m.invalidated_at IS NOT NULL)");
|
|
@@ -703,7 +729,7 @@ function bruteForceVectorSearch(db, queryVec, userId, limit, filters) {
|
|
|
703
729
|
stateConditions.push("(is_latest = 1 AND invalidated_at IS NULL)");
|
|
704
730
|
}
|
|
705
731
|
if (filters.states.includes("superseded")) {
|
|
706
|
-
stateConditions.push("(is_latest = 0)");
|
|
732
|
+
stateConditions.push("(is_latest = 0 AND invalidated_at IS NULL)");
|
|
707
733
|
}
|
|
708
734
|
if (filters.states.includes("invalidated")) {
|
|
709
735
|
stateConditions.push("(invalidated_at IS NOT NULL)");
|
|
@@ -791,7 +817,7 @@ function vectorSearch(db, queryVec, userId, limit, filters, useVecTable = true)
|
|
|
791
817
|
stateConditions.push("(is_latest = 1 AND invalidated_at IS NULL)");
|
|
792
818
|
}
|
|
793
819
|
if (filters.states.includes("superseded")) {
|
|
794
|
-
stateConditions.push("(is_latest = 0)");
|
|
820
|
+
stateConditions.push("(is_latest = 0 AND invalidated_at IS NULL)");
|
|
795
821
|
}
|
|
796
822
|
if (filters.states.includes("invalidated")) {
|
|
797
823
|
stateConditions.push("(invalidated_at IS NOT NULL)");
|
|
@@ -1209,10 +1235,22 @@ var SqliteMemoryEngine = class {
|
|
|
1209
1235
|
} else {
|
|
1210
1236
|
memories = storeBatchInTransaction(this.db, this.stmts, inputs);
|
|
1211
1237
|
}
|
|
1212
|
-
if (
|
|
1238
|
+
if (memories.length <= 50) {
|
|
1213
1239
|
for (const memory of memories) {
|
|
1240
|
+
if (this.options.embedder && this.options.contradictionDetector) {
|
|
1241
|
+
try {
|
|
1242
|
+
await this.checkContradictions(memory);
|
|
1243
|
+
} catch {
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (this.options.embedder) {
|
|
1247
|
+
try {
|
|
1248
|
+
await this.checkDuplicates(memory);
|
|
1249
|
+
} catch {
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1214
1252
|
try {
|
|
1215
|
-
await this.
|
|
1253
|
+
await this.autoRelate(memory);
|
|
1216
1254
|
} catch {
|
|
1217
1255
|
}
|
|
1218
1256
|
}
|
|
@@ -1338,6 +1376,7 @@ var SqliteMemoryEngine = class {
|
|
|
1338
1376
|
const coldMemories = db.prepare(`
|
|
1339
1377
|
SELECT * FROM memories
|
|
1340
1378
|
WHERE user_id = ? AND tier = 'cold' AND activation_score < 0.1 AND is_latest = 1
|
|
1379
|
+
AND invalidated_at IS NULL
|
|
1341
1380
|
ORDER BY namespace, learned_at
|
|
1342
1381
|
`).all(userId);
|
|
1343
1382
|
if (coldMemories.length === 0) return { compressed: 0, removed: 0 };
|
|
@@ -1398,8 +1437,12 @@ var SqliteMemoryEngine = class {
|
|
|
1398
1437
|
// access_count
|
|
1399
1438
|
null,
|
|
1400
1439
|
// last_accessed_at
|
|
1401
|
-
rows[0].memory_id
|
|
1440
|
+
rows[0].memory_id,
|
|
1402
1441
|
// compressed_from
|
|
1442
|
+
0,
|
|
1443
|
+
// use_count
|
|
1444
|
+
0
|
|
1445
|
+
// success_count
|
|
1403
1446
|
);
|
|
1404
1447
|
compressed++;
|
|
1405
1448
|
for (const row of rows) {
|
|
@@ -1467,6 +1510,29 @@ var SqliteMemoryEngine = class {
|
|
|
1467
1510
|
this.ensureInitialized();
|
|
1468
1511
|
this.db.prepare("UPDATE memories SET tier = ? WHERE memory_id = ?").run(tier, memoryId);
|
|
1469
1512
|
}
|
|
1513
|
+
async feedback(memoryId, helpful) {
|
|
1514
|
+
this.ensureInitialized();
|
|
1515
|
+
const db = this.db;
|
|
1516
|
+
db.transaction(() => {
|
|
1517
|
+
if (helpful) {
|
|
1518
|
+
db.prepare(
|
|
1519
|
+
"UPDATE memories SET use_count = use_count + 1, success_count = success_count + 1 WHERE memory_id = ?"
|
|
1520
|
+
).run(memoryId);
|
|
1521
|
+
} else {
|
|
1522
|
+
db.prepare(
|
|
1523
|
+
"UPDATE memories SET use_count = use_count + 1 WHERE memory_id = ?"
|
|
1524
|
+
).run(memoryId);
|
|
1525
|
+
}
|
|
1526
|
+
const row = db.prepare(
|
|
1527
|
+
"SELECT salience, use_count, success_count FROM memories WHERE memory_id = ?"
|
|
1528
|
+
).get(memoryId);
|
|
1529
|
+
if (row && row.use_count > 0) {
|
|
1530
|
+
const successRate = row.success_count / row.use_count;
|
|
1531
|
+
const newSalience = Math.min(1, Math.max(0.1, 0.5 + 0.5 * successRate));
|
|
1532
|
+
db.prepare("UPDATE memories SET salience = ? WHERE memory_id = ?").run(newSalience, memoryId);
|
|
1533
|
+
}
|
|
1534
|
+
})();
|
|
1535
|
+
}
|
|
1470
1536
|
async quality(userId) {
|
|
1471
1537
|
this.ensureInitialized();
|
|
1472
1538
|
const db = this.db;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memrosetta/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"better-sqlite3": "^11.0.0",
|
|
21
21
|
"nanoid": "^5.0.0",
|
|
22
22
|
"sqlite-vec": "^0.1.7",
|
|
23
|
-
"@memrosetta/types": "0.2.
|
|
23
|
+
"@memrosetta/types": "0.2.21"
|
|
24
24
|
},
|
|
25
25
|
"optionalDependencies": {
|
|
26
|
-
"@memrosetta/embeddings": "0.2.
|
|
26
|
+
"@memrosetta/embeddings": "0.2.21"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/better-sqlite3": "^7.6.0",
|