@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 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 = 4;
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 (this.options.contradictionDetector && this.options.embedder && memories.length <= 50) {
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.checkContradictions(memory);
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.20",
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.20"
23
+ "@memrosetta/types": "0.2.21"
24
24
  },
25
25
  "optionalDependencies": {
26
- "@memrosetta/embeddings": "0.2.20"
26
+ "@memrosetta/embeddings": "0.2.21"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/better-sqlite3": "^7.6.0",