agent-working-memory 0.4.2 → 0.5.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 (127) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +21 -3
  3. package/dist/api/index.d.ts.map +1 -1
  4. package/dist/api/index.js +2 -0
  5. package/dist/api/index.js.map +1 -1
  6. package/dist/api/routes.d.ts.map +1 -1
  7. package/dist/api/routes.js +7 -0
  8. package/dist/api/routes.js.map +1 -1
  9. package/dist/cli.d.ts +0 -9
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +69 -67
  12. package/dist/cli.js.map +1 -1
  13. package/dist/core/decay.d.ts.map +1 -1
  14. package/dist/core/decay.js +2 -0
  15. package/dist/core/decay.js.map +1 -1
  16. package/dist/core/embeddings.d.ts.map +1 -1
  17. package/dist/core/embeddings.js +2 -0
  18. package/dist/core/embeddings.js.map +1 -1
  19. package/dist/core/hebbian.d.ts.map +1 -1
  20. package/dist/core/hebbian.js +2 -0
  21. package/dist/core/hebbian.js.map +1 -1
  22. package/dist/core/index.d.ts.map +1 -1
  23. package/dist/core/index.js +2 -0
  24. package/dist/core/index.js.map +1 -1
  25. package/dist/core/logger.d.ts.map +1 -1
  26. package/dist/core/logger.js +2 -0
  27. package/dist/core/logger.js.map +1 -1
  28. package/dist/core/query-expander.d.ts.map +1 -1
  29. package/dist/core/query-expander.js +2 -0
  30. package/dist/core/query-expander.js.map +1 -1
  31. package/dist/core/reranker.d.ts.map +1 -1
  32. package/dist/core/reranker.js +2 -0
  33. package/dist/core/reranker.js.map +1 -1
  34. package/dist/core/salience.d.ts +3 -1
  35. package/dist/core/salience.d.ts.map +1 -1
  36. package/dist/core/salience.js +29 -10
  37. package/dist/core/salience.js.map +1 -1
  38. package/dist/engine/activation.d.ts.map +1 -1
  39. package/dist/engine/activation.js +9 -0
  40. package/dist/engine/activation.js.map +1 -1
  41. package/dist/engine/connections.d.ts.map +1 -1
  42. package/dist/engine/connections.js +2 -0
  43. package/dist/engine/connections.js.map +1 -1
  44. package/dist/engine/consolidation-scheduler.d.ts.map +1 -1
  45. package/dist/engine/consolidation-scheduler.js +2 -0
  46. package/dist/engine/consolidation-scheduler.js.map +1 -1
  47. package/dist/engine/consolidation.d.ts.map +1 -1
  48. package/dist/engine/consolidation.js +5 -3
  49. package/dist/engine/consolidation.js.map +1 -1
  50. package/dist/engine/eval.d.ts.map +1 -1
  51. package/dist/engine/eval.js +2 -0
  52. package/dist/engine/eval.js.map +1 -1
  53. package/dist/engine/eviction.d.ts.map +1 -1
  54. package/dist/engine/eviction.js +2 -0
  55. package/dist/engine/eviction.js.map +1 -1
  56. package/dist/engine/index.d.ts.map +1 -1
  57. package/dist/engine/index.js +2 -0
  58. package/dist/engine/index.js.map +1 -1
  59. package/dist/engine/retraction.d.ts.map +1 -1
  60. package/dist/engine/retraction.js +2 -0
  61. package/dist/engine/retraction.js.map +1 -1
  62. package/dist/engine/staging.d.ts.map +1 -1
  63. package/dist/engine/staging.js +2 -0
  64. package/dist/engine/staging.js.map +1 -1
  65. package/dist/hooks/sidecar.d.ts.map +1 -1
  66. package/dist/hooks/sidecar.js +2 -0
  67. package/dist/hooks/sidecar.js.map +1 -1
  68. package/dist/index.js +2 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/mcp.d.ts +2 -1
  71. package/dist/mcp.d.ts.map +1 -1
  72. package/dist/mcp.js +69 -3
  73. package/dist/mcp.js.map +1 -1
  74. package/dist/storage/index.d.ts.map +1 -1
  75. package/dist/storage/index.js +2 -0
  76. package/dist/storage/index.js.map +1 -1
  77. package/dist/storage/sqlite.d.ts +12 -1
  78. package/dist/storage/sqlite.d.ts.map +1 -1
  79. package/dist/storage/sqlite.js +52 -5
  80. package/dist/storage/sqlite.js.map +1 -1
  81. package/dist/types/agent.d.ts.map +1 -1
  82. package/dist/types/agent.js +2 -0
  83. package/dist/types/agent.js.map +1 -1
  84. package/dist/types/checkpoint.d.ts.map +1 -1
  85. package/dist/types/checkpoint.js +2 -0
  86. package/dist/types/checkpoint.js.map +1 -1
  87. package/dist/types/engram.d.ts +16 -0
  88. package/dist/types/engram.d.ts.map +1 -1
  89. package/dist/types/engram.js +2 -0
  90. package/dist/types/engram.js.map +1 -1
  91. package/dist/types/eval.d.ts.map +1 -1
  92. package/dist/types/eval.js +2 -0
  93. package/dist/types/eval.js.map +1 -1
  94. package/dist/types/index.d.ts.map +1 -1
  95. package/dist/types/index.js +2 -0
  96. package/dist/types/index.js.map +1 -1
  97. package/package.json +2 -2
  98. package/src/api/index.ts +2 -0
  99. package/src/api/routes.ts +8 -0
  100. package/src/cli.ts +385 -383
  101. package/src/core/decay.ts +2 -0
  102. package/src/core/embeddings.ts +2 -0
  103. package/src/core/hebbian.ts +2 -0
  104. package/src/core/index.ts +2 -0
  105. package/src/core/logger.ts +2 -0
  106. package/src/core/query-expander.ts +2 -0
  107. package/src/core/reranker.ts +2 -0
  108. package/src/core/salience.ts +34 -13
  109. package/src/engine/activation.ts +10 -0
  110. package/src/engine/connections.ts +2 -0
  111. package/src/engine/consolidation-scheduler.ts +125 -123
  112. package/src/engine/consolidation.ts +5 -3
  113. package/src/engine/eval.ts +2 -0
  114. package/src/engine/eviction.ts +2 -0
  115. package/src/engine/index.ts +2 -0
  116. package/src/engine/retraction.ts +2 -0
  117. package/src/engine/staging.ts +2 -0
  118. package/src/hooks/sidecar.ts +2 -0
  119. package/src/index.ts +2 -0
  120. package/src/mcp.ts +82 -3
  121. package/src/storage/index.ts +2 -0
  122. package/src/storage/sqlite.ts +61 -5
  123. package/src/types/agent.ts +2 -0
  124. package/src/types/checkpoint.ts +46 -44
  125. package/src/types/engram.ts +23 -0
  126. package/src/types/eval.ts +2 -0
  127. package/src/types/index.ts +2 -0
