agent-working-memory 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/cli/migrate.js +29 -29
  2. package/dist/cli.js +324 -219
  3. package/dist/cli.js.map +1 -1
  4. package/dist/coordination/circuit-breaker.js +23 -23
  5. package/dist/core/salience.d.ts.map +1 -1
  6. package/dist/core/salience.js +10 -1
  7. package/dist/core/salience.js.map +1 -1
  8. package/dist/core/write-pipeline.d.ts.map +1 -1
  9. package/dist/core/write-pipeline.js +5 -1
  10. package/dist/core/write-pipeline.js.map +1 -1
  11. package/dist/storage/factory.d.ts +1 -1
  12. package/dist/storage/factory.d.ts.map +1 -1
  13. package/dist/storage/factory.js +16 -2
  14. package/dist/storage/factory.js.map +1 -1
  15. package/dist/storage/pglite-schema.js +143 -143
  16. package/dist/storage/pglite.d.ts.map +1 -1
  17. package/dist/storage/pglite.js +146 -138
  18. package/dist/storage/pglite.js.map +1 -1
  19. package/dist/storage/postgres.d.ts +228 -0
  20. package/dist/storage/postgres.d.ts.map +1 -0
  21. package/dist/storage/postgres.js +1221 -0
  22. package/dist/storage/postgres.js.map +1 -0
  23. package/package.json +3 -1
  24. package/src/api/index.ts +3 -3
  25. package/src/cli/migrate.ts +307 -307
  26. package/src/cli.ts +266 -268
  27. package/src/coordination/circuit-breaker.ts +83 -83
  28. package/src/coordination/failure-modes.ts +50 -50
  29. package/src/core/decay.ts +63 -63
  30. package/src/core/embeddings.ts +110 -110
  31. package/src/core/index.ts +5 -5
  32. package/src/core/logger.ts +36 -36
  33. package/src/core/ml-worker-entry.ts +194 -194
  34. package/src/core/ml-worker.ts +281 -281
  35. package/src/core/query-expander.ts +122 -122
  36. package/src/core/reranker.ts +119 -119
  37. package/src/core/salience.ts +10 -1
  38. package/src/core/write-pipeline.ts +5 -1
  39. package/src/engine/confidence.ts +120 -120
  40. package/src/engine/consolidation-scheduler.ts +242 -242
  41. package/src/engine/eval.ts +102 -102
  42. package/src/engine/eviction.ts +101 -101
  43. package/src/engine/index.ts +8 -8
  44. package/src/engine/retraction.ts +366 -366
  45. package/src/engine/staging.ts +74 -74
  46. package/src/storage/factory.ts +159 -147
  47. package/src/storage/index.ts +3 -3
  48. package/src/storage/pglite-schema.ts +166 -166
  49. package/src/storage/pglite.ts +1372 -1363
  50. package/src/storage/postgres.ts +1475 -0
  51. package/src/storage/store.ts +80 -80
  52. package/src/types/agent.ts +67 -67
  53. package/src/types/checkpoint.ts +46 -46
  54. package/src/types/eval.ts +100 -100
  55. package/src/types/index.ts +6 -6
@@ -129,6 +129,7 @@ function extractTagValue(tags, prefix) {
129
129
  }
130
130
  return null;
131
131
  }
