agent-working-memory 0.5.6 → 0.6.0

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.
Files changed (54) hide show
  1. package/README.md +73 -44
  2. package/dist/api/routes.d.ts.map +1 -1
  3. package/dist/api/routes.js +40 -1
  4. package/dist/api/routes.js.map +1 -1
  5. package/dist/cli.js +401 -1
  6. package/dist/cli.js.map +1 -1
  7. package/dist/coordination/mcp-tools.d.ts.map +1 -1
  8. package/dist/coordination/mcp-tools.js +10 -5
  9. package/dist/coordination/mcp-tools.js.map +1 -1
  10. package/dist/coordination/routes.d.ts.map +1 -1
  11. package/dist/coordination/routes.js +155 -16
  12. package/dist/coordination/routes.js.map +1 -1
  13. package/dist/coordination/schema.d.ts.map +1 -1
  14. package/dist/coordination/schema.js +35 -1
  15. package/dist/coordination/schema.js.map +1 -1
  16. package/dist/coordination/schemas.d.ts +21 -2
  17. package/dist/coordination/schemas.d.ts.map +1 -1
  18. package/dist/coordination/schemas.js +16 -0
  19. package/dist/coordination/schemas.js.map +1 -1
  20. package/dist/coordination/stale.d.ts +2 -0
  21. package/dist/coordination/stale.d.ts.map +1 -1
  22. package/dist/coordination/stale.js +5 -0
  23. package/dist/coordination/stale.js.map +1 -1
  24. package/dist/engine/activation.d.ts.map +1 -1
  25. package/dist/engine/activation.js +119 -23
  26. package/dist/engine/activation.js.map +1 -1
  27. package/dist/engine/consolidation.d.ts.map +1 -1
  28. package/dist/engine/consolidation.js +27 -6
  29. package/dist/engine/consolidation.js.map +1 -1
  30. package/dist/index.js +81 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/mcp.js +61 -3
  33. package/dist/mcp.js.map +1 -1
  34. package/dist/storage/sqlite.d.ts +18 -0
  35. package/dist/storage/sqlite.d.ts.map +1 -1
  36. package/dist/storage/sqlite.js +50 -5
  37. package/dist/storage/sqlite.js.map +1 -1
  38. package/dist/types/engram.d.ts +24 -0
  39. package/dist/types/engram.d.ts.map +1 -1
  40. package/dist/types/engram.js.map +1 -1
  41. package/package.json +3 -1
  42. package/src/api/routes.ts +50 -1
  43. package/src/cli.ts +454 -1
  44. package/src/coordination/mcp-tools.ts +10 -5
  45. package/src/coordination/routes.ts +209 -19
  46. package/src/coordination/schema.ts +27 -1
  47. package/src/coordination/schemas.ts +19 -0
  48. package/src/coordination/stale.ts +8 -0
  49. package/src/engine/activation.ts +125 -23
  50. package/src/engine/consolidation.ts +29 -6
  51. package/src/index.ts +74 -3
  52. package/src/mcp.ts +72 -3
  53. package/src/storage/sqlite.ts +54 -5
  54. package/src/types/engram.ts +28 -0
@@ -12,7 +12,7 @@ import { randomUUID } from 'node:crypto';
12
12
  import type {
13
13
  Engram, EngramCreate, EngramStage, Association, AssociationType,
14
14
  SearchQuery, SalienceFeatures, ActivationEvent, StagingEvent,
15
- RetrievalFeedbackEvent, Episode, TaskStatus, TaskPriority, MemoryClass,
15
+ RetrievalFeedbackEvent, Episode, TaskStatus, TaskPriority, MemoryClass, MemoryType,
16
16
  ConsciousState, AutoCheckpoint, CheckpointRow,
17
17
  } from '../types/index.js';
18
18
 
@@ -35,6 +35,8 @@ export class EngramStore {
35
35
  this.db = new Database(dbPath);
36
36
  this.db.pragma('journal_mode = WAL');
37
37
  this.db.pragma('foreign_keys = ON');
38
+ this.db.pragma('busy_timeout = 5000');
39
+ this.db.pragma('synchronous = NORMAL');
38
40
  this.init();
39
41
  }
40
42
 
@@ -43,6 +45,27 @@ export class EngramStore {
43
45
  return this.db;
44
46
  }
45
47
 
