agent-working-memory 0.8.7 → 0.9.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 (57) hide show
  1. package/README.md +207 -46
  2. package/dist/api/routes.js +1 -1
  3. package/dist/cli/migrate.js +29 -29
  4. package/dist/cli.js +1 -1
  5. package/dist/coordination/circuit-breaker.js +23 -23
  6. package/dist/core/write-pipeline.d.ts.map +1 -1
  7. package/dist/core/write-pipeline.js +17 -0
  8. package/dist/core/write-pipeline.js.map +1 -1
  9. package/dist/engine/activation.d.ts +28 -0
  10. package/dist/engine/activation.d.ts.map +1 -1
  11. package/dist/engine/activation.js +341 -11
  12. package/dist/engine/activation.js.map +1 -1
  13. package/dist/engine/connections.d.ts +12 -0
  14. package/dist/engine/connections.d.ts.map +1 -1
  15. package/dist/engine/connections.js +95 -0
  16. package/dist/engine/connections.js.map +1 -1
  17. package/dist/mcp.js +2 -2
  18. package/dist/storage/pglite-schema.js +143 -143
  19. package/dist/storage/pglite.js +138 -138
  20. package/dist/types/engram.d.ts +1 -0
  21. package/dist/types/engram.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/api/index.ts +3 -3
  24. package/src/api/routes.ts +1 -1
  25. package/src/cli/migrate.ts +307 -307
  26. package/src/cli.ts +1 -1
  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/write-pipeline.ts +15 -0
  38. package/src/engine/activation.ts +328 -11
  39. package/src/engine/confidence.ts +120 -120
  40. package/src/engine/connections.ts +94 -0
  41. package/src/engine/consolidation-scheduler.ts +242 -242
  42. package/src/engine/eval.ts +102 -102
  43. package/src/engine/eviction.ts +101 -101
  44. package/src/engine/index.ts +8 -8
  45. package/src/engine/retraction.ts +366 -366
  46. package/src/engine/staging.ts +74 -74
  47. package/src/mcp.ts +2 -2
  48. package/src/storage/factory.ts +147 -147
  49. package/src/storage/index.ts +3 -3
  50. package/src/storage/pglite-schema.ts +166 -166
  51. package/src/storage/pglite.ts +1363 -1363
  52. package/src/storage/store.ts +80 -80
  53. package/src/types/agent.ts +67 -67
  54. package/src/types/checkpoint.ts +46 -46
  55. package/src/types/engram.ts +1 -0
  56. package/src/types/eval.ts +100 -100
  57. package/src/types/index.ts +6 -6