@@ -1,3 +1,5 @@
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
1
3
  /**
2
4
  * SQLite storage layer — persistence for engrams, associations, and eval events.
3
5
  *
@@ -10,10 +12,18 @@ import { randomUUID } from 'node:crypto';
10
12
  import type {
11
13
  Engram, EngramCreate, EngramStage, Association, AssociationType,
12
14
  SearchQuery, SalienceFeatures, ActivationEvent, StagingEvent,
13
- RetrievalFeedbackEvent, Episode, TaskStatus, TaskPriority,
15
+ RetrievalFeedbackEvent, Episode, TaskStatus, TaskPriority, MemoryClass,
14
16
  ConsciousState, AutoCheckpoint, CheckpointRow,
15
17
  } from '../types/index.js';
16
18
 
19
+ /** Safely convert a Node Buffer to Float32Array, respecting byteOffset/byteLength. */
20
+ function bufferToFloat32Array(buf: Buffer | ArrayBuffer): Float32Array {
21
+ if (buf instanceof ArrayBuffer) return new Float32Array(buf);
22
+ // Node Buffer may share an underlying ArrayBuffer — slice to the exact region
23
+ const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
24
+ return new Float32Array(ab);
25
+ }
26
+
17
27
  const DEFAULT_SALIENCE_FEATURES: SalienceFeatures = {
18
28
  surprise: 0, decisionMade: false, causalDepth: 0, resolutionEffort: 0, eventType: 'observation',
19
29
  };