48
+ /** Run PRAGMA quick_check and return true if DB is healthy. */
49
+ integrityCheck(): { ok: boolean; result: string } {
50
+ try {
51
+ const rows = this.db.pragma('quick_check') as Array<{ quick_check: string }>;
52
+ const result = rows[0]?.quick_check ?? 'unknown';
53
+ return { ok: result === 'ok', result };
54
+ } catch (err) {
55
+ return { ok: false, result: (err as Error).message };
56
+ }
57
+ }
58
+
59
+ /** Hot backup using SQLite backup API. Returns the backup path. */
60
+ backup(destPath: string): void {
61
+ this.db.backup(destPath);
62
+ }
63
+
64
+ /** Flush WAL to main database file. */
65
+ walCheckpoint(): void {
66
+ this.db.pragma('wal_checkpoint(TRUNCATE)');
67
+ }
68
+
46
69
  private init(): void {
47
70
  this.db.exec(`
48
71
  CREATE TABLE IF NOT EXISTS engrams (
@@ -63,7 +86,8 @@ export class EngramStore {
63
86
  retracted INTEGER NOT NULL DEFAULT 0,
64
87
  retracted_by TEXT,
65
88
  retracted_at TEXT,
66
- tags TEXT NOT NULL DEFAULT '[]'
89
+ tags TEXT NOT NULL DEFAULT '[]',
90
+ memory_type TEXT NOT NULL DEFAULT 'unclassified'
67
91
  );
68
92
 
69
93
  CREATE INDEX IF NOT EXISTS idx_engrams_agent ON engrams(agent_id);
@@ -211,6 +235,13 @@ export class EngramStore {
211
235
  try {
212
236
  this.db.exec(`ALTER TABLE conscious_state ADD COLUMN consolidation_cycle_count INTEGER NOT NULL DEFAULT 0`);
213
237
  } catch { /* column already exists */ }
238
+
239
+ // Migration: add memory_type column if missing
240
+ try {
241
+ this.db.prepare('SELECT memory_type FROM engrams LIMIT 0').get();
242
+ } catch {
243
+ this.db.exec(`ALTER TABLE engrams ADD COLUMN memory_type TEXT NOT NULL DEFAULT 'unclassified'`);
244
+ }
214
245
  }
215
246
 
216
247
  // --- Engram CRUD ---
@@ -225,8 +256,8 @@ export class EngramStore {
225
256
  this.db.prepare(`
226
257
  INSERT INTO engrams (id, agent_id, concept, content, embedding, confidence, salience,
227
258
  access_count, last_accessed, created_at, salience_features, reason_codes, stage, tags, episode_id,
228
- ttl, memory_class, supersedes, task_status, task_priority, blocked_by)
229
- VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?)
259
+ ttl, memory_class, supersedes, task_status, task_priority, blocked_by, memory_type)
260
+ VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?, ?)
230
261
  `).run(
231
262
  id, input.agentId, input.concept, input.content, embeddingBlob,
232
263
  input.confidence ?? 0.5,
@@ -242,6 +273,7 @@ export class EngramStore {
242
273
  input.taskStatus ?? null,
243
274
  input.taskPriority ?? null,
244
275
  input.blockedBy ?? null,
276
+ input.memoryType ?? 'unclassified',
245
277
  );
246
278
 
247
279
  return this.getEngram(id)!;
@@ -267,9 +299,21 @@ export class EngramStore {
267
299
  return (this.db.prepare(query).all(...params) as any[]).map(r => this.rowToEngram(r));
268
300
  }
269
301
 
302
+ /**
303
+ * Touch an engram: increment access count, update last_accessed, and
304
+ * nudge confidence upward. Each retrieval is weak evidence the memory
305
+ * is useful — bounded so only explicit feedback can push confidence
306
+ * above 0.85. Diminishing returns: first accesses matter most.
307
+ *
308
+ * Boost: +0.02 per access, scaled by 1/sqrt(accessCount+1), capped at 0.85.
309
+ */
270
310
  touchEngram(id: string): void {
271
311
  this.db.prepare(`
