agent-working-memory 0.5.5 → 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.
- package/README.md +428 -399
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +60 -5
- package/dist/api/routes.js.map +1 -1
- package/dist/cli.js +468 -68
- package/dist/cli.js.map +1 -1
- package/dist/coordination/index.d.ts +11 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +39 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/mcp-tools.d.ts +8 -0
- package/dist/coordination/mcp-tools.d.ts.map +1 -0
- package/dist/coordination/mcp-tools.js +221 -0
- package/dist/coordination/mcp-tools.js.map +1 -0
- package/dist/coordination/routes.d.ts +9 -0
- package/dist/coordination/routes.d.ts.map +1 -0
- package/dist/coordination/routes.js +573 -0
- package/dist/coordination/routes.js.map +1 -0
- package/dist/coordination/schema.d.ts +12 -0
- package/dist/coordination/schema.d.ts.map +1 -0
- package/dist/coordination/schema.js +125 -0
- package/dist/coordination/schema.js.map +1 -0
- package/dist/coordination/schemas.d.ts +227 -0
- package/dist/coordination/schemas.d.ts.map +1 -0
- package/dist/coordination/schemas.js +125 -0
- package/dist/coordination/schemas.js.map +1 -0
- package/dist/coordination/stale.d.ts +27 -0
- package/dist/coordination/stale.d.ts.map +1 -0
- package/dist/coordination/stale.js +58 -0
- package/dist/coordination/stale.js.map +1 -0
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +119 -23
- package/dist/engine/activation.js.map +1 -1
- package/dist/engine/consolidation.d.ts.map +1 -1
- package/dist/engine/consolidation.js +27 -6
- package/dist/engine/consolidation.js.map +1 -1
- package/dist/index.js +100 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +149 -80
- package/dist/mcp.js.map +1 -1
- package/dist/storage/sqlite.d.ts +21 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +331 -282
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/types/engram.d.ts +24 -0
- package/dist/types/engram.d.ts.map +1 -1
- package/dist/types/engram.js.map +1 -1
- package/package.json +57 -55
- package/src/api/index.ts +3 -3
- package/src/api/routes.ts +600 -536
- package/src/cli.ts +850 -397
- package/src/coordination/index.ts +47 -0
- package/src/coordination/mcp-tools.ts +318 -0
- package/src/coordination/routes.ts +846 -0
- package/src/coordination/schema.ts +120 -0
- package/src/coordination/schemas.ts +155 -0
- package/src/coordination/stale.ts +97 -0
- package/src/core/decay.ts +63 -63
- package/src/core/embeddings.ts +88 -88
- package/src/core/hebbian.ts +93 -93
- package/src/core/index.ts +5 -5
- package/src/core/logger.ts +36 -36
- package/src/core/query-expander.ts +66 -66
- package/src/core/reranker.ts +101 -101
- package/src/engine/activation.ts +758 -656
- package/src/engine/connections.ts +103 -103
- package/src/engine/consolidation-scheduler.ts +125 -125
- package/src/engine/consolidation.ts +29 -6
- package/src/engine/eval.ts +102 -102
- package/src/engine/eviction.ts +101 -101
- package/src/engine/index.ts +8 -8
- package/src/engine/retraction.ts +100 -100
- package/src/engine/staging.ts +74 -74
- package/src/index.ts +208 -121
- package/src/mcp.ts +1093 -1013
- package/src/storage/index.ts +3 -3
- package/src/storage/sqlite.ts +1017 -963
- package/src/types/agent.ts +67 -67
- package/src/types/checkpoint.ts +46 -46
- package/src/types/engram.ts +245 -217
- package/src/types/eval.ts +100 -100
- package/src/types/index.ts +6 -6
package/dist/storage/sqlite.js
CHANGED
|
@@ -25,121 +25,147 @@ export class EngramStore {
|
|
|
25
25
|
this.db = new Database(dbPath);
|
|
26
26
|
this.db.pragma('journal_mode = WAL');
|
|
27
27
|
this.db.pragma('foreign_keys = ON');
|
|
28
|
+
this.db.pragma('busy_timeout = 5000');
|
|
29
|
+
this.db.pragma('synchronous = NORMAL');
|
|
28
30
|
this.init();
|
|
29
31
|
}
|
|
32
|
+
/** Expose the raw database handle for the coordination module. */
|
|
33
|
+
getDb() {
|
|
34
|
+
return this.db;
|
|
35
|
+
}
|
|
36
|
+
/** Run PRAGMA quick_check and return true if DB is healthy. */
|
|
37
|
+
integrityCheck() {
|
|
38
|
+
try {
|
|
39
|
+
const rows = this.db.pragma('quick_check');
|
|
40
|
+
const result = rows[0]?.quick_check ?? 'unknown';
|
|
41
|
+
return { ok: result === 'ok', result };
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return { ok: false, result: err.message };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Hot backup using SQLite backup API. Returns the backup path. */
|
|
48
|
+
backup(destPath) {
|
|
49
|
+
this.db.backup(destPath);
|
|
50
|
+
}
|
|
51
|
+
/** Flush WAL to main database file. */
|
|
52
|
+
walCheckpoint() {
|
|
53
|
+
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
54
|
+
}
|
|
30
55
|
init() {
|
|
31
|
-
this.db.exec(`
|
|
32
|
-
CREATE TABLE IF NOT EXISTS engrams (
|
|
33
|
-
id TEXT PRIMARY KEY,
|
|
34
|
-
agent_id TEXT NOT NULL,
|
|
35
|
-
concept TEXT NOT NULL,
|
|
36
|
-
content TEXT NOT NULL,
|
|
37
|
-
embedding BLOB,
|
|
38
|
-
confidence REAL NOT NULL DEFAULT 0.5,
|
|
39
|
-
salience REAL NOT NULL DEFAULT 0.5,
|
|
40
|
-
access_count INTEGER NOT NULL DEFAULT 0,
|
|
41
|
-
last_accessed TEXT NOT NULL,
|
|
42
|
-
created_at TEXT NOT NULL,
|
|
43
|
-
salience_features TEXT NOT NULL DEFAULT '{}',
|
|
44
|
-
reason_codes TEXT NOT NULL DEFAULT '[]',
|
|
45
|
-
stage TEXT NOT NULL DEFAULT 'active',
|
|
46
|
-
ttl INTEGER,
|
|
47
|
-
retracted INTEGER NOT NULL DEFAULT 0,
|
|
48
|
-
retracted_by TEXT,
|
|
49
|
-
retracted_at TEXT,
|
|
50
|
-
tags TEXT NOT NULL DEFAULT '[]'
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
CREATE INDEX IF NOT EXISTS
|
|
55
|
-
CREATE INDEX IF NOT EXISTS
|
|
56
|
-
CREATE INDEX IF NOT EXISTS
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
CREATE INDEX IF NOT EXISTS
|
|
72
|
-
CREATE
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
content
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
INSERT INTO engrams_fts(rowid, concept, content, tags) VALUES
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
CREATE INDEX IF NOT EXISTS
|
|
56
|
+
this.db.exec(`
|
|
57
|
+
CREATE TABLE IF NOT EXISTS engrams (
|
|
58
|
+
id TEXT PRIMARY KEY,
|
|
59
|
+
agent_id TEXT NOT NULL,
|
|
60
|
+
concept TEXT NOT NULL,
|
|
61
|
+
content TEXT NOT NULL,
|
|
62
|
+
embedding BLOB,
|
|
63
|
+
confidence REAL NOT NULL DEFAULT 0.5,
|
|
64
|
+
salience REAL NOT NULL DEFAULT 0.5,
|
|
65
|
+
access_count INTEGER NOT NULL DEFAULT 0,
|
|
66
|
+
last_accessed TEXT NOT NULL,
|
|
67
|
+
created_at TEXT NOT NULL,
|
|
68
|
+
salience_features TEXT NOT NULL DEFAULT '{}',
|
|
69
|
+
reason_codes TEXT NOT NULL DEFAULT '[]',
|
|
70
|
+
stage TEXT NOT NULL DEFAULT 'active',
|
|
71
|
+
ttl INTEGER,
|
|
72
|
+
retracted INTEGER NOT NULL DEFAULT 0,
|
|
73
|
+
retracted_by TEXT,
|
|
74
|
+
retracted_at TEXT,
|
|
75
|
+
tags TEXT NOT NULL DEFAULT '[]',
|
|
76
|
+
memory_type TEXT NOT NULL DEFAULT 'unclassified'
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_engrams_agent ON engrams(agent_id);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_engrams_stage ON engrams(agent_id, stage);
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_engrams_concept ON engrams(concept);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_engrams_retracted ON engrams(agent_id, retracted);
|
|
83
|
+
|
|
84
|
+
CREATE TABLE IF NOT EXISTS associations (
|
|
85
|
+
id TEXT PRIMARY KEY,
|
|
86
|
+
from_engram_id TEXT NOT NULL REFERENCES engrams(id) ON DELETE CASCADE,
|
|
87
|
+
to_engram_id TEXT NOT NULL REFERENCES engrams(id) ON DELETE CASCADE,
|
|
88
|
+
weight REAL NOT NULL DEFAULT 0.1,
|
|
89
|
+
confidence REAL NOT NULL DEFAULT 0.5,
|
|
90
|
+
type TEXT NOT NULL DEFAULT 'hebbian',
|
|
91
|
+
activation_count INTEGER NOT NULL DEFAULT 0,
|
|
92
|
+
created_at TEXT NOT NULL,
|
|
93
|
+
last_activated TEXT NOT NULL
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_assoc_from ON associations(from_engram_id);
|
|
97
|
+
CREATE INDEX IF NOT EXISTS idx_assoc_to ON associations(to_engram_id);
|
|
98
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_assoc_pair ON associations(from_engram_id, to_engram_id);
|
|
99
|
+
|
|
100
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
101
|
+
id TEXT PRIMARY KEY,
|
|
102
|
+
name TEXT NOT NULL,
|
|
103
|
+
created_at TEXT NOT NULL,
|
|
104
|
+
config TEXT NOT NULL DEFAULT '{}'
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
-- FTS5 for full-text search (BM25 ranking built in)
|
|
108
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS engrams_fts USING fts5(
|
|
109
|
+
concept, content, tags,
|
|
110
|
+
content=engrams,
|
|
111
|
+
content_rowid=rowid
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
-- Triggers to keep FTS in sync
|
|
115
|
+
CREATE TRIGGER IF NOT EXISTS engrams_ai AFTER INSERT ON engrams BEGIN
|
|
116
|
+
INSERT INTO engrams_fts(rowid, concept, content, tags) VALUES (new.rowid, new.concept, new.content, new.tags);
|
|
117
|
+
END;
|
|
118
|
+
CREATE TRIGGER IF NOT EXISTS engrams_ad AFTER DELETE ON engrams BEGIN
|
|
119
|
+
INSERT INTO engrams_fts(engrams_fts, rowid, concept, content, tags) VALUES('delete', old.rowid, old.concept, old.content, old.tags);
|
|
120
|
+
END;
|
|
121
|
+
CREATE TRIGGER IF NOT EXISTS engrams_au AFTER UPDATE ON engrams BEGIN
|
|
122
|
+
INSERT INTO engrams_fts(engrams_fts, rowid, concept, content, tags) VALUES('delete', old.rowid, old.concept, old.content, old.tags);
|
|
123
|
+
INSERT INTO engrams_fts(rowid, concept, content, tags) VALUES (new.rowid, new.concept, new.content, new.tags);
|
|
124
|
+
END;
|
|
125
|
+
|
|
126
|
+
-- Eval event logs
|
|
127
|
+
CREATE TABLE IF NOT EXISTS activation_events (
|
|
128
|
+
id TEXT PRIMARY KEY,
|
|
129
|
+
agent_id TEXT NOT NULL,
|
|
130
|
+
timestamp TEXT NOT NULL,
|
|
131
|
+
context TEXT NOT NULL,
|
|
132
|
+
results_returned INTEGER NOT NULL,
|
|
133
|
+
top_score REAL,
|
|
134
|
+
latency_ms REAL NOT NULL,
|
|
135
|
+
engram_ids TEXT NOT NULL DEFAULT '[]'
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
CREATE TABLE IF NOT EXISTS staging_events (
|
|
139
|
+
engram_id TEXT NOT NULL,
|
|
140
|
+
agent_id TEXT NOT NULL,
|
|
141
|
+
action TEXT NOT NULL,
|
|
142
|
+
resonance_score REAL,
|
|
143
|
+
timestamp TEXT NOT NULL,
|
|
144
|
+
age_ms INTEGER NOT NULL
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
CREATE TABLE IF NOT EXISTS retrieval_feedback (
|
|
148
|
+
id TEXT PRIMARY KEY,
|
|
149
|
+
activation_event_id TEXT,
|
|
150
|
+
engram_id TEXT NOT NULL,
|
|
151
|
+
useful INTEGER NOT NULL,
|
|
152
|
+
context TEXT,
|
|
153
|
+
timestamp TEXT NOT NULL
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
CREATE TABLE IF NOT EXISTS episodes (
|
|
157
|
+
id TEXT PRIMARY KEY,
|
|
158
|
+
agent_id TEXT NOT NULL,
|
|
159
|
+
label TEXT NOT NULL,
|
|
160
|
+
embedding BLOB,
|
|
161
|
+
engram_count INTEGER NOT NULL DEFAULT 0,
|
|
162
|
+
start_time TEXT NOT NULL,
|
|
163
|
+
end_time TEXT NOT NULL,
|
|
164
|
+
created_at TEXT NOT NULL
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
CREATE INDEX IF NOT EXISTS idx_episodes_agent ON episodes(agent_id);
|
|
168
|
+
CREATE INDEX IF NOT EXISTS idx_episodes_time ON episodes(agent_id, end_time);
|
|
143
169
|
`);
|
|
144
170
|
// Migration: add episode_id column if missing
|
|
145
171
|
try {
|
|
@@ -153,10 +179,10 @@ export class EngramStore {
|
|
|
153
179
|
this.db.prepare('SELECT task_status FROM engrams LIMIT 0').get();
|
|
154
180
|
}
|
|
155
181
|
catch {
|
|
156
|
-
this.db.exec(`
|
|
157
|
-
ALTER TABLE engrams ADD COLUMN task_status TEXT;
|
|
158
|
-
ALTER TABLE engrams ADD COLUMN task_priority TEXT;
|
|
159
|
-
ALTER TABLE engrams ADD COLUMN blocked_by TEXT;
|
|
182
|
+
this.db.exec(`
|
|
183
|
+
ALTER TABLE engrams ADD COLUMN task_status TEXT;
|
|
184
|
+
ALTER TABLE engrams ADD COLUMN task_priority TEXT;
|
|
185
|
+
ALTER TABLE engrams ADD COLUMN blocked_by TEXT;
|
|
160
186
|
`);
|
|
161
187
|
this.db.exec('CREATE INDEX IF NOT EXISTS idx_engrams_task ON engrams(agent_id, task_status)');
|
|
162
188
|
}
|
|
@@ -165,35 +191,42 @@ export class EngramStore {
|
|
|
165
191
|
this.db.prepare('SELECT memory_class FROM engrams LIMIT 0').get();
|
|
166
192
|
}
|
|
167
193
|
catch {
|
|
168
|
-
this.db.exec(`
|
|
169
|
-
ALTER TABLE engrams ADD COLUMN memory_class TEXT NOT NULL DEFAULT 'working';
|
|
170
|
-
ALTER TABLE engrams ADD COLUMN superseded_by TEXT;
|
|
171
|
-
ALTER TABLE engrams ADD COLUMN supersedes TEXT;
|
|
194
|
+
this.db.exec(`
|
|
195
|
+
ALTER TABLE engrams ADD COLUMN memory_class TEXT NOT NULL DEFAULT 'working';
|
|
196
|
+
ALTER TABLE engrams ADD COLUMN superseded_by TEXT;
|
|
197
|
+
ALTER TABLE engrams ADD COLUMN supersedes TEXT;
|
|
172
198
|
`);
|
|
173
199
|
}
|
|
174
200
|
// Migration: add conscious_state table for checkpointing
|
|
175
|
-
this.db.exec(`
|
|
176
|
-
CREATE TABLE IF NOT EXISTS conscious_state (
|
|
177
|
-
agent_id TEXT PRIMARY KEY,
|
|
178
|
-
last_write_id TEXT,
|
|
179
|
-
last_recall_context TEXT,
|
|
180
|
-
last_recall_ids TEXT NOT NULL DEFAULT '[]',
|
|
181
|
-
last_activity_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
182
|
-
write_count_since_consolidation INTEGER NOT NULL DEFAULT 0,
|
|
183
|
-
recall_count_since_consolidation INTEGER NOT NULL DEFAULT 0,
|
|
184
|
-
execution_state TEXT,
|
|
185
|
-
checkpoint_at TEXT,
|
|
186
|
-
last_consolidation_at TEXT,
|
|
187
|
-
last_mini_consolidation_at TEXT,
|
|
188
|
-
consolidation_cycle_count INTEGER NOT NULL DEFAULT 0,
|
|
189
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
190
|
-
)
|
|
201
|
+
this.db.exec(`
|
|
202
|
+
CREATE TABLE IF NOT EXISTS conscious_state (
|
|
203
|
+
agent_id TEXT PRIMARY KEY,
|
|
204
|
+
last_write_id TEXT,
|
|
205
|
+
last_recall_context TEXT,
|
|
206
|
+
last_recall_ids TEXT NOT NULL DEFAULT '[]',
|
|
207
|
+
last_activity_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
208
|
+
write_count_since_consolidation INTEGER NOT NULL DEFAULT 0,
|
|
209
|
+
recall_count_since_consolidation INTEGER NOT NULL DEFAULT 0,
|
|
210
|
+
execution_state TEXT,
|
|
211
|
+
checkpoint_at TEXT,
|
|
212
|
+
last_consolidation_at TEXT,
|
|
213
|
+
last_mini_consolidation_at TEXT,
|
|
214
|
+
consolidation_cycle_count INTEGER NOT NULL DEFAULT 0,
|
|
215
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
216
|
+
)
|
|
191
217
|
`);
|
|
192
218
|
// Migration: add consolidation_cycle_count if missing (existing DBs)
|
|
193
219
|
try {
|
|
194
220
|
this.db.exec(`ALTER TABLE conscious_state ADD COLUMN consolidation_cycle_count INTEGER NOT NULL DEFAULT 0`);
|
|
195
221
|
}
|
|
196
222
|
catch { /* column already exists */ }
|
|
223
|
+
// Migration: add memory_type column if missing
|
|
224
|
+
try {
|
|
225
|
+
this.db.prepare('SELECT memory_type FROM engrams LIMIT 0').get();
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
this.db.exec(`ALTER TABLE engrams ADD COLUMN memory_type TEXT NOT NULL DEFAULT 'unclassified'`);
|
|
229
|
+
}
|
|
197
230
|
}
|
|
198
231
|
// --- Engram CRUD ---
|
|
199
232
|
createEngram(input) {
|
|
@@ -202,12 +235,12 @@ export class EngramStore {
|
|
|
202
235
|
const embeddingBlob = input.embedding
|
|
203
236
|
? Buffer.from(new Float32Array(input.embedding).buffer)
|
|
204
237
|
: null;
|
|
205
|
-
this.db.prepare(`
|
|
206
|
-
INSERT INTO engrams (id, agent_id, concept, content, embedding, confidence, salience,
|
|
207
|
-
access_count, last_accessed, created_at, salience_features, reason_codes, stage, tags, episode_id,
|
|
208
|
-
ttl, memory_class, supersedes, task_status, task_priority, blocked_by)
|
|
209
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?)
|
|
210
|
-
`).run(id, input.agentId, input.concept, input.content, embeddingBlob, input.confidence ?? 0.5, input.salience ?? 0.5, now, now, JSON.stringify(input.salienceFeatures ?? DEFAULT_SALIENCE_FEATURES), JSON.stringify(input.reasonCodes ?? []), JSON.stringify(input.tags ?? []), input.episodeId ?? null, input.ttl ?? null, input.memoryClass ?? 'working', input.supersedes ?? null, input.taskStatus ?? null, input.taskPriority ?? null, input.blockedBy ?? null);
|
|
238
|
+
this.db.prepare(`
|
|
239
|
+
INSERT INTO engrams (id, agent_id, concept, content, embedding, confidence, salience,
|
|
240
|
+
access_count, last_accessed, created_at, salience_features, reason_codes, stage, tags, episode_id,
|
|
241
|
+
ttl, memory_class, supersedes, task_status, task_priority, blocked_by, memory_type)
|
|
242
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
243
|
+
`).run(id, input.agentId, input.concept, input.content, embeddingBlob, input.confidence ?? 0.5, input.salience ?? 0.5, now, now, JSON.stringify(input.salienceFeatures ?? DEFAULT_SALIENCE_FEATURES), JSON.stringify(input.reasonCodes ?? []), JSON.stringify(input.tags ?? []), input.episodeId ?? null, input.ttl ?? null, input.memoryClass ?? 'working', input.supersedes ?? null, input.taskStatus ?? null, input.taskPriority ?? null, input.blockedBy ?? null, input.memoryType ?? 'unclassified');
|
|
211
244
|
return this.getEngram(id);
|
|
212
245
|
}
|
|
213
246
|
getEngram(id) {
|
|
@@ -226,9 +259,21 @@ export class EngramStore {
|
|
|
226
259
|
}
|
|
227
260
|
return this.db.prepare(query).all(...params).map(r => this.rowToEngram(r));
|
|
228
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* Touch an engram: increment access count, update last_accessed, and
|
|
264
|
+
* nudge confidence upward. Each retrieval is weak evidence the memory
|
|
265
|
+
* is useful — bounded so only explicit feedback can push confidence
|
|
266
|
+
* above 0.85. Diminishing returns: first accesses matter most.
|
|
267
|
+
*
|
|
268
|
+
* Boost: +0.02 per access, scaled by 1/sqrt(accessCount+1), capped at 0.85.
|
|
269
|
+
*/
|
|
229
270
|
touchEngram(id) {
|
|
230
|
-
this.db.prepare(`
|
|
231
|
-
UPDATE engrams
|
|
271
|
+
this.db.prepare(`
|
|
272
|
+
UPDATE engrams
|
|
273
|
+
SET access_count = access_count + 1,
|
|
274
|
+
last_accessed = ?,
|
|
275
|
+
confidence = MIN(0.85, confidence + 0.02 / (1.0 + sqrt(access_count)))
|
|
276
|
+
WHERE id = ?
|
|
232
277
|
`).run(new Date().toISOString(), id);
|
|
233
278
|
}
|
|
234
279
|
updateStage(id, stage) {
|
|
@@ -242,8 +287,8 @@ export class EngramStore {
|
|
|
242
287
|
this.db.prepare('UPDATE engrams SET embedding = ? WHERE id = ?').run(blob, id);
|
|
243
288
|
}
|
|
244
289
|
retractEngram(id, retractedBy) {
|
|
245
|
-
this.db.prepare(`
|
|
246
|
-
UPDATE engrams SET retracted = 1, retracted_by = ?, retracted_at = ? WHERE id = ?
|
|
290
|
+
this.db.prepare(`
|
|
291
|
+
UPDATE engrams SET retracted = 1, retracted_by = ?, retracted_at = ? WHERE id = ?
|
|
247
292
|
`).run(retractedBy, new Date().toISOString(), id);
|
|
248
293
|
}
|
|
249
294
|
deleteEngram(id) {
|
|
@@ -258,20 +303,20 @@ export class EngramStore {
|
|
|
258
303
|
let count = 0;
|
|
259
304
|
const shiftSec = Math.round(ms / 1000);
|
|
260
305
|
// Shift engram timestamps
|
|
261
|
-
const r1 = this.db.prepare(`
|
|
262
|
-
UPDATE engrams SET
|
|
263
|
-
created_at = datetime(created_at, '-${shiftSec} seconds'),
|
|
264
|
-
last_accessed = datetime(last_accessed, '-${shiftSec} seconds')
|
|
265
|
-
WHERE agent_id = ?
|
|
306
|
+
const r1 = this.db.prepare(`
|
|
307
|
+
UPDATE engrams SET
|
|
308
|
+
created_at = datetime(created_at, '-${shiftSec} seconds'),
|
|
309
|
+
last_accessed = datetime(last_accessed, '-${shiftSec} seconds')
|
|
310
|
+
WHERE agent_id = ?
|
|
266
311
|
`).run(agentId);
|
|
267
312
|
count += r1.changes;
|
|
268
313
|
// Shift association timestamps
|
|
269
|
-
const r2 = this.db.prepare(`
|
|
270
|
-
UPDATE associations SET
|
|
271
|
-
created_at = datetime(created_at, '-${shiftSec} seconds'),
|
|
272
|
-
last_activated = datetime(last_activated, '-${shiftSec} seconds')
|
|
273
|
-
WHERE from_engram_id IN (SELECT id FROM engrams WHERE agent_id = ?)
|
|
274
|
-
OR to_engram_id IN (SELECT id FROM engrams WHERE agent_id = ?)
|
|
314
|
+
const r2 = this.db.prepare(`
|
|
315
|
+
UPDATE associations SET
|
|
316
|
+
created_at = datetime(created_at, '-${shiftSec} seconds'),
|
|
317
|
+
last_activated = datetime(last_activated, '-${shiftSec} seconds')
|
|
318
|
+
WHERE from_engram_id IN (SELECT id FROM engrams WHERE agent_id = ?)
|
|
319
|
+
OR to_engram_id IN (SELECT id FROM engrams WHERE agent_id = ?)
|
|
275
320
|
`).run(agentId, agentId);
|
|
276
321
|
count += r2.changes;
|
|
277
322
|
return count;
|
|
@@ -296,12 +341,12 @@ export class EngramStore {
|
|
|
296
341
|
if (!sanitized)
|
|
297
342
|
return [];
|
|
298
343
|
try {
|
|
299
|
-
const rows = this.db.prepare(`
|
|
300
|
-
SELECT e.*, rank FROM engrams e
|
|
301
|
-
JOIN engrams_fts ON e.rowid = engrams_fts.rowid
|
|
302
|
-
WHERE engrams_fts MATCH ? AND e.agent_id = ? AND e.retracted = 0
|
|
303
|
-
ORDER BY rank
|
|
304
|
-
LIMIT ?
|
|
344
|
+
const rows = this.db.prepare(`
|
|
345
|
+
SELECT e.*, rank FROM engrams e
|
|
346
|
+
JOIN engrams_fts ON e.rowid = engrams_fts.rowid
|
|
347
|
+
WHERE engrams_fts MATCH ? AND e.agent_id = ? AND e.retracted = 0
|
|
348
|
+
ORDER BY rank
|
|
349
|
+
LIMIT ?
|
|
305
350
|
`).all(sanitized, agentId, limit);
|
|
306
351
|
return rows.map(r => ({
|
|
307
352
|
engram: this.rowToEngram(r),
|
|
@@ -381,14 +426,14 @@ export class EngramStore {
|
|
|
381
426
|
sql += ' AND task_status = ?';
|
|
382
427
|
params.push(status);
|
|
383
428
|
}
|
|
384
|
-
sql += ` ORDER BY
|
|
385
|
-
CASE task_priority
|
|
386
|
-
WHEN 'urgent' THEN 0
|
|
387
|
-
WHEN 'high' THEN 1
|
|
388
|
-
WHEN 'medium' THEN 2
|
|
389
|
-
WHEN 'low' THEN 3
|
|
390
|
-
ELSE 4
|
|
391
|
-
END,
|
|
429
|
+
sql += ` ORDER BY
|
|
430
|
+
CASE task_priority
|
|
431
|
+
WHEN 'urgent' THEN 0
|
|
432
|
+
WHEN 'high' THEN 1
|
|
433
|
+
WHEN 'medium' THEN 2
|
|
434
|
+
WHEN 'low' THEN 3
|
|
435
|
+
ELSE 4
|
|
436
|
+
END,
|
|
392
437
|
created_at DESC`;
|
|
393
438
|
return this.db.prepare(sql).all(...params).map(r => this.rowToEngram(r));
|
|
394
439
|
}
|
|
@@ -396,20 +441,20 @@ export class EngramStore {
|
|
|
396
441
|
* Get the next actionable task — highest priority that's not blocked or done.
|
|
397
442
|
*/
|
|
398
443
|
getNextTask(agentId) {
|
|
399
|
-
const row = this.db.prepare(`
|
|
400
|
-
SELECT * FROM engrams
|
|
401
|
-
WHERE agent_id = ? AND task_status IN ('open', 'in_progress') AND retracted = 0
|
|
402
|
-
ORDER BY
|
|
403
|
-
CASE task_status WHEN 'in_progress' THEN 0 ELSE 1 END,
|
|
404
|
-
CASE task_priority
|
|
405
|
-
WHEN 'urgent' THEN 0
|
|
406
|
-
WHEN 'high' THEN 1
|
|
407
|
-
WHEN 'medium' THEN 2
|
|
408
|
-
WHEN 'low' THEN 3
|
|
409
|
-
ELSE 4
|
|
410
|
-
END,
|
|
411
|
-
created_at ASC
|
|
412
|
-
LIMIT 1
|
|
444
|
+
const row = this.db.prepare(`
|
|
445
|
+
SELECT * FROM engrams
|
|
446
|
+
WHERE agent_id = ? AND task_status IN ('open', 'in_progress') AND retracted = 0
|
|
447
|
+
ORDER BY
|
|
448
|
+
CASE task_status WHEN 'in_progress' THEN 0 ELSE 1 END,
|
|
449
|
+
CASE task_priority
|
|
450
|
+
WHEN 'urgent' THEN 0
|
|
451
|
+
WHEN 'high' THEN 1
|
|
452
|
+
WHEN 'medium' THEN 2
|
|
453
|
+
WHEN 'low' THEN 3
|
|
454
|
+
ELSE 4
|
|
455
|
+
END,
|
|
456
|
+
created_at ASC
|
|
457
|
+
LIMIT 1
|
|
413
458
|
`).get(agentId);
|
|
414
459
|
return row ? this.rowToEngram(row) : null;
|
|
415
460
|
}
|
|
@@ -432,15 +477,18 @@ export class EngramStore {
|
|
|
432
477
|
updateMemoryClass(id, memoryClass) {
|
|
433
478
|
this.db.prepare('UPDATE engrams SET memory_class = ? WHERE id = ?').run(memoryClass, id);
|
|
434
479
|
}
|
|
480
|
+
updateTags(id, tags) {
|
|
481
|
+
this.db.prepare('UPDATE engrams SET tags = ? WHERE id = ?').run(JSON.stringify(tags), id);
|
|
482
|
+
}
|
|
435
483
|
// --- Associations ---
|
|
436
484
|
upsertAssociation(fromId, toId, weight, type = 'hebbian', confidence = 0.5) {
|
|
437
485
|
const now = new Date().toISOString();
|
|
438
486
|
const id = randomUUID();
|
|
439
|
-
this.db.prepare(`
|
|
440
|
-
INSERT INTO associations (id, from_engram_id, to_engram_id, weight, confidence, type, activation_count, created_at, last_activated)
|
|
441
|
-
VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
442
|
-
ON CONFLICT(from_engram_id, to_engram_id) DO UPDATE SET
|
|
443
|
-
weight = ?, confidence = ?, last_activated = ?, activation_count = activation_count + 1
|
|
487
|
+
this.db.prepare(`
|
|
488
|
+
INSERT INTO associations (id, from_engram_id, to_engram_id, weight, confidence, type, activation_count, created_at, last_activated)
|
|
489
|
+
VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
490
|
+
ON CONFLICT(from_engram_id, to_engram_id) DO UPDATE SET
|
|
491
|
+
weight = ?, confidence = ?, last_activated = ?, activation_count = activation_count + 1
|
|
444
492
|
`).run(id, fromId, toId, weight, confidence, type, now, now, weight, confidence, now);
|
|
445
493
|
return this.getAssociation(fromId, toId);
|
|
446
494
|
}
|
|
@@ -468,22 +516,22 @@ export class EngramStore {
|
|
|
468
516
|
this.db.prepare('DELETE FROM associations WHERE id = ?').run(id);
|
|
469
517
|
}
|
|
470
518
|
getAllAssociations(agentId) {
|
|
471
|
-
const rows = this.db.prepare(`
|
|
472
|
-
SELECT a.* FROM associations a
|
|
473
|
-
JOIN engrams e ON a.from_engram_id = e.id
|
|
474
|
-
WHERE e.agent_id = ?
|
|
519
|
+
const rows = this.db.prepare(`
|
|
520
|
+
SELECT a.* FROM associations a
|
|
521
|
+
JOIN engrams e ON a.from_engram_id = e.id
|
|
522
|
+
WHERE e.agent_id = ?
|
|
475
523
|
`).all(agentId);
|
|
476
524
|
return rows.map(r => this.rowToAssociation(r));
|
|
477
525
|
}
|
|
478
526
|
// --- Eviction ---
|
|
479
527
|
getEvictionCandidates(agentId, limit) {
|
|
480
528
|
// Lowest combined score: low salience + low access + low confidence + oldest
|
|
481
|
-
const rows = this.db.prepare(`
|
|
482
|
-
SELECT * FROM engrams
|
|
483
|
-
WHERE agent_id = ? AND stage = 'active' AND retracted = 0
|
|
484
|
-
ORDER BY (salience * 0.3 + confidence * 0.3 + (CAST(access_count AS REAL) / (access_count + 5)) * 0.2 +
|
|
485
|
-
(1.0 / (1.0 + (julianday('now') - julianday(last_accessed)))) * 0.2) ASC
|
|
486
|
-
LIMIT ?
|
|
529
|
+
const rows = this.db.prepare(`
|
|
530
|
+
SELECT * FROM engrams
|
|
531
|
+
WHERE agent_id = ? AND stage = 'active' AND retracted = 0
|
|
532
|
+
ORDER BY (salience * 0.3 + confidence * 0.3 + (CAST(access_count AS REAL) / (access_count + 5)) * 0.2 +
|
|
533
|
+
(1.0 / (1.0 + (julianday('now') - julianday(last_accessed)))) * 0.2) ASC
|
|
534
|
+
LIMIT ?
|
|
487
535
|
`).all(agentId, limit);
|
|
488
536
|
return rows.map(r => this.rowToEngram(r));
|
|
489
537
|
}
|
|
@@ -498,8 +546,8 @@ export class EngramStore {
|
|
|
498
546
|
// --- Staging buffer ---
|
|
499
547
|
getExpiredStaging() {
|
|
500
548
|
const now = Date.now();
|
|
501
|
-
const rows = this.db.prepare(`
|
|
502
|
-
SELECT * FROM engrams WHERE stage = 'staging' AND ttl IS NOT NULL
|
|
549
|
+
const rows = this.db.prepare(`
|
|
550
|
+
SELECT * FROM engrams WHERE stage = 'staging' AND ttl IS NOT NULL
|
|
503
551
|
`).all();
|
|
504
552
|
return rows
|
|
505
553
|
.map(r => this.rowToEngram(r))
|
|
@@ -507,53 +555,53 @@ export class EngramStore {
|
|
|
507
555
|
}
|
|
508
556
|
// --- Eval event logging ---
|
|
509
557
|
logActivationEvent(event) {
|
|
510
|
-
this.db.prepare(`
|
|
511
|
-
INSERT INTO activation_events (id, agent_id, timestamp, context, results_returned, top_score, latency_ms, engram_ids)
|
|
512
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
558
|
+
this.db.prepare(`
|
|
559
|
+
INSERT INTO activation_events (id, agent_id, timestamp, context, results_returned, top_score, latency_ms, engram_ids)
|
|
560
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
513
561
|
`).run(event.id, event.agentId, event.timestamp.toISOString(), event.context, event.resultsReturned, event.topScore, event.latencyMs, JSON.stringify(event.engramIds));
|
|
514
562
|
}
|
|
515
563
|
logStagingEvent(event) {
|
|
516
|
-
this.db.prepare(`
|
|
517
|
-
INSERT INTO staging_events (engram_id, agent_id, action, resonance_score, timestamp, age_ms)
|
|
518
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
564
|
+
this.db.prepare(`
|
|
565
|
+
INSERT INTO staging_events (engram_id, agent_id, action, resonance_score, timestamp, age_ms)
|
|
566
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
519
567
|
`).run(event.engramId, event.agentId, event.action, event.resonanceScore, event.timestamp.toISOString(), event.ageMs);
|
|
520
568
|
}
|
|
521
569
|
logRetrievalFeedback(activationEventId, engramId, useful, context) {
|
|
522
|
-
this.db.prepare(`
|
|
523
|
-
INSERT INTO retrieval_feedback (id, activation_event_id, engram_id, useful, context, timestamp)
|
|
524
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
570
|
+
this.db.prepare(`
|
|
571
|
+
INSERT INTO retrieval_feedback (id, activation_event_id, engram_id, useful, context, timestamp)
|
|
572
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
525
573
|
`).run(randomUUID(), activationEventId, engramId, useful ? 1 : 0, context, new Date().toISOString());
|
|
526
574
|
}
|
|
527
575
|
// --- Eval metrics queries ---
|
|
528
576
|
getRetrievalPrecision(agentId, windowHours = 24) {
|
|
529
577
|
const since = new Date(Date.now() - windowHours * 3600_000).toISOString();
|
|
530
|
-
const row = this.db.prepare(`
|
|
531
|
-
SELECT
|
|
532
|
-
COUNT(CASE WHEN useful = 1 THEN 1 END) as useful_count,
|
|
533
|
-
COUNT(*) as total_count
|
|
534
|
-
FROM retrieval_feedback rf
|
|
535
|
-
LEFT JOIN activation_events ae ON rf.activation_event_id = ae.id
|
|
536
|
-
JOIN engrams e ON rf.engram_id = e.id
|
|
537
|
-
WHERE e.agent_id = ? AND rf.timestamp > ?
|
|
578
|
+
const row = this.db.prepare(`
|
|
579
|
+
SELECT
|
|
580
|
+
COUNT(CASE WHEN useful = 1 THEN 1 END) as useful_count,
|
|
581
|
+
COUNT(*) as total_count
|
|
582
|
+
FROM retrieval_feedback rf
|
|
583
|
+
LEFT JOIN activation_events ae ON rf.activation_event_id = ae.id
|
|
584
|
+
JOIN engrams e ON rf.engram_id = e.id
|
|
585
|
+
WHERE e.agent_id = ? AND rf.timestamp > ?
|
|
538
586
|
`).get(agentId, since);
|
|
539
587
|
return row.total_count > 0 ? row.useful_count / row.total_count : 0;
|
|
540
588
|
}
|
|
541
589
|
getStagingMetrics(agentId) {
|
|
542
|
-
const row = this.db.prepare(`
|
|
543
|
-
SELECT
|
|
544
|
-
COUNT(CASE WHEN action = 'promoted' THEN 1 END) as promoted,
|
|
545
|
-
COUNT(CASE WHEN action = 'discarded' THEN 1 END) as discarded,
|
|
546
|
-
COUNT(CASE WHEN action = 'expired' THEN 1 END) as expired
|
|
547
|
-
FROM staging_events WHERE agent_id = ?
|
|
590
|
+
const row = this.db.prepare(`
|
|
591
|
+
SELECT
|
|
592
|
+
COUNT(CASE WHEN action = 'promoted' THEN 1 END) as promoted,
|
|
593
|
+
COUNT(CASE WHEN action = 'discarded' THEN 1 END) as discarded,
|
|
594
|
+
COUNT(CASE WHEN action = 'expired' THEN 1 END) as expired
|
|
595
|
+
FROM staging_events WHERE agent_id = ?
|
|
548
596
|
`).get(agentId);
|
|
549
597
|
return { promoted: row.promoted, discarded: row.discarded, expired: row.expired };
|
|
550
598
|
}
|
|
551
599
|
getActivationStats(agentId, windowHours = 24) {
|
|
552
600
|
const since = new Date(Date.now() - windowHours * 3600_000).toISOString();
|
|
553
|
-
const rows = this.db.prepare(`
|
|
554
|
-
SELECT latency_ms FROM activation_events
|
|
555
|
-
WHERE agent_id = ? AND timestamp > ?
|
|
556
|
-
ORDER BY latency_ms ASC
|
|
601
|
+
const rows = this.db.prepare(`
|
|
602
|
+
SELECT latency_ms FROM activation_events
|
|
603
|
+
WHERE agent_id = ? AND timestamp > ?
|
|
604
|
+
ORDER BY latency_ms ASC
|
|
557
605
|
`).all(agentId, since);
|
|
558
606
|
if (rows.length === 0)
|
|
559
607
|
return { count: 0, avgLatencyMs: 0, p95LatencyMs: 0 };
|
|
@@ -594,6 +642,7 @@ export class EngramStore {
|
|
|
594
642
|
tags: JSON.parse(row.tags),
|
|
595
643
|
episodeId: row.episode_id ?? null,
|
|
596
644
|
memoryClass: (row.memory_class ?? 'working'),
|
|
645
|
+
memoryType: (row.memory_type ?? 'unclassified'),
|
|
597
646
|
supersededBy: row.superseded_by ?? null,
|
|
598
647
|
supersedes: row.supersedes ?? null,
|
|
599
648
|
taskStatus: row.task_status ?? null,
|
|
@@ -621,9 +670,9 @@ export class EngramStore {
|
|
|
621
670
|
const embeddingBlob = input.embedding
|
|
622
671
|
? Buffer.from(new Float32Array(input.embedding).buffer)
|
|
623
672
|
: null;
|
|
624
|
-
this.db.prepare(`
|
|
625
|
-
INSERT INTO episodes (id, agent_id, label, embedding, engram_count, start_time, end_time, created_at)
|
|
626
|
-
VALUES (?, ?, ?, ?, 0, ?, ?, ?)
|
|
673
|
+
this.db.prepare(`
|
|
674
|
+
INSERT INTO episodes (id, agent_id, label, embedding, engram_count, start_time, end_time, created_at)
|
|
675
|
+
VALUES (?, ?, ?, ?, 0, ?, ?, ?)
|
|
627
676
|
`).run(id, input.agentId, input.label, embeddingBlob, now, now, now);
|
|
628
677
|
return this.getEpisode(id);
|
|
629
678
|
}
|
|
@@ -638,19 +687,19 @@ export class EngramStore {
|
|
|
638
687
|
getActiveEpisode(agentId, windowMs = 3600_000) {
|
|
639
688
|
// Find most recent episode that ended within the time window
|
|
640
689
|
const cutoff = new Date(Date.now() - windowMs).toISOString();
|
|
641
|
-
const row = this.db.prepare(`
|
|
642
|
-
SELECT * FROM episodes WHERE agent_id = ? AND end_time > ?
|
|
643
|
-
ORDER BY end_time DESC LIMIT 1
|
|
690
|
+
const row = this.db.prepare(`
|
|
691
|
+
SELECT * FROM episodes WHERE agent_id = ? AND end_time > ?
|
|
692
|
+
ORDER BY end_time DESC LIMIT 1
|
|
644
693
|
`).get(agentId, cutoff);
|
|
645
694
|
return row ? this.rowToEpisode(row) : null;
|
|
646
695
|
}
|
|
647
696
|
addEngramToEpisode(engramId, episodeId) {
|
|
648
697
|
this.db.prepare('UPDATE engrams SET episode_id = ? WHERE id = ?').run(episodeId, engramId);
|
|
649
|
-
this.db.prepare(`
|
|
650
|
-
UPDATE episodes SET
|
|
651
|
-
engram_count = engram_count + 1,
|
|
652
|
-
end_time = MAX(end_time, ?)
|
|
653
|
-
WHERE id = ?
|
|
698
|
+
this.db.prepare(`
|
|
699
|
+
UPDATE episodes SET
|
|
700
|
+
engram_count = engram_count + 1,
|
|
701
|
+
end_time = MAX(end_time, ?)
|
|
702
|
+
WHERE id = ?
|
|
654
703
|
`).run(new Date().toISOString(), episodeId);
|
|
655
704
|
}
|
|
656
705
|
getEngramsByEpisode(episodeId) {
|
|
@@ -701,49 +750,49 @@ export class EngramStore {
|
|
|
701
750
|
// --- Checkpointing ---
|
|
702
751
|
updateAutoCheckpointWrite(agentId, engramId) {
|
|
703
752
|
const now = new Date().toISOString();
|
|
704
|
-
this.db.prepare(`
|
|
705
|
-
INSERT INTO conscious_state (agent_id, last_write_id, last_activity_at, write_count_since_consolidation, updated_at)
|
|
706
|
-
VALUES (?, ?, ?, 1, ?)
|
|
707
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
708
|
-
last_write_id = excluded.last_write_id,
|
|
709
|
-
last_activity_at = excluded.last_activity_at,
|
|
710
|
-
write_count_since_consolidation = write_count_since_consolidation + 1,
|
|
711
|
-
updated_at = excluded.updated_at
|
|
753
|
+
this.db.prepare(`
|
|
754
|
+
INSERT INTO conscious_state (agent_id, last_write_id, last_activity_at, write_count_since_consolidation, updated_at)
|
|
755
|
+
VALUES (?, ?, ?, 1, ?)
|
|
756
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
757
|
+
last_write_id = excluded.last_write_id,
|
|
758
|
+
last_activity_at = excluded.last_activity_at,
|
|
759
|
+
write_count_since_consolidation = write_count_since_consolidation + 1,
|
|
760
|
+
updated_at = excluded.updated_at
|
|
712
761
|
`).run(agentId, engramId, now, now);
|
|
713
762
|
}
|
|
714
763
|
updateAutoCheckpointRecall(agentId, context, engramIds) {
|
|
715
764
|
const now = new Date().toISOString();
|
|
716
|
-
this.db.prepare(`
|
|
717
|
-
INSERT INTO conscious_state (agent_id, last_recall_context, last_recall_ids, last_activity_at, recall_count_since_consolidation, updated_at)
|
|
718
|
-
VALUES (?, ?, ?, ?, 1, ?)
|
|
719
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
720
|
-
last_recall_context = excluded.last_recall_context,
|
|
721
|
-
last_recall_ids = excluded.last_recall_ids,
|
|
722
|
-
last_activity_at = excluded.last_activity_at,
|
|
723
|
-
recall_count_since_consolidation = recall_count_since_consolidation + 1,
|
|
724
|
-
updated_at = excluded.updated_at
|
|
765
|
+
this.db.prepare(`
|
|
766
|
+
INSERT INTO conscious_state (agent_id, last_recall_context, last_recall_ids, last_activity_at, recall_count_since_consolidation, updated_at)
|
|
767
|
+
VALUES (?, ?, ?, ?, 1, ?)
|
|
768
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
769
|
+
last_recall_context = excluded.last_recall_context,
|
|
770
|
+
last_recall_ids = excluded.last_recall_ids,
|
|
771
|
+
last_activity_at = excluded.last_activity_at,
|
|
772
|
+
recall_count_since_consolidation = recall_count_since_consolidation + 1,
|
|
773
|
+
updated_at = excluded.updated_at
|
|
725
774
|
`).run(agentId, context, JSON.stringify(engramIds), now, now);
|
|
726
775
|
}
|
|
727
776
|
touchActivity(agentId) {
|
|
728
777
|
const now = new Date().toISOString();
|
|
729
|
-
this.db.prepare(`
|
|
730
|
-
INSERT INTO conscious_state (agent_id, last_activity_at, updated_at)
|
|
731
|
-
VALUES (?, ?, ?)
|
|
732
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
733
|
-
last_activity_at = excluded.last_activity_at,
|
|
734
|
-
updated_at = excluded.updated_at
|
|
778
|
+
this.db.prepare(`
|
|
779
|
+
INSERT INTO conscious_state (agent_id, last_activity_at, updated_at)
|
|
780
|
+
VALUES (?, ?, ?)
|
|
781
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
782
|
+
last_activity_at = excluded.last_activity_at,
|
|
783
|
+
updated_at = excluded.updated_at
|
|
735
784
|
`).run(agentId, now, now);
|
|
736
785
|
}
|
|
737
786
|
saveCheckpoint(agentId, state) {
|
|
738
787
|
const now = new Date().toISOString();
|
|
739
|
-
this.db.prepare(`
|
|
740
|
-
INSERT INTO conscious_state (agent_id, execution_state, checkpoint_at, last_activity_at, updated_at)
|
|
741
|
-
VALUES (?, ?, ?, ?, ?)
|
|
742
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
743
|
-
execution_state = excluded.execution_state,
|
|
744
|
-
checkpoint_at = excluded.checkpoint_at,
|
|
745
|
-
last_activity_at = excluded.last_activity_at,
|
|
746
|
-
updated_at = excluded.updated_at
|
|
788
|
+
this.db.prepare(`
|
|
789
|
+
INSERT INTO conscious_state (agent_id, execution_state, checkpoint_at, last_activity_at, updated_at)
|
|
790
|
+
VALUES (?, ?, ?, ?, ?)
|
|
791
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
792
|
+
execution_state = excluded.execution_state,
|
|
793
|
+
checkpoint_at = excluded.checkpoint_at,
|
|
794
|
+
last_activity_at = excluded.last_activity_at,
|
|
795
|
+
updated_at = excluded.updated_at
|
|
747
796
|
`).run(agentId, JSON.stringify(state), now, now, now);
|
|
748
797
|
}
|
|
749
798
|
getCheckpoint(agentId) {
|
|
@@ -770,20 +819,20 @@ export class EngramStore {
|
|
|
770
819
|
markConsolidation(agentId, mini) {
|
|
771
820
|
const now = new Date().toISOString();
|
|
772
821
|
if (mini) {
|
|
773
|
-
this.db.prepare(`
|
|
774
|
-
UPDATE conscious_state SET last_mini_consolidation_at = ?, updated_at = ? WHERE agent_id = ?
|
|
822
|
+
this.db.prepare(`
|
|
823
|
+
UPDATE conscious_state SET last_mini_consolidation_at = ?, updated_at = ? WHERE agent_id = ?
|
|
775
824
|
`).run(now, now, agentId);
|
|
776
825
|
}
|
|
777
826
|
else {
|
|
778
|
-
this.db.prepare(`
|
|
779
|
-
UPDATE conscious_state SET
|
|
780
|
-
last_consolidation_at = ?,
|
|
781
|
-
last_mini_consolidation_at = ?,
|
|
782
|
-
write_count_since_consolidation = 0,
|
|
783
|
-
recall_count_since_consolidation = 0,
|
|
784
|
-
consolidation_cycle_count = consolidation_cycle_count + 1,
|
|
785
|
-
updated_at = ?
|
|
786
|
-
WHERE agent_id = ?
|
|
827
|
+
this.db.prepare(`
|
|
828
|
+
UPDATE conscious_state SET
|
|
829
|
+
last_consolidation_at = ?,
|
|
830
|
+
last_mini_consolidation_at = ?,
|
|
831
|
+
write_count_since_consolidation = 0,
|
|
832
|
+
recall_count_since_consolidation = 0,
|
|
833
|
+
consolidation_cycle_count = consolidation_cycle_count + 1,
|
|
834
|
+
updated_at = ?
|
|
835
|
+
WHERE agent_id = ?
|
|
787
836
|
`).run(now, now, now, agentId);
|
|
788
837
|
}
|
|
789
838
|
}
|