@@ -1,102 +1,102 @@
1
- // Copyright 2026 Robert Winter / Complete Ideas
2
- // SPDX-License-Identifier: Apache-2.0
3
- /**
4
- * Evaluation Engine — measures whether memory actually helps.
5
- *
6
- * Four dimensions (from Codex):
7
- * 1. Retrieval quality — precision@k, latency
8
- * 2. Connection quality — edge utility, stability
9
- * 3. Staging accuracy — promotion precision, discard regret
10
- * 4. Memory health — contamination tracking, confidence distribution
11
- *
12
- * Task impact (with/without memory) is measured externally via TaskTrial records.
13
- */
14
-
15
- import type { IEngramStore as EngramStore } from '../storage/store.js';
16
- import type { EvalMetrics } from '../types/index.js';
17
-
18
- export class EvalEngine {
19
- private store: EngramStore;
20
-
21
- constructor(store: EngramStore) {
22
- this.store = store;
23
- }
24
-
25
- /**
26
- * Compute aggregate metrics for an agent over a time window.
27
- */
28
- async computeMetrics(agentId: string, windowHours: number = 24): Promise<EvalMetrics> {
29
- const window = windowHours <= 24 ? '24h' : `${Math.round(windowHours / 24)}d`;
30
-
31
- // Retrieval quality
32
- const precision = await this.store.getRetrievalPrecision(agentId, windowHours);
33
-
34
- // Staging accuracy
35
- const stagingMetrics = await this.store.getStagingMetrics(agentId);
36
- const totalStaged = stagingMetrics.promoted + stagingMetrics.discarded + stagingMetrics.expired;
37
- const promotionPrecision = totalStaged > 0 ? stagingMetrics.promoted / totalStaged : 0;
38
-
39
- // Memory health
40
- const activeEngrams = await this.store.getEngramsByAgent(agentId, 'active');
41
- const stagingEngrams = await this.store.getEngramsByAgent(agentId, 'staging');
42
- const retractedEngrams = (await this.store.getEngramsByAgent(agentId, undefined, true))
43
- .filter(e => e.retracted);
44
- const allAssociations = await this.store.getAllAssociations(agentId);
45
-
46
- const avgConfidence = activeEngrams.length > 0
47
- ? activeEngrams.reduce((sum, e) => sum + e.confidence, 0) / activeEngrams.length
48
- : 0;
49
-
50
- // Edge utility — % of edges that have been used in activation
51
- const usedEdges = allAssociations.filter(a => a.activationCount > 0);
52
- const edgeUtility = allAssociations.length > 0
53
- ? usedEdges.length / allAssociations.length
54
- : 0;
55
-
56
- // Edge survival — average age of edges that are still above minimum weight
57
- const livingEdges = allAssociations.filter(a => a.weight > 0.01);
58
- const avgSurvival = livingEdges.length > 0
59
- ? livingEdges.reduce((sum, a) =>
60
- sum + (Date.now() - a.createdAt.getTime()) / (1000 * 60 * 60 * 24), 0
61
- ) / livingEdges.length
62
- : 0;
63
-
64
- // Activation performance stats
65
- const activationStats = await this.store.getActivationStats(agentId, windowHours);
66
-
67
- // Consolidated count
68
- const consolidatedCount = await this.store.getConsolidatedCount(agentId);
69
-
70
- return {
71
- agentId,
72
- timestamp: new Date(),
73
- window,
74
-
75
- activationCount: activationStats.count,
76
- avgPrecisionAtK: precision,
77
- avgLatencyMs: activationStats.avgLatencyMs,
78
- p95LatencyMs: activationStats.p95LatencyMs,
79
-
80
- totalEdges: allAssociations.length,
81
- edgesUsedInActivation: usedEdges.length,
82
- edgeUtilityRate: edgeUtility,
83
- avgEdgeSurvivalDays: avgSurvival,
84
-
85
- totalStaged: totalStaged,
86
- promotedCount: stagingMetrics.promoted,
87
- discardedCount: stagingMetrics.discarded,
88
- promotionPrecision,
89
- discardRegret: 0, // Requires tracking discarded-then-rediscovered items
90
-
91
- activeEngramCount: activeEngrams.length,
92
- stagingEngramCount: stagingEngrams.length,
93
- retractedCount: retractedEngrams.length,
94
- consolidatedCount,
95
- avgConfidence,
96
-
97
- staleUsageCount: 0, // Requires per-activation age/confidence tracking
98
- retractionRate: retractedEngrams.length /
99
- Math.max(activeEngrams.length + retractedEngrams.length, 1),
100
- };
101
- }
102
- }
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Evaluation Engine — measures whether memory actually helps.
5
+ *
6
+ * Four dimensions (from Codex):
7
+ * 1. Retrieval quality — precision@k, latency
8
+ * 2. Connection quality — edge utility, stability
9
+ * 3. Staging accuracy — promotion precision, discard regret
10
+ * 4. Memory health — contamination tracking, confidence distribution
11
+ *
12
+ * Task impact (with/without memory) is measured externally via TaskTrial records.
13
+ */
14
+
15
+ import type { IEngramStore as EngramStore } from '../storage/store.js';
16
+ import type { EvalMetrics } from '../types/index.js';
17
+
18
+ export class EvalEngine {
19
+ private store: EngramStore;
20
+
21
+ constructor(store: EngramStore) {
22
+ this.store = store;
23
+ }
24
+
25
+ /**
26
+ * Compute aggregate metrics for an agent over a time window.
27
+ */
28
+ async computeMetrics(agentId: string, windowHours: number = 24): Promise<EvalMetrics> {
29
+ const window = windowHours <= 24 ? '24h' : `${Math.round(windowHours / 24)}d`;
30
+
31
+ // Retrieval quality
32
+ const precision = await this.store.getRetrievalPrecision(agentId, windowHours);
33
+
34
+ // Staging accuracy
35
+ const stagingMetrics = await this.store.getStagingMetrics(agentId);
36
+ const totalStaged = stagingMetrics.promoted + stagingMetrics.discarded + stagingMetrics.expired;
37
+ const promotionPrecision = totalStaged > 0 ? stagingMetrics.promoted / totalStaged : 0;
38
+
39
+ // Memory health
40
+ const activeEngrams = await this.store.getEngramsByAgent(agentId, 'active');
41
+ const stagingEngrams = await this.store.getEngramsByAgent(agentId, 'staging');
42
+ const retractedEngrams = (await this.store.getEngramsByAgent(agentId, undefined, true))
43
+ .filter(e => e.retracted);
44
+ const allAssociations = await this.store.getAllAssociations(agentId);
45
+
46
+ const avgConfidence = activeEngrams.length > 0
47
+ ? activeEngrams.reduce((sum, e) => sum + e.confidence, 0) / activeEngrams.length
48
+ : 0;
49
+
50
+ // Edge utility — % of edges that have been used in activation
51
+ const usedEdges = allAssociations.filter(a => a.activationCount > 0);
52
+ const edgeUtility = allAssociations.length > 0
53
+ ? usedEdges.length / allAssociations.length
54
+ : 0;
55
+
56
+ // Edge survival — average age of edges that are still above minimum weight
57
+ const livingEdges = allAssociations.filter(a => a.weight > 0.01);
58
+ const avgSurvival = livingEdges.length > 0
59
+ ? livingEdges.reduce((sum, a) =>
60
+ sum + (Date.now() - a.createdAt.getTime()) / (1000 * 60 * 60 * 24), 0
61
+ ) / livingEdges.length
62
+ : 0;
63
+
64
+ // Activation performance stats
65
+ const activationStats = await this.store.getActivationStats(agentId, windowHours);
66
+
67
+ // Consolidated count
68
+ const consolidatedCount = await this.store.getConsolidatedCount(agentId);
69
+
70
+ return {
71
+ agentId,
72
+ timestamp: new Date(),
73
+ window,
74
+
75
+ activationCount: activationStats.count,
76
+ avgPrecisionAtK: precision,
77
+ avgLatencyMs: activationStats.avgLatencyMs,
78
+ p95LatencyMs: activationStats.p95LatencyMs,
79
+
80
+ totalEdges: allAssociations.length,
81
+ edgesUsedInActivation: usedEdges.length,
82
+ edgeUtilityRate: edgeUtility,
83
+ avgEdgeSurvivalDays: avgSurvival,
84
+
85
+ totalStaged: totalStaged,
86
+ promotedCount: stagingMetrics.promoted,
87
+ discardedCount: stagingMetrics.discarded,
88
+ promotionPrecision,
89
+ discardRegret: 0, // Requires tracking discarded-then-rediscovered items
90
+
91
+ activeEngramCount: activeEngrams.length,
92
+ stagingEngramCount: stagingEngrams.length,
93
+ retractedCount: retractedEngrams.length,
94
+ consolidatedCount,
95
+ avgConfidence,
96
+
97
+ staleUsageCount: 0, // Requires per-activation age/confidence tracking
98
+ retractionRate: retractedEngrams.length /
99
+ Math.max(activeEngrams.length + retractedEngrams.length, 1),
100
+ };
101
+ }
102
+ }
@@ -1,101 +1,101 @@
1
- // Copyright 2026 Robert Winter / Complete Ideas
2
- // SPDX-License-Identifier: Apache-2.0
3
- /**
4
- * Eviction Engine — capacity enforcement and edge pruning.
5
- *
6
- * When memory budgets are exceeded:
7
- * 1. Archive lowest-value active engrams
8
- * 2. Delete expired staging engrams
9
- * 3. Prune weakest edges when per-engram cap exceeded
10
- * 4. Decay unused association weights over time
11
- */
12
-
13
- import type { IEngramStore as EngramStore } from '../storage/store.js';
14
- import type { AgentConfig } from '../types/agent.js';
15
- import { decayAssociation } from '../core/hebbian.js';
16
-
17
- export class EvictionEngine {
18
- private store: EngramStore;
19
-
20
- constructor(store: EngramStore) {
21
- this.store = store;
22
- }
23
-
24
- /**
25
- * Check capacity budgets and evict if needed.
26
- * Returns count of evicted engrams.
27
- */
28
- async enforceCapacity(agentId: string, config: AgentConfig): Promise<{ evicted: number; edgesPruned: number }> {
29
- let evicted = 0;
30
- let edgesPruned = 0;
31
-
32
- // Active engram budget
33
- const activeCount = await this.store.getActiveCount(agentId);
34
- if (activeCount > config.maxActiveEngrams) {
35
- const excess = activeCount - config.maxActiveEngrams;
36
- const candidates = await this.store.getEvictionCandidates(agentId, excess);
37
- for (const engram of candidates) {
38
- await this.store.updateStage(engram.id, 'archived');
39
- evicted++;
40
- }
41
- }
42
-
43
- // Staging budget
44
- const stagingCount = await this.store.getStagingCount(agentId);
45
- if (stagingCount > config.maxStagingEngrams) {
46
- const expired = await this.store.getExpiredStaging();
47
- for (const engram of expired) {
48
- await this.store.deleteEngram(engram.id);
49
- evicted++;
50
- }
51
- }
52
-
53
- // Edge pruning — cap per engram
54
- const engrams = await this.store.getEngramsByAgent(agentId, 'active');
55
- for (const engram of engrams) {
56
- const edgeCount = await this.store.countAssociationsFor(engram.id);
57
- if (edgeCount > config.maxEdgesPerEngram) {
58
- // Remove weakest edges until under cap
59
- let toRemove = edgeCount - config.maxEdgesPerEngram;
60
- while (toRemove > 0) {
61
- const weakest = await this.store.getWeakestAssociation(engram.id);
62
- if (weakest) {
63
- await this.store.deleteAssociation(weakest.id);
64
- edgesPruned++;
65
- }
66
- toRemove--;
67
- }
68
- }
69
- }
70
-
71
- return { evicted, edgesPruned };
72
- }
73
-
74
- /**
75
- * Decay all association weights based on time since last activation.
76
- * Run periodically (e.g., daily).
77
- */
78
- async decayEdges(agentId: string, halfLifeDays: number = 7): Promise<number> {
79
- const associations = await this.store.getAllAssociations(agentId);
80
- let decayed = 0;
81
-
82
- for (const assoc of associations) {
83
- const daysSince = (Date.now() - assoc.lastActivated.getTime()) / (1000 * 60 * 60 * 24);
84
- if (daysSince < 0.5) continue; // Skip recently activated
85
-
86
- const newWeight = decayAssociation(assoc.weight, daysSince, halfLifeDays);
87
- if (newWeight < 0.01) {
88
- // Below minimum useful weight — prune
89
- await this.store.deleteAssociation(assoc.id);
90
- decayed++;
91
- } else if (Math.abs(newWeight - assoc.weight) > 0.001) {
92
- await this.store.upsertAssociation(
93
- assoc.fromEngramId, assoc.toEngramId, newWeight, assoc.type, assoc.confidence
94
- );
95
- decayed++;
96
- }
97
- }
98
-
99
- return decayed;
100
- }
101
- }
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Eviction Engine — capacity enforcement and edge pruning.
5
+ *
6
+ * When memory budgets are exceeded:
7
+ * 1. Archive lowest-value active engrams
8
+ * 2. Delete expired staging engrams
9
+ * 3. Prune weakest edges when per-engram cap exceeded
10
+ * 4. Decay unused association weights over time
11
+ */
12
+
13
+ import type { IEngramStore as EngramStore } from '../storage/store.js';
14
+ import type { AgentConfig } from '../types/agent.js';
15
+ import { decayAssociation } from '../core/hebbian.js';
16
+
17
+ export class EvictionEngine {
18
+ private store: EngramStore;
19
+
20
+ constructor(store: EngramStore) {
21
+ this.store = store;
22
+ }
23
+
24
+ /**
25
+ * Check capacity budgets and evict if needed.
26
+ * Returns count of evicted engrams.
27
+ */
28
+ async enforceCapacity(agentId: string, config: AgentConfig): Promise<{ evicted: number; edgesPruned: number }> {
29
+ let evicted = 0;
30
+ let edgesPruned = 0;
31
+
32
+ // Active engram budget
33
+ const activeCount = await this.store.getActiveCount(agentId);
34
+ if (activeCount > config.maxActiveEngrams) {
35
+ const excess = activeCount - config.maxActiveEngrams;
36
+ const candidates = await this.store.getEvictionCandidates(agentId, excess);
37
+ for (const engram of candidates) {
38
+ await this.store.updateStage(engram.id, 'archived');
39
+ evicted++;
40
+ }
41
+ }
42
+
43
+ // Staging budget
44
+ const stagingCount = await this.store.getStagingCount(agentId);
45
+ if (stagingCount > config.maxStagingEngrams) {
46
+ const expired = await this.store.getExpiredStaging();
47
+ for (const engram of expired) {
48
+ await this.store.deleteEngram(engram.id);
49
+ evicted++;
50
+ }
51
+ }
52
+
53
+ // Edge pruning — cap per engram
54
+ const engrams = await this.store.getEngramsByAgent(agentId, 'active');
55
+ for (const engram of engrams) {
56
+ const edgeCount = await this.store.countAssociationsFor(engram.id);
57
+ if (edgeCount > config.maxEdgesPerEngram) {
58
+ // Remove weakest edges until under cap
59
+ let toRemove = edgeCount - config.maxEdgesPerEngram;
60
+ while (toRemove > 0) {
61
+ const weakest = await this.store.getWeakestAssociation(engram.id);
62
+ if (weakest) {
63
+ await this.store.deleteAssociation(weakest.id);
64
+ edgesPruned++;
65
+ }
66
+ toRemove--;
67
+ }
68
+ }
69
+ }
70
+
71
+ return { evicted, edgesPruned };
72
+ }
73
+
74
+ /**
75
+ * Decay all association weights based on time since last activation.
76
+ * Run periodically (e.g., daily).
77
+ */
78
+ async decayEdges(agentId: string, halfLifeDays: number = 7): Promise<number> {
79
+ const associations = await this.store.getAllAssociations(agentId);
80
+ let decayed = 0;
81
+
82
+ for (const assoc of associations) {
83
+ const daysSince = (Date.now() - assoc.lastActivated.getTime()) / (1000 * 60 * 60 * 24);
84
+ if (daysSince < 0.5) continue; // Skip recently activated
85
+
86
+ const newWeight = decayAssociation(assoc.weight, daysSince, halfLifeDays);
87
+ if (newWeight < 0.01) {
88
+ // Below minimum useful weight — prune
89
+ await this.store.deleteAssociation(assoc.id);
90
+ decayed++;
91
+ } else if (Math.abs(newWeight - assoc.weight) > 0.001) {
92
+ await this.store.upsertAssociation(
93
+ assoc.fromEngramId, assoc.toEngramId, newWeight, assoc.type, assoc.confidence
94
+ );
95
+ decayed++;
96
+ }
97
+ }
98
+
99
+ return decayed;
100
+ }
101
+ }
@@ -1,8 +1,8 @@
1
- // Copyright 2026 Robert Winter / Complete Ideas
2
- // SPDX-License-Identifier: Apache-2.0
3
- export * from './activation.js';
4
- export * from './staging.js';
5
- export * from './connections.js';
6
- export * from './eviction.js';
7
- export * from './retraction.js';
8
- export * from './eval.js';
1
+ // Copyright 2026 Robert Winter / Complete Ideas
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export * from './activation.js';
4
+ export * from './staging.js';
5
+ export * from './connections.js';
6
+ export * from './eviction.js';
7
+ export * from './retraction.js';
8
+ export * from './eval.js';