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.
- package/LICENSE +190 -21
- package/README.md +21 -3
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +7 -0
- package/dist/api/routes.js.map +1 -1
- package/dist/cli.d.ts +0 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +69 -67
- package/dist/cli.js.map +1 -1
- package/dist/core/decay.d.ts.map +1 -1
- package/dist/core/decay.js +2 -0
- package/dist/core/decay.js.map +1 -1
- package/dist/core/embeddings.d.ts.map +1 -1
- package/dist/core/embeddings.js +2 -0
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/hebbian.d.ts.map +1 -1
- package/dist/core/hebbian.js +2 -0
- package/dist/core/hebbian.js.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +2 -0
- package/dist/core/logger.js.map +1 -1
- package/dist/core/query-expander.d.ts.map +1 -1
- package/dist/core/query-expander.js +2 -0
- package/dist/core/query-expander.js.map +1 -1
- package/dist/core/reranker.d.ts.map +1 -1
- package/dist/core/reranker.js +2 -0
- package/dist/core/reranker.js.map +1 -1
- package/dist/core/salience.d.ts +3 -1
- package/dist/core/salience.d.ts.map +1 -1
- package/dist/core/salience.js +29 -10
- package/dist/core/salience.js.map +1 -1
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +9 -0
- package/dist/engine/activation.js.map +1 -1
- package/dist/engine/connections.d.ts.map +1 -1
- package/dist/engine/connections.js +2 -0
- package/dist/engine/connections.js.map +1 -1
- package/dist/engine/consolidation-scheduler.d.ts.map +1 -1
- package/dist/engine/consolidation-scheduler.js +2 -0
- package/dist/engine/consolidation-scheduler.js.map +1 -1
- package/dist/engine/consolidation.d.ts.map +1 -1
- package/dist/engine/consolidation.js +5 -3
- package/dist/engine/consolidation.js.map +1 -1
- package/dist/engine/eval.d.ts.map +1 -1
- package/dist/engine/eval.js +2 -0
- package/dist/engine/eval.js.map +1 -1
- package/dist/engine/eviction.d.ts.map +1 -1
- package/dist/engine/eviction.js +2 -0
- package/dist/engine/eviction.js.map +1 -1
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +2 -0
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/retraction.d.ts.map +1 -1
- package/dist/engine/retraction.js +2 -0
- package/dist/engine/retraction.js.map +1 -1
- package/dist/engine/staging.d.ts.map +1 -1
- package/dist/engine/staging.js +2 -0
- package/dist/engine/staging.js.map +1 -1
- package/dist/hooks/sidecar.d.ts.map +1 -1
- package/dist/hooks/sidecar.js +2 -0
- package/dist/hooks/sidecar.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +69 -3
- package/dist/mcp.js.map +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/sqlite.d.ts +12 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +52 -5
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/agent.js +2 -0
- package/dist/types/agent.js.map +1 -1
- package/dist/types/checkpoint.d.ts.map +1 -1
- package/dist/types/checkpoint.js +2 -0
- package/dist/types/checkpoint.js.map +1 -1
- package/dist/types/engram.d.ts +16 -0
- package/dist/types/engram.d.ts.map +1 -1
- package/dist/types/engram.js +2 -0
- package/dist/types/engram.js.map +1 -1
- package/dist/types/eval.d.ts.map +1 -1
- package/dist/types/eval.js +2 -0
- package/dist/types/eval.js.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/package.json +2 -2
- package/src/api/index.ts +2 -0
- package/src/api/routes.ts +8 -0
- package/src/cli.ts +385 -383
- package/src/core/decay.ts +2 -0
- package/src/core/embeddings.ts +2 -0
- package/src/core/hebbian.ts +2 -0
- package/src/core/index.ts +2 -0
- package/src/core/logger.ts +2 -0
- package/src/core/query-expander.ts +2 -0
- package/src/core/reranker.ts +2 -0
- package/src/core/salience.ts +34 -13
- package/src/engine/activation.ts +10 -0
- package/src/engine/connections.ts +2 -0
- package/src/engine/consolidation-scheduler.ts +125 -123
- package/src/engine/consolidation.ts +5 -3
- package/src/engine/eval.ts +2 -0
- package/src/engine/eviction.ts +2 -0
- package/src/engine/index.ts +2 -0
- package/src/engine/retraction.ts +2 -0
- package/src/engine/staging.ts +2 -0
- package/src/hooks/sidecar.ts +2 -0
- package/src/index.ts +2 -0
- package/src/mcp.ts +82 -3
- package/src/storage/index.ts +2 -0
- package/src/storage/sqlite.ts +61 -5
- package/src/types/agent.ts +2 -0
- package/src/types/checkpoint.ts +46 -44
- package/src/types/engram.ts +23 -0
- package/src/types/eval.ts +2 -0
- package/src/types/index.ts +2 -0
package/src/storage/sqlite.ts
CHANGED
|
@@ -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(
|
|
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(
|
|
810
|
+
? Array.from(bufferToFloat32Array(row.embedding))
|
|
755
811
|
: null,
|
|
756
812
|
engramCount: row.engram_count,
|
|
757
813
|
startTime: new Date(row.start_time),
|
package/src/types/agent.ts
CHANGED
package/src/types/checkpoint.ts
CHANGED
|
@@ -1,44 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
+
}
|
package/src/types/engram.ts
CHANGED
|
@@ -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