@@ -162,6 +172,17 @@ export class EngramStore {
162
172
  this.db.exec('CREATE INDEX IF NOT EXISTS idx_engrams_task ON engrams(agent_id, task_status)');
163
173
  }
164
174
 
175
+ // Migration: add memory_class and supersession columns if missing
176
+ try {
177
+ this.db.prepare('SELECT memory_class FROM engrams LIMIT 0').get();
178
+ } catch {
179
+ this.db.exec(`
180
+ ALTER TABLE engrams ADD COLUMN memory_class TEXT NOT NULL DEFAULT 'working';
181
+ ALTER TABLE engrams ADD COLUMN superseded_by TEXT;
182
+ ALTER TABLE engrams ADD COLUMN supersedes TEXT;
183
+ `);
184
+ }
185
+
165
186
  // Migration: add conscious_state table for checkpointing
166
187
  this.db.exec(`
167
188
  CREATE TABLE IF NOT EXISTS conscious_state (
@@ -193,8 +214,8 @@ export class EngramStore {
193
214
  this.db.prepare(`
194
215
  INSERT INTO engrams (id, agent_id, concept, content, embedding, confidence, salience,
195
216
  access_count, last_accessed, created_at, salience_features, reason_codes, stage, tags, episode_id,
196
- ttl, task_status, task_priority, blocked_by)
197
- VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)
217
+ ttl, memory_class, supersedes, task_status, task_priority, blocked_by)
218
+ VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?)
198
219
  `).run(
199
220
  id, input.agentId, input.concept, input.content, embeddingBlob,
200
221
  input.confidence ?? 0.5,
@@ -205,6 +226,8 @@ export class EngramStore {
205
226
  JSON.stringify(input.tags ?? []),
206
227
  input.episodeId ?? null,
207
228
  input.ttl ?? null,
229
+ input.memoryClass ?? 'working',
230
+ input.supersedes ?? null,
208
231
  input.taskStatus ?? null,
209
232
  input.taskPriority ?? null,
210
233
  input.blockedBy ?? null,
@@ -445,6 +468,29 @@ export class EngramStore {
445
468
  return row ? this.rowToEngram(row) : null;
446
469
  }
447
470
 
471
+ // --- Supersession ---
472
+
473
+ /**
474
+ * Mark an engram as superseded by another.
475
+ * The old memory stays in the DB (historical) but gets down-ranked in recall.
476
+ */
477
+ supersedeEngram(oldId: string, newId: string): void {
478
+ this.db.prepare('UPDATE engrams SET superseded_by = ? WHERE id = ?').run(newId, oldId);
479
+ this.db.prepare('UPDATE engrams SET supersedes = ? WHERE id = ?').run(oldId, newId);
480
+ }
481
+
482
+ /**
483
+ * Check if an engram has been superseded.
484
+ */
485
+ isSuperseded(id: string): boolean {
486
+ const row = this.db.prepare('SELECT superseded_by FROM engrams WHERE id = ?').get(id) as any;
487
+ return row?.superseded_by != null;
488
+ }
489
+
490
+ updateMemoryClass(id: string, memoryClass: MemoryClass): void {
491
+ this.db.prepare('UPDATE engrams SET memory_class = ? WHERE id = ?').run(memoryClass, id);
492
+ }
493
+
448
494
  // --- Associations ---
449
495
 
450
496
  upsertAssociation(
@@ -478,6 +524,13 @@ export class EngramStore {
478
524
  return (rows as any[]).map(r => this.rowToAssociation(r));
479
525
  }
480
526
 
527
+ getOutgoingAssociations(engramId: string): Association[] {
528
+ const rows = this.db.prepare(
529
+ 'SELECT * FROM associations WHERE from_engram_id = ?'
530
+ ).all(engramId);
531
+ return (rows as any[]).map(r => this.rowToAssociation(r));
532
+ }
533
+
481
534
  countAssociationsFor(engramId: string): number {
482
535
  const row = this.db.prepare(
483
536
  'SELECT COUNT(*) as count FROM associations WHERE from_engram_id = ?'
@@ -641,7 +694,7 @@ export class EngramStore {
641
694
  concept: row.concept,
642
695
  content: row.content,
643
696
  embedding: row.embedding
644
- ? Array.from(new Float32Array(row.embedding.buffer ?? row.embedding))
697
+ ? Array.from(bufferToFloat32Array(row.embedding))
645
698
  : null,
646
699
  confidence: row.confidence,
647
700
  salience: row.salience,
@@ -657,6 +710,9 @@ export class EngramStore {
657
710
  retractedAt: row.retracted_at ? new Date(row.retracted_at) : null,
658
711
  tags: JSON.parse(row.tags),
659
712
  episodeId: row.episode_id ?? null,
713
+ memoryClass: (row.memory_class ?? 'working') as MemoryClass,
714
+ supersededBy: row.superseded_by ?? null,
715
+ supersedes: row.supersedes ?? null,
660
716
  taskStatus: row.task_status ?? null,
661
717
  taskPriority: row.task_priority ?? null,
662
718
  blockedBy: row.blocked_by ?? null,
@@ -751,7 +807,7 @@ export class EngramStore {
751
807
  agentId: row.agent_id,
752
808
  label: row.label,
753
809
  embedding: row.embedding
754
- ? Array.from(new Float32Array(row.embedding.buffer ?? row.embedding))
810
+ ? Array.from(bufferToFloat32Array(row.embedding))
755
811
  : null,
756
812
  engramCount: row.engram_count,
757
813
  startTime: new Date(row.start_time),
@@ -1,3 +1,5 @@
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
1
3
  /**
2
4
  * Agent — a consciousness boundary.
3
5
  * Each agent has its own isolated memory space with capacity budgets.
@@ -1,44 +1,46 @@
1
- /**
2
- * Checkpoint types — conscious state preservation across compaction.
3
- *
4
- * ConsciousState: explicit structured snapshot (saved by agent)
5
- * AutoCheckpoint: implicit lightweight tracking (updated on every write/recall)
6
- */
7
-
8
- export interface ConsciousState {
9
- currentTask: string;
10
- decisions: string[];
11
- activeFiles: string[];
12
- nextSteps: string[];
13
- relatedMemoryIds: string[];
14
- notes: string;
15
- episodeId: string | null;
16
- }
17
-
18
- export interface AutoCheckpoint {
19
- lastWriteId: string | null;
20
- lastRecallContext: string | null;
21
- lastRecallIds: string[];
22
- lastActivityAt: Date;
23
- writeCountSinceConsolidation: number;
24
- recallCountSinceConsolidation: number;
25
- }
26
-
27
- export interface CheckpointRow {
28
- agentId: string;
29
- auto: AutoCheckpoint;
30
- executionState: ConsciousState | null;
31
- checkpointAt: Date | null;
32
- lastConsolidationAt: Date | null;
33
- lastMiniConsolidationAt: Date | null;
34
- updatedAt: Date;
35
- }
36
-
37
- export interface RestoreResult {
38
- executionState: ConsciousState | null;
39
- checkpointAt: Date | null;
40
- recalledMemories: Array<{ id: string; concept: string; content: string; score: number }>;
41
- lastWrite: { id: string; concept: string; content: string } | null;
42
- idleMs: number;
43
- miniConsolidationTriggered: boolean;
44
- }
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Checkpoint types conscious state preservation across compaction.
5
+ *
6
+ * ConsciousState: explicit structured snapshot (saved by agent)
7
+ * AutoCheckpoint: implicit lightweight tracking (updated on every write/recall)
8
+ */
9
+
10
+ export interface ConsciousState {
11
+ currentTask: string;
12
+ decisions: string[];
13
+ activeFiles: string[];
14
+ nextSteps: string[];
15
+ relatedMemoryIds: string[];
16
+ notes: string;
17
+ episodeId: string | null;
18
+ }
19
+
20
+ export interface AutoCheckpoint {
21
+ lastWriteId: string | null;
22
+ lastRecallContext: string | null;
23
+ lastRecallIds: string[];
24
+ lastActivityAt: Date;
25
+ writeCountSinceConsolidation: number;
26
+ recallCountSinceConsolidation: number;
27
+ }
28
+
29
+ export interface CheckpointRow {
30
+ agentId: string;
31
+ auto: AutoCheckpoint;
32
+ executionState: ConsciousState | null;
33
+ checkpointAt: Date | null;
34
+ lastConsolidationAt: Date | null;
35
+ lastMiniConsolidationAt: Date | null;
36
+ updatedAt: Date;
37
+ }
38
+
39
+ export interface RestoreResult {
40
+ executionState: ConsciousState | null;
41
+ checkpointAt: Date | null;
42
+ recalledMemories: Array<{ id: string; concept: string; content: string; score: number }>;
43
+ lastWrite: { id: string; concept: string; content: string } | null;
44
+ idleMs: number;
45
+ miniConsolidationTriggered: boolean;
46
+ }
@@ -1,3 +1,5 @@
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
1
3
  /**
2
4
  * Engram — the fundamental unit of agent memory.
3
5
  *
@@ -38,6 +40,13 @@ export interface Engram {
38
40
  // Episode grouping
39
41
  episodeId: string | null;
40
42
 
43
+ // Memory class
44
+ memoryClass: MemoryClass;
45
+
46
+ // Supersession — "this replaces that" (not retraction — original wasn't wrong, just outdated)
47
+ supersededBy: string | null; // ID of the engram that replaced this one
48
+ supersedes: string | null; // ID of the engram this one replaces
49
+
41
50
  // Task management (null = not a task)
42
51
  taskStatus: TaskStatus | null;
43
52
  taskPriority: TaskPriority | null;
@@ -49,6 +58,18 @@ export type EngramStage = 'staging' | 'active' | 'consolidated' | 'archived';
49
58
  export type TaskStatus = 'open' | 'in_progress' | 'blocked' | 'done';
50
59
  export type TaskPriority = 'urgent' | 'high' | 'medium' | 'low';
51
60
 
61
+ /**
62
+ * Memory class — controls salience floor and recall priority.
63
+ *
64
+ * canonical: Source-of-truth facts (current state, decisions, architecture).
65
+ * Never goes to staging. Minimum salience 0.7.
66
+ * working: Normal observations, learnings, context (default).
67
+ * Standard salience rules apply.
68
+ * ephemeral: Temporary context (debugging traces, session-specific notes).
69
+ * Stronger time decay, lower recall priority.
70
+ */
71
+ export type MemoryClass = 'canonical' | 'working' | 'ephemeral';
72
+
52
73
  /**
53
74
  * Raw feature scores that produced the salience score.
54
75
  * Persisted for auditability and tuning.
@@ -73,6 +94,8 @@ export interface EngramCreate {
73
94
  reasonCodes?: string[];
74
95
  episodeId?: string;
75
96
  ttl?: number;
97
+ memoryClass?: MemoryClass;
98
+ supersedes?: string;
76
99
  taskStatus?: TaskStatus;
77
100
  taskPriority?: TaskPriority;
78
101
  blockedBy?: string;
package/src/types/eval.ts CHANGED
@@ -1,3 +1,5 @@
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
1
3
  /**
2
4
  * Evaluation types — measuring whether memory actually helps.
3
5
  *
@@ -1,3 +1,5 @@
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
1
3
  export * from './engram.js';
2
4
  export * from './agent.js';
3
5
  export * from './eval.js';