272
- UPDATE engrams SET access_count = access_count + 1, last_accessed = ? WHERE id = ?
312
+ UPDATE engrams
313
+ SET access_count = access_count + 1,
314
+ last_accessed = ?,
315
+ confidence = MIN(0.85, confidence + 0.02 / (1.0 + sqrt(access_count)))
316
+ WHERE id = ?
273
317
  `).run(new Date().toISOString(), id);
274
318
  }
275
319
 
@@ -502,6 +546,10 @@ export class EngramStore {
502
546
  this.db.prepare('UPDATE engrams SET memory_class = ? WHERE id = ?').run(memoryClass, id);
503
547
  }
504
548
 
549
+ updateTags(id: string, tags: string[]): void {
550
+ this.db.prepare('UPDATE engrams SET tags = ? WHERE id = ?').run(JSON.stringify(tags), id);
551
+ }
552
+
505
553
  // --- Associations ---
506
554
 
507
555
  upsertAssociation(
@@ -722,6 +770,7 @@ export class EngramStore {
722
770
  tags: JSON.parse(row.tags),
723
771
  episodeId: row.episode_id ?? null,
724
772
  memoryClass: (row.memory_class ?? 'working') as MemoryClass,
773
+ memoryType: (row.memory_type ?? 'unclassified') as MemoryType,
725
774
  supersededBy: row.superseded_by ?? null,
726
775
  supersedes: row.supersedes ?? null,
727
776
  taskStatus: row.task_status ?? null,
@@ -43,6 +43,9 @@ export interface Engram {
43
43
  // Memory class
44
44
  memoryClass: MemoryClass;
45
45
 
46
+ // Memory type (content classification)
47
+ memoryType: MemoryType;
48
+
46
49
  // Supersession — "this replaces that" (not retraction — original wasn't wrong, just outdated)
47
50
  supersededBy: string | null; // ID of the engram that replaced this one
48
51
  supersedes: string | null; // ID of the engram this one replaces
@@ -70,6 +73,16 @@ export type TaskPriority = 'urgent' | 'high' | 'medium' | 'low';
70
73
  */
71
74
  export type MemoryClass = 'canonical' | 'working' | 'ephemeral';
72
75
 
76
+ /**
77
+ * Memory type — content classification for retrieval routing.
78
+ *
79
+ * episodic: Events, incidents, debugging sessions ("we did X because Y").
80
+ * semantic: Facts, decisions, patterns ("X is true", "we use Y for Z").
81
+ * procedural: How-to, steps, processes ("to deploy, run X then Y").
82
+ * unclassified: Default for backwards compatibility.
83
+ */
84
+ export type MemoryType = 'episodic' | 'semantic' | 'procedural' | 'unclassified';
85
+
73
86
  /**
74
87
  * Raw feature scores that produced the salience score.
75
88
  * Persisted for auditability and tuning.
@@ -95,6 +108,7 @@ export interface EngramCreate {
95
108
  episodeId?: string;
96
109
  ttl?: number;
97
110
  memoryClass?: MemoryClass;
111
+ memoryType?: MemoryType;
98
112
  supersedes?: string;
99
113
  taskStatus?: TaskStatus;
100
114
  taskPriority?: TaskPriority;
@@ -147,6 +161,18 @@ export interface PhaseScores {
147
161
  rerankerScore: number; // Cross-encoder relevance (0-1), 0 if reranker disabled
148
162
  }
149
163
 
164
+ /**
165
+ * Query mode — controls how the activation pipeline weights its signals.
166
+ *
167
+ * targeted: Query has identifiers, ticket IDs, specific names. Boost BM25,
168
+ * narrow graph beam, stronger decay, stricter vector z-gate.
169
+ * exploratory: Vague/conceptual query. Boost vector/semantic signals, wider
170
+ * graph beam, weaker decay, relaxed z-gate.
171
+ * balanced: Default weights (current behavior).
172
+ * auto: Classify automatically based on query characteristics.
173
+ */
174
+ export type QueryMode = 'targeted' | 'exploratory' | 'balanced' | 'auto';
175
+
150
176
  export interface ActivationQuery {
151
177
  agentId: string;
152
178
  context: string;
@@ -158,6 +184,8 @@ export interface ActivationQuery {
158
184
  useExpansion?: boolean; // Enable query expansion (default: true)
159
185
  abstentionThreshold?: number; // Min reranker score to return results (default: 0)
160
186
  internal?: boolean; // Skip access count increment, Hebbian update, and event logging (for system calls)
187
+ memoryType?: MemoryType; // Filter by memory type (episodic, semantic, procedural)
188
+ mode?: QueryMode; // Pipeline mode — 'auto' by default
161
189
  }
162
190
 
163
191
  /**