132
+ let warnedNoCoordPglite = false; // one-time warning when workspace/hive recall falls back (coord_agents absent)
132
133
  export class PGliteEngramStore {
133
134
  db;
134
135
  readyPromise;
@@ -184,7 +185,7 @@ export class PGliteEngramStore {
184
185
  params.push(e.id, e.agentId, e.timestamp.toISOString(), e.context, e.resultsReturned, e.topScore, e.latencyMs, JSON.stringify(e.engramIds));
185
186
  }
186
187
  try {
187
- await this.db.query(`INSERT INTO activation_events (id, agent_id, timestamp, context, results_returned, top_score, latency_ms, engram_ids)
188
+ await this.db.query(`INSERT INTO activation_events (id, agent_id, timestamp, context, results_returned, top_score, latency_ms, engram_ids)
188
189
  VALUES ${values.join(',')}`, params);
189
190
  }
190
191
  catch {
@@ -222,18 +223,18 @@ export class PGliteEngramStore {
222
223
  await this.readyPromise;
223
224
  const id = input.id ?? randomUUID();
224
225
  const now = new Date().toISOString();
225
- await this.db.query(`INSERT INTO engrams (
226
- id, agent_id, concept, content, embedding, embedding_model,
227
- confidence, salience, access_count, last_accessed, created_at,
228
- salience_features, reason_codes, stage, ttl, retracted,
229
- tags, memory_type, memory_class, supersedes, episode_id,
230
- task_status, task_priority, blocked_by, sequence, references_json
231
- ) VALUES (
232
- $1, $2, $3, $4, $5::vector, $6,
233
- $7, $8, 0, $9, $10,
234
- $11, $12, 'active', $13, FALSE,
235
- $14, $15, $16, $17, $18,
236
- $19, $20, $21, $22, $23
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
+ ) VALUES (
233
+ $1, $2, $3, $4, $5::vector, $6,
234
+ $7, $8, 0, $9, $10,
235
+ $11, $12, 'active', $13, FALSE,
236
+ $14, $15, $16, $17, $18,
237
+ $19, $20, $21, $22, $23
237
238
  )`, [
238
239
  id,
239
240
  input.agentId,
@@ -357,15 +358,22 @@ export class PGliteEngramStore {
357
358
  return names;
358
359
  }
359
360
  catch {
361
+ // coord_agents isn't provisioned on PGlite — workspace/hive coordination is currently SQLite-only.
362
+ // Warn ONCE so this degrades VISIBLY (recall scoped to self) instead of silently.
363
+ if (!warnedNoCoordPglite) {
364
+ warnedNoCoordPglite = true;
365
+ console.warn('[awm:pglite] workspace/hive coordination is not available on the PGlite backend ' +
366
+ '(coord_agents not provisioned) — recall is scoped to THIS agent only. Hive coordination is SQLite-only for now.');
367
+ }
360
368
  return [agentId];
361
369
  }
362
370
  }
363
371
  async touchEngram(id) {
364
372
  await this.readyPromise;
365
- await this.db.query(`UPDATE engrams
366
- SET access_count = access_count + 1,
367
- last_accessed = $1,
368
- confidence = LEAST(0.85, confidence + 0.02 / (1.0 + sqrt(access_count::float)))
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)))
369
377
  WHERE id = $2`, [new Date().toISOString(), id]);
370
378
  }
371
379
  async updateStage(id, stage) {
@@ -411,9 +419,9 @@ export class PGliteEngramStore {
411
419
  async timeWarp(agentId, ms) {
412
420
  await this.readyPromise;
413
421
  const seconds = Math.round(ms / 1000);
414
- const r1 = await this.db.query(`UPDATE engrams SET
415
- created_at = to_char(($1::timestamptz - interval '1 second' * $2), 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'),
416
- last_accessed = to_char(($3::timestamptz - interval '1 second' * $2), 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')
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"')
417
425
  WHERE agent_id = $4`, ['now', seconds, 'now', agentId]);
418
426
  // Simpler: just update with relative arithmetic on stored ISO strings.
419
427
  // PGlite doesn't support all date ops cleanly; fall through to JS-side calculation.
@@ -439,13 +447,13 @@ export class PGliteEngramStore {
439
447
  // Restrict to active + fading. Faded engrams (Paper 1: storage degradation)
440
448
  // retain their embedding so they still participate in semantic recall, even
441
449
  // though their content has been trimmed. Excludes staging/consolidated/archived.
442
- const result = await this.db.query(`SELECT *, (embedding <=> $2::vector) AS distance
443
- FROM engrams
444
- WHERE agent_id = $1
445
- AND embedding IS NOT NULL
446
- AND retracted = FALSE
447
- AND stage IN ('active', 'fading')
448
- ORDER BY distance ASC
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
449
457
  LIMIT $3`, [agentId, vectorToLiteral(vec), limit]);
450
458
  return result.rows.map((r) => ({ engram: rowToEngram(r), distance: r.distance }));
451
459
  }
@@ -464,11 +472,11 @@ export class PGliteEngramStore {
464
472
  if (tokens.length === 0)
465
473
  return [];
466
474
  const websearchQuery = tokens.join(' OR ');
467
- const result = await this.db.query(`SELECT *, ts_rank_cd(fts, websearch_to_tsquery('english', $2)) AS rank
468
- FROM engrams
469
- WHERE agent_id = $1 AND retracted = FALSE
470
- AND fts @@ websearch_to_tsquery('english', $2)
471
- ORDER BY rank DESC
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
472
480
  LIMIT $3`, [agentId, websearchQuery, limit]);
473
481
  return result.rows.map((r) => ({ engram: rowToEngram(r), bm25Score: calibrateBm25(Number(r.rank)) }));
474
482
  }
@@ -482,11 +490,11 @@ export class PGliteEngramStore {
482
490
  if (tokens.length === 0)
483
491
  return [];
484
492
  const websearchQuery = tokens.join(' OR ');
485
- const result = await this.db.query(`SELECT *, ts_rank_cd(fts, websearch_to_tsquery('english', $2)) AS rank
486
- FROM engrams
487
- WHERE agent_id = ANY($1::text[]) AND retracted = FALSE
488
- AND fts @@ websearch_to_tsquery('english', $2)
489
- ORDER BY rank DESC
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
490
498
  LIMIT $3`, [agentIds, websearchQuery, limit]);
491
499
  return result.rows.map((r) => ({ engram: rowToEngram(r), bm25Score: calibrateBm25(Number(r.rank)) }));
492
500
  }
@@ -567,32 +575,32 @@ export class PGliteEngramStore {
567
575
  sql += ` AND task_status = $${params.length + 1}`;
568
576
  params.push(status);
569
577
  }
570
- sql += ` ORDER BY
571
- CASE task_priority
572
- WHEN 'urgent' THEN 0
573
- WHEN 'high' THEN 1
574
- WHEN 'medium' THEN 2
575
- WHEN 'low' THEN 3
576
- ELSE 4
577
- END,
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,
578
586
  created_at DESC`;
579
587
  const result = await this.db.query(sql, params);
580
588
  return result.rows.map(rowToEngram);
581
589
  }
582
590
  async getNextTask(agentId) {
583
591
  await this.readyPromise;
584
- const result = await this.db.query(`SELECT * FROM engrams
585
- WHERE agent_id = $1 AND task_status IN ('open', 'in_progress') AND retracted = FALSE
586
- ORDER BY
587
- CASE task_status WHEN 'in_progress' THEN 0 ELSE 1 END,
588
- CASE task_priority
589
- WHEN 'urgent' THEN 0
590
- WHEN 'high' THEN 1
591
- WHEN 'medium' THEN 2
592
- WHEN 'low' THEN 3
593
- ELSE 4
594
- END,
595
- created_at ASC
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
596
604
  LIMIT 1`, [agentId]);
597
605
  return result.rows.length > 0 ? rowToEngram(result.rows[0]) : null;
598
606
  }
@@ -606,11 +614,11 @@ export class PGliteEngramStore {
606
614
  }
607
615
  async findActiveMatchByConcept(agentId, concept, requiredTags) {
608
616
  await this.readyPromise;
609
- let sql = `SELECT * FROM engrams
610
- WHERE agent_id = $1
611
- AND LOWER(TRIM(concept)) = LOWER(TRIM($2))
612
- AND stage = 'active'
613
- AND retracted = FALSE
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
614
622
  AND superseded_by IS NULL`;
615
623
  const params = [agentId, concept];
616
624
  if (requiredTags && requiredTags.length > 0) {
@@ -643,12 +651,12 @@ export class PGliteEngramStore {
643
651
  await this.readyPromise;
644
652
  const id = randomUUID();
645
653
  const now = new Date().toISOString();
646
- await this.db.query(`INSERT INTO associations (id, from_engram_id, to_engram_id, weight, confidence, type, activation_count, created_at, last_activated)
647
- VALUES ($1, $2, $3, $4, $5, $6, 0, $7, $7)
648
- ON CONFLICT (from_engram_id, to_engram_id) DO UPDATE SET
649
- weight = EXCLUDED.weight,
650
- confidence = EXCLUDED.confidence,
651
- last_activated = EXCLUDED.last_activated,
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,
652
660
  activation_count = associations.activation_count + 1`, [id, fromId, toId, weight, confidence, type, now]);
653
661
  const assoc = await this.getAssociation(fromId, toId);
654
662
  if (!assoc)
@@ -670,12 +678,12 @@ export class PGliteEngramStore {
670
678
  if (engramIds.length === 0)
671
679
  return result;
672
680
  await this.readyPromise;
673
- const r = await this.db.query(`SELECT id, SUM(cnt) AS count, SUM(sw) AS sum_weight FROM (
674
- SELECT from_engram_id AS id, 1 AS cnt, weight AS sw FROM associations WHERE from_engram_id = ANY($1::text[])
675
- UNION ALL
676
- SELECT to_engram_id AS id, 1 AS cnt, weight AS sw FROM associations WHERE to_engram_id = ANY($1::text[])
677
- ) t
678
- WHERE id = ANY($1::text[])
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[])
679
687
  GROUP BY id`, [engramIds]);
680
688
  for (const row of r.rows) {
681
689
  result.set(row.id, { count: Number(row.count), sumWeight: Number(row.sum_weight) });
@@ -691,7 +699,7 @@ export class PGliteEngramStore {
691
699
  if (engramIds.length === 0)
692
700
  return result;
693
701
  await this.readyPromise;
694
- const r = await this.db.query(`SELECT * FROM associations
702
+ const r = await this.db.query(`SELECT * FROM associations
695
703
  WHERE from_engram_id = ANY($1::text[]) OR to_engram_id = ANY($1::text[])`, [engramIds]);
696
704
  for (const row of r.rows) {
697
705
  const a = rowToAssociation(row);
@@ -731,8 +739,8 @@ export class PGliteEngramStore {
731
739
  }
732
740
  async getAllAssociations(agentId) {
733
741
  await this.readyPromise;
734
- const result = await this.db.query(`SELECT a.* FROM associations a
735
- JOIN engrams e ON a.from_engram_id = e.id
742
+ const result = await this.db.query(`SELECT a.* FROM associations a
743
+ JOIN engrams e ON a.from_engram_id = e.id
736
744
  WHERE e.agent_id = $1`, [agentId]);
737
745
  return result.rows.map(rowToAssociation);
738
746
  }
@@ -741,11 +749,11 @@ export class PGliteEngramStore {
741
749
  // ============================================================
742
750
  async getEvictionCandidates(agentId, limit) {
743
751
  await this.readyPromise;
744
- const result = await this.db.query(`SELECT * FROM engrams
745
- WHERE agent_id = $1 AND stage = 'active' AND retracted = FALSE
746
- ORDER BY (salience * 0.3 + confidence * 0.3
747
- + (access_count::float / (access_count + 5)) * 0.2
748
- + (1.0 / (1.0 + EXTRACT(EPOCH FROM (now() - last_accessed::timestamptz)) / 86400.0)) * 0.2) ASC
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
749
757
  LIMIT $2`, [agentId, limit]);
750
758
  return result.rows.map(rowToEngram);
751
759
  }
@@ -780,7 +788,7 @@ export class PGliteEngramStore {
780
788
  }
781
789
  async logStagingEvent(event) {
782
790
  await this.readyPromise;
783
- await this.db.query(`INSERT INTO staging_events (engram_id, agent_id, action, resonance_score, timestamp, age_ms)
791
+ await this.db.query(`INSERT INTO staging_events (engram_id, agent_id, action, resonance_score, timestamp, age_ms)
784
792
  VALUES ($1, $2, $3, $4, $5, $6)`, [
785
793
  event.engramId, event.agentId, event.action,
786
794
  event.resonanceScore, event.timestamp.toISOString(), event.ageMs,
@@ -788,18 +796,18 @@ export class PGliteEngramStore {
788
796
  }
789
797
  async logRetrievalFeedback(activationEventId, engramId, useful, context) {
790
798
  await this.readyPromise;
791
- await this.db.query(`INSERT INTO retrieval_feedback (id, activation_event_id, engram_id, useful, context, timestamp)
799
+ await this.db.query(`INSERT INTO retrieval_feedback (id, activation_event_id, engram_id, useful, context, timestamp)
792
800
  VALUES ($1, $2, $3, $4, $5, $6)`, [randomUUID(), activationEventId, engramId, useful, context, new Date().toISOString()]);
793
801
  }
794
802
  async getRetrievalPrecision(agentId, windowHours = 24) {
795
803
  await this.readyPromise;
796
804
  const since = new Date(Date.now() - windowHours * 3600_000).toISOString();
797
- const result = await this.db.query(`SELECT
798
- COUNT(CASE WHEN useful = TRUE THEN 1 END) AS useful_count,
799
- COUNT(*) AS total_count
800
- FROM retrieval_feedback rf
801
- LEFT JOIN activation_events ae ON rf.activation_event_id = ae.id
802
- JOIN engrams e ON rf.engram_id = e.id
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
803
811
  WHERE e.agent_id = $1 AND rf.timestamp > $2`, [agentId, since]);
804
812
  const row = result.rows[0];
805
813
  const total = Number(row?.total_count ?? 0);
@@ -808,10 +816,10 @@ export class PGliteEngramStore {
808
816
  }
809
817
  async getStagingMetrics(agentId) {
810
818
  await this.readyPromise;
811
- const result = await this.db.query(`SELECT
812
- COUNT(CASE WHEN action = 'promoted' THEN 1 END) AS promoted,
813
- COUNT(CASE WHEN action = 'discarded' THEN 1 END) AS discarded,
814
- COUNT(CASE WHEN action = 'expired' THEN 1 END) AS expired
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
815
823
  FROM staging_events WHERE agent_id = $1`, [agentId]);
816
824
  const row = result.rows[0] ?? { promoted: 0, discarded: 0, expired: 0 };
817
825
  return {
@@ -825,8 +833,8 @@ export class PGliteEngramStore {
825
833
  // Flush any buffered activation events so stats reflect the latest writes.
826
834
  await this.flushActivationEvents();
827
835
  const since = new Date(Date.now() - windowHours * 3600_000).toISOString();
828
- const result = await this.db.query(`SELECT latency_ms FROM activation_events
829
- WHERE agent_id = $1 AND timestamp > $2
836
+ const result = await this.db.query(`SELECT latency_ms FROM activation_events
837
+ WHERE agent_id = $1 AND timestamp > $2
830
838
  ORDER BY latency_ms ASC`, [agentId, since]);
831
839
  if (result.rows.length === 0)
832
840
  return { count: 0, avgLatencyMs: 0, p95LatencyMs: 0 };
@@ -851,7 +859,7 @@ export class PGliteEngramStore {
851
859
  await this.readyPromise;
852
860
  const id = randomUUID();
853
861
  const now = new Date().toISOString();
854
- await this.db.query(`INSERT INTO episodes (id, agent_id, label, embedding, engram_count, start_time, end_time, created_at)
862
+ await this.db.query(`INSERT INTO episodes (id, agent_id, label, embedding, engram_count, start_time, end_time, created_at)
855
863
  VALUES ($1, $2, $3, $4::vector, 0, $5, $5, $5)`, [id, input.agentId, input.label, vectorToLiteral(input.embedding ?? null), now]);
856
864
  const ep = await this.getEpisode(id);
857
865
  if (!ep)
@@ -877,9 +885,9 @@ export class PGliteEngramStore {
877
885
  async addEngramToEpisode(engramId, episodeId) {
878
886
  await this.readyPromise;
879
887
  await this.db.query(`UPDATE engrams SET episode_id = $1 WHERE id = $2`, [episodeId, engramId]);
880
- await this.db.query(`UPDATE episodes SET
881
- engram_count = engram_count + 1,
882
- end_time = GREATEST(end_time, $1)
888
+ await this.db.query(`UPDATE episodes SET
889
+ engram_count = engram_count + 1,
890
+ end_time = GREATEST(end_time, $1)
883
891
  WHERE id = $2`, [new Date().toISOString(), episodeId]);
884
892
  }
885
893
  async getEngramsByEpisode(episodeId) {
@@ -918,44 +926,44 @@ export class PGliteEngramStore {
918
926
  async updateAutoCheckpointWrite(agentId, engramId) {
919
927
  await this.readyPromise;
920
928
  const now = new Date().toISOString();
921
- await this.db.query(`INSERT INTO conscious_state (agent_id, last_write_id, last_activity_at, write_count_since_consolidation, updated_at)
922
- VALUES ($1, $2, $3, 1, $3)
923
- ON CONFLICT(agent_id) DO UPDATE SET
924
- last_write_id = EXCLUDED.last_write_id,
925
- last_activity_at = EXCLUDED.last_activity_at,
926
- write_count_since_consolidation = conscious_state.write_count_since_consolidation + 1,
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,
927
935
  updated_at = EXCLUDED.updated_at`, [agentId, engramId, now]);
928
936
  }
929
937
  async updateAutoCheckpointRecall(agentId, context, engramIds) {
930
938
  await this.readyPromise;
931
939
  const now = new Date().toISOString();
932
- 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)
933
- VALUES ($1, $2, $3, $4, 1, $4)
934
- ON CONFLICT(agent_id) DO UPDATE SET
935
- last_recall_context = EXCLUDED.last_recall_context,
936
- last_recall_ids = EXCLUDED.last_recall_ids,
937
- last_activity_at = EXCLUDED.last_activity_at,
938
- recall_count_since_consolidation = conscious_state.recall_count_since_consolidation + 1,
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,
939
947
  updated_at = EXCLUDED.updated_at`, [agentId, context, JSON.stringify(engramIds), now]);
940
948
  }
941
949
  async touchActivity(agentId) {
942
950
  await this.readyPromise;
943
951
  const now = new Date().toISOString();
944
- await this.db.query(`INSERT INTO conscious_state (agent_id, last_activity_at, updated_at)
945
- VALUES ($1, $2, $2)
946
- ON CONFLICT(agent_id) DO UPDATE SET
947
- last_activity_at = EXCLUDED.last_activity_at,
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,
948
956
  updated_at = EXCLUDED.updated_at`, [agentId, now]);
949
957
  }
950
958
  async saveCheckpoint(agentId, state) {
951
959
  await this.readyPromise;
952
960
  const now = new Date().toISOString();
953
- await this.db.query(`INSERT INTO conscious_state (agent_id, execution_state, checkpoint_at, last_activity_at, updated_at)
954
- VALUES ($1, $2, $3, $3, $3)
955
- ON CONFLICT(agent_id) DO UPDATE SET
956
- execution_state = EXCLUDED.execution_state,
957
- checkpoint_at = EXCLUDED.checkpoint_at,
958
- last_activity_at = EXCLUDED.last_activity_at,
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,
959
967
  updated_at = EXCLUDED.updated_at`, [agentId, JSON.stringify(state), now]);
960
968
  }
961
969
  async getCheckpoint(agentId) {
@@ -988,13 +996,13 @@ export class PGliteEngramStore {
988
996
  await this.db.query(`UPDATE conscious_state SET last_mini_consolidation_at = $1, updated_at = $1 WHERE agent_id = $2`, [now, agentId]);
989
997
  }
990
998
  else {
991
- await this.db.query(`UPDATE conscious_state SET
992
- last_consolidation_at = $1,
993
- last_mini_consolidation_at = $1,
994
- write_count_since_consolidation = 0,
995
- recall_count_since_consolidation = 0,
996
- consolidation_cycle_count = consolidation_cycle_count + 1,
997
- updated_at = $1
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
998
1006
  WHERE agent_id = $2`, [now, agentId]);
999
1007
  }
1000
1008
  }
@@ -1019,10 +1027,10 @@ export class PGliteEngramStore {
1019
1027
  // ============================================================
1020
1028
  async getLatestByTag(opts) {
1021
1029
  await this.readyPromise;
1022
- let sql = `SELECT * FROM engrams
1023
- WHERE agent_id = $1
1024
- AND retracted = $2
1025
- AND stage = 'active'
1030
+ let sql = `SELECT * FROM engrams
1031
+ WHERE agent_id = $1
1032
+ AND retracted = $2
1033
+ AND stage = 'active'
1026
1034
  AND tags LIKE $3`;
1027
1035
  const params = [opts.agentId, opts.retracted ?? false, `%"${opts.tagKeyPrefix}%`];
1028
1036
  if (opts.scopeTagsAll && opts.scopeTagsAll.length > 0) {
@@ -1049,10 +1057,10 @@ export class PGliteEngramStore {
1049
1057
  }
1050
1058
  async getTopBy(opts) {
1051
1059
  await this.readyPromise;
1052
- let sql = `SELECT * FROM engrams
1053
- WHERE agent_id = $1
1054
- AND retracted = $2
1055
- AND stage = 'active'
1060
+ let sql = `SELECT * FROM engrams
1061
+ WHERE agent_id = $1
1062
+ AND retracted = $2
1063
+ AND stage = 'active'
1056
1064
  AND tags LIKE $3`;
1057
1065
  const params = [opts.agentId, opts.retracted ?? false, `%"${opts.sortField}%`];
1058
1066
  if (opts.filterTagsAll && opts.filterTagsAll.length > 0) {