agent-working-memory 0.10.0 → 0.12.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 +118 -19
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +63 -3
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/common.d.ts.map +1 -1
- package/dist/adapters/common.js +329 -302
- package/dist/adapters/common.js.map +1 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +31 -8
- package/dist/api/routes.js.map +1 -1
- package/dist/cli/migrate.js +29 -29
- package/dist/cli.js +82 -2
- package/dist/cli.js.map +1 -1
- package/dist/coordination/circuit-breaker.js +23 -23
- package/dist/coordination/routes.d.ts.map +1 -1
- package/dist/coordination/routes.js +174 -170
- package/dist/coordination/routes.js.map +1 -1
- package/dist/core/embeddings.d.ts.map +1 -1
- package/dist/core/embeddings.js +3 -0
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/entity-extract.d.ts +3 -0
- package/dist/core/entity-extract.d.ts.map +1 -0
- package/dist/core/entity-extract.js +47 -0
- package/dist/core/entity-extract.js.map +1 -0
- package/dist/core/salience.d.ts.map +1 -1
- package/dist/core/salience.js +14 -2
- package/dist/core/salience.js.map +1 -1
- package/dist/core/whoami.d.ts +24 -0
- package/dist/core/whoami.d.ts.map +1 -0
- package/dist/core/whoami.js +66 -0
- package/dist/core/whoami.js.map +1 -0
- package/dist/core/write-pipeline.d.ts +9 -0
- package/dist/core/write-pipeline.d.ts.map +1 -1
- package/dist/core/write-pipeline.js +109 -68
- package/dist/core/write-pipeline.js.map +1 -1
- package/dist/core/write-telemetry.d.ts +33 -0
- package/dist/core/write-telemetry.d.ts.map +1 -0
- package/dist/core/write-telemetry.js +110 -0
- package/dist/core/write-telemetry.js.map +1 -0
- package/dist/engine/activation.d.ts +22 -12
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +133 -17
- package/dist/engine/activation.js.map +1 -1
- package/dist/engine/consolidation-scheduler.d.ts +1 -1
- package/dist/engine/consolidation-scheduler.js +1 -1
- package/dist/engine/consolidation.d.ts +1 -0
- package/dist/engine/consolidation.d.ts.map +1 -1
- package/dist/engine/consolidation.js +18 -0
- package/dist/engine/consolidation.js.map +1 -1
- package/dist/engine/eval.d.ts.map +1 -1
- package/dist/engine/eval.js +5 -1
- package/dist/engine/eval.js.map +1 -1
- package/dist/index.js +21 -2
- 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 +212 -97
- package/dist/mcp.js.map +1 -1
- package/dist/onboard/index.d.ts +68 -0
- package/dist/onboard/index.d.ts.map +1 -0
- package/dist/onboard/index.js +265 -0
- package/dist/onboard/index.js.map +1 -0
- package/dist/recipes/index.d.ts +57 -0
- package/dist/recipes/index.d.ts.map +1 -0
- package/dist/recipes/index.js +81 -0
- package/dist/recipes/index.js.map +1 -0
- package/dist/storage/pglite-schema.d.ts.map +1 -1
- package/dist/storage/pglite-schema.js +170 -143
- package/dist/storage/pglite-schema.js.map +1 -1
- package/dist/storage/pglite.d.ts +5 -0
- package/dist/storage/pglite.d.ts.map +1 -1
- package/dist/storage/pglite.js +180 -138
- package/dist/storage/pglite.js.map +1 -1
- package/dist/storage/postgres.d.ts +5 -0
- package/dist/storage/postgres.d.ts.map +1 -1
- package/dist/storage/postgres.js +44 -2
- package/dist/storage/postgres.js.map +1 -1
- package/dist/storage/sqlite.d.ts +9 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +394 -326
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/types/engram.d.ts +14 -0
- package/dist/types/engram.d.ts.map +1 -1
- package/dist/types/engram.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +27 -0
- package/dist/version.js.map +1 -0
- package/package.json +9 -1
- package/src/adapters/claude-code.ts +66 -3
- package/src/adapters/common.ts +538 -511
- package/src/api/index.ts +3 -3
- package/src/api/routes.ts +999 -970
- package/src/cli/migrate.ts +307 -307
- package/src/cli.ts +77 -2
- package/src/coordination/circuit-breaker.ts +83 -83
- package/src/coordination/failure-modes.ts +50 -50
- package/src/coordination/routes.ts +2155 -2150
- package/src/core/decay.ts +63 -63
- package/src/core/embeddings.ts +113 -110
- package/src/core/entity-extract.ts +47 -0
- package/src/core/index.ts +5 -5
- package/src/core/logger.ts +36 -36
- package/src/core/ml-worker-entry.ts +194 -194
- package/src/core/ml-worker.ts +281 -281
- package/src/core/query-expander.ts +122 -122
- package/src/core/reranker.ts +119 -119
- package/src/core/salience.ts +529 -514
- package/src/core/whoami.ts +92 -0
- package/src/core/write-pipeline.ts +60 -8
- package/src/core/write-telemetry.ts +131 -0
- package/src/engine/activation.ts +1468 -1369
- package/src/engine/confidence.ts +120 -120
- package/src/engine/consolidation-scheduler.ts +242 -242
- package/src/engine/consolidation.ts +887 -869
- package/src/engine/eval.ts +107 -102
- package/src/engine/eviction.ts +101 -101
- package/src/engine/index.ts +8 -8
- package/src/engine/retraction.ts +366 -366
- package/src/engine/staging.ts +74 -74
- package/src/index.ts +248 -226
- package/src/mcp.ts +1341 -1211
- package/src/onboard/index.ts +298 -0
- package/src/recipes/index.ts +125 -0
- package/src/storage/index.ts +3 -3
- package/src/storage/pglite-schema.ts +193 -166
- package/src/storage/pglite.ts +1420 -1372
- package/src/storage/postgres.ts +50 -2
- package/src/storage/sqlite.ts +1936 -1861
- package/src/storage/store.ts +80 -80
- package/src/types/agent.ts +67 -67
- package/src/types/checkpoint.ts +46 -46
- package/src/types/engram.ts +22 -0
- package/src/types/eval.ts +100 -100
- package/src/types/index.ts +6 -6
- package/src/version.ts +26 -0
package/dist/storage/pglite.js
CHANGED
|
@@ -92,6 +92,11 @@ function rowToEngram(row) {
|
|
|
92
92
|
blockedBy: row.blocked_by ?? null,
|
|
93
93
|
sequence: row.sequence == null ? null : Number(row.sequence),
|
|
94
94
|
references: row.references_json ? JSON.parse(row.references_json) : null,
|
|
95
|
+
originClass: row.origin_class ?? null,
|
|
96
|
+
writerSession: row.writer_session ?? null,
|
|
97
|
+
recipeId: row.recipe_id ?? null,
|
|
98
|
+
validFrom: row.valid_from ?? null,
|
|
99
|
+
validTo: row.valid_to ?? null,
|
|
95
100
|
};
|
|
96
101
|
}
|
|
97
102
|
function rowToAssociation(row) {
|
|
@@ -185,7 +190,7 @@ export class PGliteEngramStore {
|
|
|
185
190
|
params.push(e.id, e.agentId, e.timestamp.toISOString(), e.context, e.resultsReturned, e.topScore, e.latencyMs, JSON.stringify(e.engramIds));
|
|
186
191
|
}
|
|
187
192
|
try {
|
|
188
|
-
await this.db.query(`INSERT INTO activation_events (id, agent_id, timestamp, context, results_returned, top_score, latency_ms, engram_ids)
|
|
193
|
+
await this.db.query(`INSERT INTO activation_events (id, agent_id, timestamp, context, results_returned, top_score, latency_ms, engram_ids)
|
|
189
194
|
VALUES ${values.join(',')}`, params);
|
|
190
195
|
}
|
|
191
196
|
catch {
|
|
@@ -223,18 +228,20 @@ export class PGliteEngramStore {
|
|
|
223
228
|
await this.readyPromise;
|
|
224
229
|
const id = input.id ?? randomUUID();
|
|
225
230
|
const now = new Date().toISOString();
|
|
226
|
-
await this.db.query(`INSERT INTO engrams (
|
|
227
|
-
id, agent_id, concept, content, embedding, embedding_model,
|
|
228
|
-
confidence, salience, access_count, last_accessed, created_at,
|
|
229
|
-
salience_features, reason_codes, stage, ttl, retracted,
|
|
230
|
-
tags, memory_type, memory_class, supersedes, episode_id,
|
|
231
|
-
task_status, task_priority, blocked_by, sequence, references_json
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
$
|
|
235
|
-
$
|
|
236
|
-
$
|
|
237
|
-
$
|
|
231
|
+
await this.db.query(`INSERT INTO engrams (
|
|
232
|
+
id, agent_id, concept, content, embedding, embedding_model,
|
|
233
|
+
confidence, salience, access_count, last_accessed, created_at,
|
|
234
|
+
salience_features, reason_codes, stage, ttl, retracted,
|
|
235
|
+
tags, memory_type, memory_class, supersedes, episode_id,
|
|
236
|
+
task_status, task_priority, blocked_by, sequence, references_json,
|
|
237
|
+
origin_class, writer_session, recipe_id, valid_from, valid_to
|
|
238
|
+
) VALUES (
|
|
239
|
+
$1, $2, $3, $4, $5::vector, $6,
|
|
240
|
+
$7, $8, 0, $9, $10,
|
|
241
|
+
$11, $12, 'active', $13, FALSE,
|
|
242
|
+
$14, $15, $16, $17, $18,
|
|
243
|
+
$19, $20, $21, $22, $23,
|
|
244
|
+
$24, $25, $26, $27, $28
|
|
238
245
|
)`, [
|
|
239
246
|
id,
|
|
240
247
|
input.agentId,
|
|
@@ -259,6 +266,11 @@ export class PGliteEngramStore {
|
|
|
259
266
|
input.sequence ?? null,
|
|
260
267
|
input.references && input.references.length > 0
|
|
261
268
|
? JSON.stringify(input.references) : null,
|
|
269
|
+
input.originClass ?? null,
|
|
270
|
+
input.writerSession ?? null,
|
|
271
|
+
input.recipeId ?? null,
|
|
272
|
+
input.validFrom ?? null,
|
|
273
|
+
input.validTo ?? null,
|
|
262
274
|
]);
|
|
263
275
|
const row = await this.getEngram(id);
|
|
264
276
|
if (!row)
|
|
@@ -370,10 +382,10 @@ export class PGliteEngramStore {
|
|
|
370
382
|
}
|
|
371
383
|
async touchEngram(id) {
|
|
372
384
|
await this.readyPromise;
|
|
373
|
-
await this.db.query(`UPDATE engrams
|
|
374
|
-
SET access_count = access_count + 1,
|
|
375
|
-
last_accessed = $1,
|
|
376
|
-
confidence = LEAST(0.85, confidence + 0.02 / (1.0 + sqrt(access_count::float)))
|
|
385
|
+
await this.db.query(`UPDATE engrams
|
|
386
|
+
SET access_count = access_count + 1,
|
|
387
|
+
last_accessed = $1,
|
|
388
|
+
confidence = LEAST(0.85, confidence + 0.02 / (1.0 + sqrt(access_count::float)))
|
|
377
389
|
WHERE id = $2`, [new Date().toISOString(), id]);
|
|
378
390
|
}
|
|
379
391
|
async updateStage(id, stage) {
|
|
@@ -419,9 +431,9 @@ export class PGliteEngramStore {
|
|
|
419
431
|
async timeWarp(agentId, ms) {
|
|
420
432
|
await this.readyPromise;
|
|
421
433
|
const seconds = Math.round(ms / 1000);
|
|
422
|
-
const r1 = await this.db.query(`UPDATE engrams SET
|
|
423
|
-
created_at = to_char(($1::timestamptz - interval '1 second' * $2), 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'),
|
|
424
|
-
last_accessed = to_char(($3::timestamptz - interval '1 second' * $2), 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
|
|
434
|
+
const r1 = await this.db.query(`UPDATE engrams SET
|
|
435
|
+
created_at = to_char(($1::timestamptz - interval '1 second' * $2), 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'),
|
|
436
|
+
last_accessed = to_char(($3::timestamptz - interval '1 second' * $2), 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
|
|
425
437
|
WHERE agent_id = $4`, ['now', seconds, 'now', agentId]);
|
|
426
438
|
// Simpler: just update with relative arithmetic on stored ISO strings.
|
|
427
439
|
// PGlite doesn't support all date ops cleanly; fall through to JS-side calculation.
|
|
@@ -447,13 +459,13 @@ export class PGliteEngramStore {
|
|
|
447
459
|
// Restrict to active + fading. Faded engrams (Paper 1: storage degradation)
|
|
448
460
|
// retain their embedding so they still participate in semantic recall, even
|
|
449
461
|
// though their content has been trimmed. Excludes staging/consolidated/archived.
|
|
450
|
-
const result = await this.db.query(`SELECT *, (embedding <=> $2::vector) AS distance
|
|
451
|
-
FROM engrams
|
|
452
|
-
WHERE agent_id = $1
|
|
453
|
-
AND embedding IS NOT NULL
|
|
454
|
-
AND retracted = FALSE
|
|
455
|
-
AND stage IN ('active', 'fading')
|
|
456
|
-
ORDER BY distance ASC
|
|
462
|
+
const result = await this.db.query(`SELECT *, (embedding <=> $2::vector) AS distance
|
|
463
|
+
FROM engrams
|
|
464
|
+
WHERE agent_id = $1
|
|
465
|
+
AND embedding IS NOT NULL
|
|
466
|
+
AND retracted = FALSE
|
|
467
|
+
AND stage IN ('active', 'fading')
|
|
468
|
+
ORDER BY distance ASC
|
|
457
469
|
LIMIT $3`, [agentId, vectorToLiteral(vec), limit]);
|
|
458
470
|
return result.rows.map((r) => ({ engram: rowToEngram(r), distance: r.distance }));
|
|
459
471
|
}
|
|
@@ -472,11 +484,11 @@ export class PGliteEngramStore {
|
|
|
472
484
|
if (tokens.length === 0)
|
|
473
485
|
return [];
|
|
474
486
|
const websearchQuery = tokens.join(' OR ');
|
|
475
|
-
const result = await this.db.query(`SELECT *, ts_rank_cd(fts, websearch_to_tsquery('english', $2)) AS rank
|
|
476
|
-
FROM engrams
|
|
477
|
-
WHERE agent_id = $1 AND retracted = FALSE
|
|
478
|
-
AND fts @@ websearch_to_tsquery('english', $2)
|
|
479
|
-
ORDER BY rank DESC
|
|
487
|
+
const result = await this.db.query(`SELECT *, ts_rank_cd(fts, websearch_to_tsquery('english', $2)) AS rank
|
|
488
|
+
FROM engrams
|
|
489
|
+
WHERE agent_id = $1 AND retracted = FALSE
|
|
490
|
+
AND fts @@ websearch_to_tsquery('english', $2)
|
|
491
|
+
ORDER BY rank DESC
|
|
480
492
|
LIMIT $3`, [agentId, websearchQuery, limit]);
|
|
481
493
|
return result.rows.map((r) => ({ engram: rowToEngram(r), bm25Score: calibrateBm25(Number(r.rank)) }));
|
|
482
494
|
}
|
|
@@ -490,11 +502,11 @@ export class PGliteEngramStore {
|
|
|
490
502
|
if (tokens.length === 0)
|
|
491
503
|
return [];
|
|
492
504
|
const websearchQuery = tokens.join(' OR ');
|
|
493
|
-
const result = await this.db.query(`SELECT *, ts_rank_cd(fts, websearch_to_tsquery('english', $2)) AS rank
|
|
494
|
-
FROM engrams
|
|
495
|
-
WHERE agent_id = ANY($1::text[]) AND retracted = FALSE
|
|
496
|
-
AND fts @@ websearch_to_tsquery('english', $2)
|
|
497
|
-
ORDER BY rank DESC
|
|
505
|
+
const result = await this.db.query(`SELECT *, ts_rank_cd(fts, websearch_to_tsquery('english', $2)) AS rank
|
|
506
|
+
FROM engrams
|
|
507
|
+
WHERE agent_id = ANY($1::text[]) AND retracted = FALSE
|
|
508
|
+
AND fts @@ websearch_to_tsquery('english', $2)
|
|
509
|
+
ORDER BY rank DESC
|
|
498
510
|
LIMIT $3`, [agentIds, websearchQuery, limit]);
|
|
499
511
|
return result.rows.map((r) => ({ engram: rowToEngram(r), bm25Score: calibrateBm25(Number(r.rank)) }));
|
|
500
512
|
}
|
|
@@ -575,32 +587,32 @@ export class PGliteEngramStore {
|
|
|
575
587
|
sql += ` AND task_status = $${params.length + 1}`;
|
|
576
588
|
params.push(status);
|
|
577
589
|
}
|
|
578
|
-
sql += ` ORDER BY
|
|
579
|
-
CASE task_priority
|
|
580
|
-
WHEN 'urgent' THEN 0
|
|
581
|
-
WHEN 'high' THEN 1
|
|
582
|
-
WHEN 'medium' THEN 2
|
|
583
|
-
WHEN 'low' THEN 3
|
|
584
|
-
ELSE 4
|
|
585
|
-
END,
|
|
590
|
+
sql += ` ORDER BY
|
|
591
|
+
CASE task_priority
|
|
592
|
+
WHEN 'urgent' THEN 0
|
|
593
|
+
WHEN 'high' THEN 1
|
|
594
|
+
WHEN 'medium' THEN 2
|
|
595
|
+
WHEN 'low' THEN 3
|
|
596
|
+
ELSE 4
|
|
597
|
+
END,
|
|
586
598
|
created_at DESC`;
|
|
587
599
|
const result = await this.db.query(sql, params);
|
|
588
600
|
return result.rows.map(rowToEngram);
|
|
589
601
|
}
|
|
590
602
|
async getNextTask(agentId) {
|
|
591
603
|
await this.readyPromise;
|
|
592
|
-
const result = await this.db.query(`SELECT * FROM engrams
|
|
593
|
-
WHERE agent_id = $1 AND task_status IN ('open', 'in_progress') AND retracted = FALSE
|
|
594
|
-
ORDER BY
|
|
595
|
-
CASE task_status WHEN 'in_progress' THEN 0 ELSE 1 END,
|
|
596
|
-
CASE task_priority
|
|
597
|
-
WHEN 'urgent' THEN 0
|
|
598
|
-
WHEN 'high' THEN 1
|
|
599
|
-
WHEN 'medium' THEN 2
|
|
600
|
-
WHEN 'low' THEN 3
|
|
601
|
-
ELSE 4
|
|
602
|
-
END,
|
|
603
|
-
created_at ASC
|
|
604
|
+
const result = await this.db.query(`SELECT * FROM engrams
|
|
605
|
+
WHERE agent_id = $1 AND task_status IN ('open', 'in_progress') AND retracted = FALSE
|
|
606
|
+
ORDER BY
|
|
607
|
+
CASE task_status WHEN 'in_progress' THEN 0 ELSE 1 END,
|
|
608
|
+
CASE task_priority
|
|
609
|
+
WHEN 'urgent' THEN 0
|
|
610
|
+
WHEN 'high' THEN 1
|
|
611
|
+
WHEN 'medium' THEN 2
|
|
612
|
+
WHEN 'low' THEN 3
|
|
613
|
+
ELSE 4
|
|
614
|
+
END,
|
|
615
|
+
created_at ASC
|
|
604
616
|
LIMIT 1`, [agentId]);
|
|
605
617
|
return result.rows.length > 0 ? rowToEngram(result.rows[0]) : null;
|
|
606
618
|
}
|
|
@@ -614,11 +626,11 @@ export class PGliteEngramStore {
|
|
|
614
626
|
}
|
|
615
627
|
async findActiveMatchByConcept(agentId, concept, requiredTags) {
|
|
616
628
|
await this.readyPromise;
|
|
617
|
-
let sql = `SELECT * FROM engrams
|
|
618
|
-
WHERE agent_id = $1
|
|
619
|
-
AND LOWER(TRIM(concept)) = LOWER(TRIM($2))
|
|
620
|
-
AND stage = 'active'
|
|
621
|
-
AND retracted = FALSE
|
|
629
|
+
let sql = `SELECT * FROM engrams
|
|
630
|
+
WHERE agent_id = $1
|
|
631
|
+
AND LOWER(TRIM(concept)) = LOWER(TRIM($2))
|
|
632
|
+
AND stage = 'active'
|
|
633
|
+
AND retracted = FALSE
|
|
622
634
|
AND superseded_by IS NULL`;
|
|
623
635
|
const params = [agentId, concept];
|
|
624
636
|
if (requiredTags && requiredTags.length > 0) {
|
|
@@ -651,12 +663,12 @@ export class PGliteEngramStore {
|
|
|
651
663
|
await this.readyPromise;
|
|
652
664
|
const id = randomUUID();
|
|
653
665
|
const now = new Date().toISOString();
|
|
654
|
-
await this.db.query(`INSERT INTO associations (id, from_engram_id, to_engram_id, weight, confidence, type, activation_count, created_at, last_activated)
|
|
655
|
-
VALUES ($1, $2, $3, $4, $5, $6, 0, $7, $7)
|
|
656
|
-
ON CONFLICT (from_engram_id, to_engram_id) DO UPDATE SET
|
|
657
|
-
weight = EXCLUDED.weight,
|
|
658
|
-
confidence = EXCLUDED.confidence,
|
|
659
|
-
last_activated = EXCLUDED.last_activated,
|
|
666
|
+
await this.db.query(`INSERT INTO associations (id, from_engram_id, to_engram_id, weight, confidence, type, activation_count, created_at, last_activated)
|
|
667
|
+
VALUES ($1, $2, $3, $4, $5, $6, 0, $7, $7)
|
|
668
|
+
ON CONFLICT (from_engram_id, to_engram_id) DO UPDATE SET
|
|
669
|
+
weight = EXCLUDED.weight,
|
|
670
|
+
confidence = EXCLUDED.confidence,
|
|
671
|
+
last_activated = EXCLUDED.last_activated,
|
|
660
672
|
activation_count = associations.activation_count + 1`, [id, fromId, toId, weight, confidence, type, now]);
|
|
661
673
|
const assoc = await this.getAssociation(fromId, toId);
|
|
662
674
|
if (!assoc)
|
|
@@ -678,12 +690,12 @@ export class PGliteEngramStore {
|
|
|
678
690
|
if (engramIds.length === 0)
|
|
679
691
|
return result;
|
|
680
692
|
await this.readyPromise;
|
|
681
|
-
const r = await this.db.query(`SELECT id, SUM(cnt) AS count, SUM(sw) AS sum_weight FROM (
|
|
682
|
-
SELECT from_engram_id AS id, 1 AS cnt, weight AS sw FROM associations WHERE from_engram_id = ANY($1::text[])
|
|
683
|
-
UNION ALL
|
|
684
|
-
SELECT to_engram_id AS id, 1 AS cnt, weight AS sw FROM associations WHERE to_engram_id = ANY($1::text[])
|
|
685
|
-
) t
|
|
686
|
-
WHERE id = ANY($1::text[])
|
|
693
|
+
const r = await this.db.query(`SELECT id, SUM(cnt) AS count, SUM(sw) AS sum_weight FROM (
|
|
694
|
+
SELECT from_engram_id AS id, 1 AS cnt, weight AS sw FROM associations WHERE from_engram_id = ANY($1::text[])
|
|
695
|
+
UNION ALL
|
|
696
|
+
SELECT to_engram_id AS id, 1 AS cnt, weight AS sw FROM associations WHERE to_engram_id = ANY($1::text[])
|
|
697
|
+
) t
|
|
698
|
+
WHERE id = ANY($1::text[])
|
|
687
699
|
GROUP BY id`, [engramIds]);
|
|
688
700
|
for (const row of r.rows) {
|
|
689
701
|
result.set(row.id, { count: Number(row.count), sumWeight: Number(row.sum_weight) });
|
|
@@ -699,7 +711,7 @@ export class PGliteEngramStore {
|
|
|
699
711
|
if (engramIds.length === 0)
|
|
700
712
|
return result;
|
|
701
713
|
await this.readyPromise;
|
|
702
|
-
const r = await this.db.query(`SELECT * FROM associations
|
|
714
|
+
const r = await this.db.query(`SELECT * FROM associations
|
|
703
715
|
WHERE from_engram_id = ANY($1::text[]) OR to_engram_id = ANY($1::text[])`, [engramIds]);
|
|
704
716
|
for (const row of r.rows) {
|
|
705
717
|
const a = rowToAssociation(row);
|
|
@@ -739,8 +751,8 @@ export class PGliteEngramStore {
|
|
|
739
751
|
}
|
|
740
752
|
async getAllAssociations(agentId) {
|
|
741
753
|
await this.readyPromise;
|
|
742
|
-
const result = await this.db.query(`SELECT a.* FROM associations a
|
|
743
|
-
JOIN engrams e ON a.from_engram_id = e.id
|
|
754
|
+
const result = await this.db.query(`SELECT a.* FROM associations a
|
|
755
|
+
JOIN engrams e ON a.from_engram_id = e.id
|
|
744
756
|
WHERE e.agent_id = $1`, [agentId]);
|
|
745
757
|
return result.rows.map(rowToAssociation);
|
|
746
758
|
}
|
|
@@ -749,11 +761,11 @@ export class PGliteEngramStore {
|
|
|
749
761
|
// ============================================================
|
|
750
762
|
async getEvictionCandidates(agentId, limit) {
|
|
751
763
|
await this.readyPromise;
|
|
752
|
-
const result = await this.db.query(`SELECT * FROM engrams
|
|
753
|
-
WHERE agent_id = $1 AND stage = 'active' AND retracted = FALSE
|
|
754
|
-
ORDER BY (salience * 0.3 + confidence * 0.3
|
|
755
|
-
+ (access_count::float / (access_count + 5)) * 0.2
|
|
756
|
-
+ (1.0 / (1.0 + EXTRACT(EPOCH FROM (now() - last_accessed::timestamptz)) / 86400.0)) * 0.2) ASC
|
|
764
|
+
const result = await this.db.query(`SELECT * FROM engrams
|
|
765
|
+
WHERE agent_id = $1 AND stage = 'active' AND retracted = FALSE
|
|
766
|
+
ORDER BY (salience * 0.3 + confidence * 0.3
|
|
767
|
+
+ (access_count::float / (access_count + 5)) * 0.2
|
|
768
|
+
+ (1.0 / (1.0 + EXTRACT(EPOCH FROM (now() - last_accessed::timestamptz)) / 86400.0)) * 0.2) ASC
|
|
757
769
|
LIMIT $2`, [agentId, limit]);
|
|
758
770
|
return result.rows.map(rowToEngram);
|
|
759
771
|
}
|
|
@@ -788,7 +800,7 @@ export class PGliteEngramStore {
|
|
|
788
800
|
}
|
|
789
801
|
async logStagingEvent(event) {
|
|
790
802
|
await this.readyPromise;
|
|
791
|
-
await this.db.query(`INSERT INTO staging_events (engram_id, agent_id, action, resonance_score, timestamp, age_ms)
|
|
803
|
+
await this.db.query(`INSERT INTO staging_events (engram_id, agent_id, action, resonance_score, timestamp, age_ms)
|
|
792
804
|
VALUES ($1, $2, $3, $4, $5, $6)`, [
|
|
793
805
|
event.engramId, event.agentId, event.action,
|
|
794
806
|
event.resonanceScore, event.timestamp.toISOString(), event.ageMs,
|
|
@@ -796,18 +808,18 @@ export class PGliteEngramStore {
|
|
|
796
808
|
}
|
|
797
809
|
async logRetrievalFeedback(activationEventId, engramId, useful, context) {
|
|
798
810
|
await this.readyPromise;
|
|
799
|
-
await this.db.query(`INSERT INTO retrieval_feedback (id, activation_event_id, engram_id, useful, context, timestamp)
|
|
811
|
+
await this.db.query(`INSERT INTO retrieval_feedback (id, activation_event_id, engram_id, useful, context, timestamp)
|
|
800
812
|
VALUES ($1, $2, $3, $4, $5, $6)`, [randomUUID(), activationEventId, engramId, useful, context, new Date().toISOString()]);
|
|
801
813
|
}
|
|
802
814
|
async getRetrievalPrecision(agentId, windowHours = 24) {
|
|
803
815
|
await this.readyPromise;
|
|
804
816
|
const since = new Date(Date.now() - windowHours * 3600_000).toISOString();
|
|
805
|
-
const result = await this.db.query(`SELECT
|
|
806
|
-
COUNT(CASE WHEN useful = TRUE THEN 1 END) AS useful_count,
|
|
807
|
-
COUNT(*) AS total_count
|
|
808
|
-
FROM retrieval_feedback rf
|
|
809
|
-
LEFT JOIN activation_events ae ON rf.activation_event_id = ae.id
|
|
810
|
-
JOIN engrams e ON rf.engram_id = e.id
|
|
817
|
+
const result = await this.db.query(`SELECT
|
|
818
|
+
COUNT(CASE WHEN useful = TRUE THEN 1 END) AS useful_count,
|
|
819
|
+
COUNT(*) AS total_count
|
|
820
|
+
FROM retrieval_feedback rf
|
|
821
|
+
LEFT JOIN activation_events ae ON rf.activation_event_id = ae.id
|
|
822
|
+
JOIN engrams e ON rf.engram_id = e.id
|
|
811
823
|
WHERE e.agent_id = $1 AND rf.timestamp > $2`, [agentId, since]);
|
|
812
824
|
const row = result.rows[0];
|
|
813
825
|
const total = Number(row?.total_count ?? 0);
|
|
@@ -816,10 +828,10 @@ export class PGliteEngramStore {
|
|
|
816
828
|
}
|
|
817
829
|
async getStagingMetrics(agentId) {
|
|
818
830
|
await this.readyPromise;
|
|
819
|
-
const result = await this.db.query(`SELECT
|
|
820
|
-
COUNT(CASE WHEN action = 'promoted' THEN 1 END) AS promoted,
|
|
821
|
-
COUNT(CASE WHEN action = 'discarded' THEN 1 END) AS discarded,
|
|
822
|
-
COUNT(CASE WHEN action = 'expired' THEN 1 END) AS expired
|
|
831
|
+
const result = await this.db.query(`SELECT
|
|
832
|
+
COUNT(CASE WHEN action = 'promoted' THEN 1 END) AS promoted,
|
|
833
|
+
COUNT(CASE WHEN action = 'discarded' THEN 1 END) AS discarded,
|
|
834
|
+
COUNT(CASE WHEN action = 'expired' THEN 1 END) AS expired
|
|
823
835
|
FROM staging_events WHERE agent_id = $1`, [agentId]);
|
|
824
836
|
const row = result.rows[0] ?? { promoted: 0, discarded: 0, expired: 0 };
|
|
825
837
|
return {
|
|
@@ -833,8 +845,8 @@ export class PGliteEngramStore {
|
|
|
833
845
|
// Flush any buffered activation events so stats reflect the latest writes.
|
|
834
846
|
await this.flushActivationEvents();
|
|
835
847
|
const since = new Date(Date.now() - windowHours * 3600_000).toISOString();
|
|
836
|
-
const result = await this.db.query(`SELECT latency_ms FROM activation_events
|
|
837
|
-
WHERE agent_id = $1 AND timestamp > $2
|
|
848
|
+
const result = await this.db.query(`SELECT latency_ms FROM activation_events
|
|
849
|
+
WHERE agent_id = $1 AND timestamp > $2
|
|
838
850
|
ORDER BY latency_ms ASC`, [agentId, since]);
|
|
839
851
|
if (result.rows.length === 0)
|
|
840
852
|
return { count: 0, avgLatencyMs: 0, p95LatencyMs: 0 };
|
|
@@ -859,7 +871,7 @@ export class PGliteEngramStore {
|
|
|
859
871
|
await this.readyPromise;
|
|
860
872
|
const id = randomUUID();
|
|
861
873
|
const now = new Date().toISOString();
|
|
862
|
-
await this.db.query(`INSERT INTO episodes (id, agent_id, label, embedding, engram_count, start_time, end_time, created_at)
|
|
874
|
+
await this.db.query(`INSERT INTO episodes (id, agent_id, label, embedding, engram_count, start_time, end_time, created_at)
|
|
863
875
|
VALUES ($1, $2, $3, $4::vector, 0, $5, $5, $5)`, [id, input.agentId, input.label, vectorToLiteral(input.embedding ?? null), now]);
|
|
864
876
|
const ep = await this.getEpisode(id);
|
|
865
877
|
if (!ep)
|
|
@@ -885,9 +897,9 @@ export class PGliteEngramStore {
|
|
|
885
897
|
async addEngramToEpisode(engramId, episodeId) {
|
|
886
898
|
await this.readyPromise;
|
|
887
899
|
await this.db.query(`UPDATE engrams SET episode_id = $1 WHERE id = $2`, [episodeId, engramId]);
|
|
888
|
-
await this.db.query(`UPDATE episodes SET
|
|
889
|
-
engram_count = engram_count + 1,
|
|
890
|
-
end_time = GREATEST(end_time, $1)
|
|
900
|
+
await this.db.query(`UPDATE episodes SET
|
|
901
|
+
engram_count = engram_count + 1,
|
|
902
|
+
end_time = GREATEST(end_time, $1)
|
|
891
903
|
WHERE id = $2`, [new Date().toISOString(), episodeId]);
|
|
892
904
|
}
|
|
893
905
|
async getEngramsByEpisode(episodeId) {
|
|
@@ -926,46 +938,76 @@ export class PGliteEngramStore {
|
|
|
926
938
|
async updateAutoCheckpointWrite(agentId, engramId) {
|
|
927
939
|
await this.readyPromise;
|
|
928
940
|
const now = new Date().toISOString();
|
|
929
|
-
await this.db.query(`INSERT INTO conscious_state (agent_id, last_write_id, last_activity_at, write_count_since_consolidation, updated_at)
|
|
930
|
-
VALUES ($1, $2, $3, 1, $3)
|
|
931
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
932
|
-
last_write_id = EXCLUDED.last_write_id,
|
|
933
|
-
last_activity_at = EXCLUDED.last_activity_at,
|
|
934
|
-
write_count_since_consolidation = conscious_state.write_count_since_consolidation + 1,
|
|
941
|
+
await this.db.query(`INSERT INTO conscious_state (agent_id, last_write_id, last_activity_at, write_count_since_consolidation, updated_at)
|
|
942
|
+
VALUES ($1, $2, $3, 1, $3)
|
|
943
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
944
|
+
last_write_id = EXCLUDED.last_write_id,
|
|
945
|
+
last_activity_at = EXCLUDED.last_activity_at,
|
|
946
|
+
write_count_since_consolidation = conscious_state.write_count_since_consolidation + 1,
|
|
935
947
|
updated_at = EXCLUDED.updated_at`, [agentId, engramId, now]);
|
|
936
948
|
}
|
|
937
949
|
async updateAutoCheckpointRecall(agentId, context, engramIds) {
|
|
938
950
|
await this.readyPromise;
|
|
939
951
|
const now = new Date().toISOString();
|
|
940
|
-
await this.db.query(`INSERT INTO conscious_state (agent_id, last_recall_context, last_recall_ids, last_activity_at, recall_count_since_consolidation, updated_at)
|
|
941
|
-
VALUES ($1, $2, $3, $4, 1, $4)
|
|
942
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
943
|
-
last_recall_context = EXCLUDED.last_recall_context,
|
|
944
|
-
last_recall_ids = EXCLUDED.last_recall_ids,
|
|
945
|
-
last_activity_at = EXCLUDED.last_activity_at,
|
|
946
|
-
recall_count_since_consolidation = conscious_state.recall_count_since_consolidation + 1,
|
|
952
|
+
await this.db.query(`INSERT INTO conscious_state (agent_id, last_recall_context, last_recall_ids, last_activity_at, recall_count_since_consolidation, updated_at)
|
|
953
|
+
VALUES ($1, $2, $3, $4, 1, $4)
|
|
954
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
955
|
+
last_recall_context = EXCLUDED.last_recall_context,
|
|
956
|
+
last_recall_ids = EXCLUDED.last_recall_ids,
|
|
957
|
+
last_activity_at = EXCLUDED.last_activity_at,
|
|
958
|
+
recall_count_since_consolidation = conscious_state.recall_count_since_consolidation + 1,
|
|
947
959
|
updated_at = EXCLUDED.updated_at`, [agentId, context, JSON.stringify(engramIds), now]);
|
|
948
960
|
}
|
|
949
961
|
async touchActivity(agentId) {
|
|
950
962
|
await this.readyPromise;
|
|
951
963
|
const now = new Date().toISOString();
|
|
952
|
-
await this.db.query(`INSERT INTO conscious_state (agent_id, last_activity_at, updated_at)
|
|
953
|
-
VALUES ($1, $2, $2)
|
|
954
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
955
|
-
last_activity_at = EXCLUDED.last_activity_at,
|
|
964
|
+
await this.db.query(`INSERT INTO conscious_state (agent_id, last_activity_at, updated_at)
|
|
965
|
+
VALUES ($1, $2, $2)
|
|
966
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
967
|
+
last_activity_at = EXCLUDED.last_activity_at,
|
|
956
968
|
updated_at = EXCLUDED.updated_at`, [agentId, now]);
|
|
957
969
|
}
|
|
958
970
|
async saveCheckpoint(agentId, state) {
|
|
959
971
|
await this.readyPromise;
|
|
960
972
|
const now = new Date().toISOString();
|
|
961
|
-
await this.db.query(`INSERT INTO conscious_state (agent_id, execution_state, checkpoint_at, last_activity_at, updated_at)
|
|
962
|
-
VALUES ($1, $2, $3, $3, $3)
|
|
963
|
-
ON CONFLICT(agent_id) DO UPDATE SET
|
|
964
|
-
execution_state = EXCLUDED.execution_state,
|
|
965
|
-
checkpoint_at = EXCLUDED.checkpoint_at,
|
|
966
|
-
last_activity_at = EXCLUDED.last_activity_at,
|
|
973
|
+
await this.db.query(`INSERT INTO conscious_state (agent_id, execution_state, checkpoint_at, last_activity_at, updated_at)
|
|
974
|
+
VALUES ($1, $2, $3, $3, $3)
|
|
975
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
976
|
+
execution_state = EXCLUDED.execution_state,
|
|
977
|
+
checkpoint_at = EXCLUDED.checkpoint_at,
|
|
978
|
+
last_activity_at = EXCLUDED.last_activity_at,
|
|
967
979
|
updated_at = EXCLUDED.updated_at`, [agentId, JSON.stringify(state), now]);
|
|
968
980
|
}
|
|
981
|
+
/** Distinct agent ids present in this store (D3 whoami; includes all stages). */
|
|
982
|
+
async listAgentIds() {
|
|
983
|
+
const res = await this.db.query('SELECT DISTINCT agent_id FROM engrams ORDER BY agent_id');
|
|
984
|
+
return res.rows.map(r => r.agent_id);
|
|
985
|
+
}
|
|
986
|
+
async recordEntityMentions(engramId, agentId, entities) {
|
|
987
|
+
if (!entities || entities.length === 0)
|
|
988
|
+
return;
|
|
989
|
+
for (const entity of entities) {
|
|
990
|
+
await this.db.query('INSERT INTO entity_mentions (entity, engram_id, agent_id) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING', [entity, engramId, agentId]);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
async searchEntities(term, limit = 8) {
|
|
994
|
+
const t = term.toLowerCase().replace(/[%_]/g, '');
|
|
995
|
+
if (!t)
|
|
996
|
+
return [];
|
|
997
|
+
const res = await this.db.query(`SELECT DISTINCT entity FROM (
|
|
998
|
+
SELECT entity FROM entity_mentions WHERE entity LIKE $1
|
|
999
|
+
UNION SELECT entity FROM entity_aliases WHERE alias LIKE $1
|
|
1000
|
+
) u LIMIT $2`, [`%${t}%`, limit]);
|
|
1001
|
+
return res.rows.map(r => r.entity);
|
|
1002
|
+
}
|
|
1003
|
+
async getEngramIdsByEntity(entity, agentId) {
|
|
1004
|
+
const alias = await this.db.query('SELECT entity FROM entity_aliases WHERE alias = $1', [entity.toLowerCase()]);
|
|
1005
|
+
const resolved = alias.rows[0]?.entity ?? entity.toLowerCase();
|
|
1006
|
+
const res = agentId
|
|
1007
|
+
? await this.db.query('SELECT engram_id FROM entity_mentions WHERE entity = $1 AND agent_id = $2', [resolved, agentId])
|
|
1008
|
+
: await this.db.query('SELECT engram_id FROM entity_mentions WHERE entity = $1', [resolved]);
|
|
1009
|
+
return res.rows.map(r => r.engram_id);
|
|
1010
|
+
}
|
|
969
1011
|
async getCheckpoint(agentId) {
|
|
970
1012
|
await this.readyPromise;
|
|
971
1013
|
const result = await this.db.query(`SELECT * FROM conscious_state WHERE agent_id = $1`, [agentId]);
|
|
@@ -996,13 +1038,13 @@ export class PGliteEngramStore {
|
|
|
996
1038
|
await this.db.query(`UPDATE conscious_state SET last_mini_consolidation_at = $1, updated_at = $1 WHERE agent_id = $2`, [now, agentId]);
|
|
997
1039
|
}
|
|
998
1040
|
else {
|
|
999
|
-
await this.db.query(`UPDATE conscious_state SET
|
|
1000
|
-
last_consolidation_at = $1,
|
|
1001
|
-
last_mini_consolidation_at = $1,
|
|
1002
|
-
write_count_since_consolidation = 0,
|
|
1003
|
-
recall_count_since_consolidation = 0,
|
|
1004
|
-
consolidation_cycle_count = consolidation_cycle_count + 1,
|
|
1005
|
-
updated_at = $1
|
|
1041
|
+
await this.db.query(`UPDATE conscious_state SET
|
|
1042
|
+
last_consolidation_at = $1,
|
|
1043
|
+
last_mini_consolidation_at = $1,
|
|
1044
|
+
write_count_since_consolidation = 0,
|
|
1045
|
+
recall_count_since_consolidation = 0,
|
|
1046
|
+
consolidation_cycle_count = consolidation_cycle_count + 1,
|
|
1047
|
+
updated_at = $1
|
|
1006
1048
|
WHERE agent_id = $2`, [now, agentId]);
|
|
1007
1049
|
}
|
|
1008
1050
|
}
|
|
@@ -1027,10 +1069,10 @@ export class PGliteEngramStore {
|
|
|
1027
1069
|
// ============================================================
|
|
1028
1070
|
async getLatestByTag(opts) {
|
|
1029
1071
|
await this.readyPromise;
|
|
1030
|
-
let sql = `SELECT * FROM engrams
|
|
1031
|
-
WHERE agent_id = $1
|
|
1032
|
-
AND retracted = $2
|
|
1033
|
-
AND stage = 'active'
|
|
1072
|
+
let sql = `SELECT * FROM engrams
|
|
1073
|
+
WHERE agent_id = $1
|
|
1074
|
+
AND retracted = $2
|
|
1075
|
+
AND stage = 'active'
|
|
1034
1076
|
AND tags LIKE $3`;
|
|
1035
1077
|
const params = [opts.agentId, opts.retracted ?? false, `%"${opts.tagKeyPrefix}%`];
|
|
1036
1078
|
if (opts.scopeTagsAll && opts.scopeTagsAll.length > 0) {
|
|
@@ -1057,10 +1099,10 @@ export class PGliteEngramStore {
|
|
|
1057
1099
|
}
|
|
1058
1100
|
async getTopBy(opts) {
|
|
1059
1101
|
await this.readyPromise;
|
|
1060
|
-
let sql = `SELECT * FROM engrams
|
|
1061
|
-
WHERE agent_id = $1
|
|
1062
|
-
AND retracted = $2
|
|
1063
|
-
AND stage = 'active'
|
|
1102
|
+
let sql = `SELECT * FROM engrams
|
|
1103
|
+
WHERE agent_id = $1
|
|
1104
|
+
AND retracted = $2
|
|
1105
|
+
AND stage = 'active'
|
|
1064
1106
|
AND tags LIKE $3`;
|
|
1065
1107
|
const params = [opts.agentId, opts.retracted ?? false, `%"${opts.sortField}%`];
|
|
1066
1108
|
if (opts.filterTagsAll && opts.filterTagsAll.length > 0) {
|