agent-working-memory 0.4.3 → 0.5.2
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/README.md +2 -0
- package/dist/cli.js +15 -4
- package/dist/cli.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 +28 -12
- package/dist/core/salience.js.map +1 -1
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +7 -0
- package/dist/engine/activation.js.map +1 -1
- package/dist/engine/consolidation.d.ts.map +1 -1
- package/dist/engine/consolidation.js +27 -15
- package/dist/engine/consolidation.js.map +1 -1
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +150 -78
- package/dist/mcp.js.map +1 -1
- package/dist/storage/sqlite.d.ts +13 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +51 -3
- package/dist/storage/sqlite.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.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +16 -4
- package/src/core/salience.ts +168 -145
- package/src/engine/activation.ts +8 -0
- package/src/engine/consolidation.ts +469 -451
- package/src/hooks/sidecar.ts +289 -289
- package/src/mcp.ts +971 -886
- package/src/storage/sqlite.ts +63 -3
- package/src/types/engram.ts +21 -0
package/src/storage/sqlite.ts
CHANGED
|
@@ -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,
|
|
15
|
+
RetrievalFeedbackEvent, Episode, TaskStatus, TaskPriority, MemoryClass,
|
|
16
16
|
ConsciousState, AutoCheckpoint, CheckpointRow,
|
|
17
17
|
} from '../types/index.js';
|
|
18
18
|
|
|
@@ -172,6 +172,17 @@ export class EngramStore {
|
|
|
172
172
|
this.db.exec('CREATE INDEX IF NOT EXISTS idx_engrams_task ON engrams(agent_id, task_status)');
|
|
173
173
|
}
|
|
174
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
|
+
|
|
175
186
|
// Migration: add conscious_state table for checkpointing
|
|
176
187
|
this.db.exec(`
|
|
177
188
|
CREATE TABLE IF NOT EXISTS conscious_state (
|
|
@@ -186,9 +197,15 @@ export class EngramStore {
|
|
|
186
197
|
checkpoint_at TEXT,
|
|
187
198
|
last_consolidation_at TEXT,
|
|
188
199
|
last_mini_consolidation_at TEXT,
|
|
200
|
+
consolidation_cycle_count INTEGER NOT NULL DEFAULT 0,
|
|
189
201
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
190
202
|
)
|
|
191
203
|
`);
|
|
204
|
+
|
|
205
|
+
// Migration: add consolidation_cycle_count if missing (existing DBs)
|
|
206
|
+
try {
|
|
207
|
+
this.db.exec(`ALTER TABLE conscious_state ADD COLUMN consolidation_cycle_count INTEGER NOT NULL DEFAULT 0`);
|
|
208
|
+
} catch { /* column already exists */ }
|
|
192
209
|
}
|
|
193
210
|
|
|
194
211
|
// --- Engram CRUD ---
|
|
@@ -203,8 +220,8 @@ export class EngramStore {
|
|
|
203
220
|
this.db.prepare(`
|
|
204
221
|
INSERT INTO engrams (id, agent_id, concept, content, embedding, confidence, salience,
|
|
205
222
|
access_count, last_accessed, created_at, salience_features, reason_codes, stage, tags, episode_id,
|
|
206
|
-
ttl, task_status, task_priority, blocked_by)
|
|
207
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)
|
|
223
|
+
ttl, memory_class, supersedes, task_status, task_priority, blocked_by)
|
|
224
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?)
|
|
208
225
|
`).run(
|
|
209
226
|
id, input.agentId, input.concept, input.content, embeddingBlob,
|
|
210
227
|
input.confidence ?? 0.5,
|
|
@@ -215,6 +232,8 @@ export class EngramStore {
|
|
|
215
232
|
JSON.stringify(input.tags ?? []),
|
|
216
233
|
input.episodeId ?? null,
|
|
217
234
|
input.ttl ?? null,
|
|
235
|
+
input.memoryClass ?? 'working',
|
|
236
|
+
input.supersedes ?? null,
|
|
218
237
|
input.taskStatus ?? null,
|
|
219
238
|
input.taskPriority ?? null,
|
|
220
239
|
input.blockedBy ?? null,
|
|
@@ -455,6 +474,29 @@ export class EngramStore {
|
|
|
455
474
|
return row ? this.rowToEngram(row) : null;
|
|
456
475
|
}
|
|
457
476
|
|
|
477
|
+
// --- Supersession ---
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Mark an engram as superseded by another.
|
|
481
|
+
* The old memory stays in the DB (historical) but gets down-ranked in recall.
|
|
482
|
+
*/
|
|
483
|
+
supersedeEngram(oldId: string, newId: string): void {
|
|
484
|
+
this.db.prepare('UPDATE engrams SET superseded_by = ? WHERE id = ?').run(newId, oldId);
|
|
485
|
+
this.db.prepare('UPDATE engrams SET supersedes = ? WHERE id = ?').run(oldId, newId);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Check if an engram has been superseded.
|
|
490
|
+
*/
|
|
491
|
+
isSuperseded(id: string): boolean {
|
|
492
|
+
const row = this.db.prepare('SELECT superseded_by FROM engrams WHERE id = ?').get(id) as any;
|
|
493
|
+
return row?.superseded_by != null;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
updateMemoryClass(id: string, memoryClass: MemoryClass): void {
|
|
497
|
+
this.db.prepare('UPDATE engrams SET memory_class = ? WHERE id = ?').run(memoryClass, id);
|
|
498
|
+
}
|
|
499
|
+
|
|
458
500
|
// --- Associations ---
|
|
459
501
|
|
|
460
502
|
upsertAssociation(
|
|
@@ -488,6 +530,13 @@ export class EngramStore {
|
|
|
488
530
|
return (rows as any[]).map(r => this.rowToAssociation(r));
|
|
489
531
|
}
|
|
490
532
|
|
|
533
|
+
getOutgoingAssociations(engramId: string): Association[] {
|
|
534
|
+
const rows = this.db.prepare(
|
|
535
|
+
'SELECT * FROM associations WHERE from_engram_id = ?'
|
|
536
|
+
).all(engramId);
|
|
537
|
+
return (rows as any[]).map(r => this.rowToAssociation(r));
|
|
538
|
+
}
|
|
539
|
+
|
|
491
540
|
countAssociationsFor(engramId: string): number {
|
|
492
541
|
const row = this.db.prepare(
|
|
493
542
|
'SELECT COUNT(*) as count FROM associations WHERE from_engram_id = ?'
|
|
@@ -667,6 +716,9 @@ export class EngramStore {
|
|
|
667
716
|
retractedAt: row.retracted_at ? new Date(row.retracted_at) : null,
|
|
668
717
|
tags: JSON.parse(row.tags),
|
|
669
718
|
episodeId: row.episode_id ?? null,
|
|
719
|
+
memoryClass: (row.memory_class ?? 'working') as MemoryClass,
|
|
720
|
+
supersededBy: row.superseded_by ?? null,
|
|
721
|
+
supersedes: row.supersedes ?? null,
|
|
670
722
|
taskStatus: row.task_status ?? null,
|
|
671
723
|
taskPriority: row.task_priority ?? null,
|
|
672
724
|
blockedBy: row.blocked_by ?? null,
|
|
@@ -880,6 +932,7 @@ export class EngramStore {
|
|
|
880
932
|
last_mini_consolidation_at = ?,
|
|
881
933
|
write_count_since_consolidation = 0,
|
|
882
934
|
recall_count_since_consolidation = 0,
|
|
935
|
+
consolidation_cycle_count = consolidation_cycle_count + 1,
|
|
883
936
|
updated_at = ?
|
|
884
937
|
WHERE agent_id = ?
|
|
885
938
|
`).run(now, now, now, agentId);
|
|
@@ -897,6 +950,13 @@ export class EngramStore {
|
|
|
897
950
|
}));
|
|
898
951
|
}
|
|
899
952
|
|
|
953
|
+
getConsolidationCycleCount(agentId: string): number {
|
|
954
|
+
const row = this.db.prepare(
|
|
955
|
+
'SELECT consolidation_cycle_count FROM conscious_state WHERE agent_id = ?',
|
|
956
|
+
).get(agentId) as { consolidation_cycle_count: number } | undefined;
|
|
957
|
+
return row?.consolidation_cycle_count ?? 0;
|
|
958
|
+
}
|
|
959
|
+
|
|
900
960
|
close(): void {
|
|
901
961
|
this.db.close();
|
|
902
962
|
}
|
package/src/types/engram.ts
CHANGED
|
@@ -40,6 +40,13 @@ export interface Engram {
|
|
|
40
40
|
// Episode grouping
|
|
41
41
|
episodeId: string | null;
|
|
42
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
|
+
|
|
43
50
|
// Task management (null = not a task)
|
|
44
51
|
taskStatus: TaskStatus | null;
|
|
45
52
|
taskPriority: TaskPriority | null;
|
|
@@ -51,6 +58,18 @@ export type EngramStage = 'staging' | 'active' | 'consolidated' | 'archived';
|
|
|
51
58
|
export type TaskStatus = 'open' | 'in_progress' | 'blocked' | 'done';
|
|
52
59
|
export type TaskPriority = 'urgent' | 'high' | 'medium' | 'low';
|
|
53
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
|
+
|
|
54
73
|
/**
|
|
55
74
|
* Raw feature scores that produced the salience score.
|
|
56
75
|
* Persisted for auditability and tuning.
|
|
@@ -75,6 +94,8 @@ export interface EngramCreate {
|
|
|
75
94
|
reasonCodes?: string[];
|
|
76
95
|
episodeId?: string;
|
|
77
96
|
ttl?: number;
|
|
97
|
+
memoryClass?: MemoryClass;
|
|
98
|
+
supersedes?: string;
|
|
78
99
|
taskStatus?: TaskStatus;
|
|
79
100
|
taskPriority?: TaskPriority;
|
|
80
101
|
blockedBy?: string;
|