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.
- package/README.md +207 -46
- package/dist/api/routes.js +1 -1
- package/dist/cli/migrate.js +29 -29
- package/dist/cli.js +1 -1
- package/dist/coordination/circuit-breaker.js +23 -23
- package/dist/core/write-pipeline.d.ts.map +1 -1
- package/dist/core/write-pipeline.js +17 -0
- package/dist/core/write-pipeline.js.map +1 -1
- package/dist/engine/activation.d.ts +28 -0
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +341 -11
- package/dist/engine/activation.js.map +1 -1
- package/dist/engine/connections.d.ts +12 -0
- package/dist/engine/connections.d.ts.map +1 -1
- package/dist/engine/connections.js +95 -0
- package/dist/engine/connections.js.map +1 -1
- package/dist/mcp.js +2 -2
- package/dist/storage/pglite-schema.js +143 -143
- package/dist/storage/pglite.js +138 -138
- package/dist/types/engram.d.ts +1 -0
- package/dist/types/engram.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +3 -3
- package/src/api/routes.ts +1 -1
- package/src/cli/migrate.ts +307 -307
- package/src/cli.ts +1 -1
- package/src/coordination/circuit-breaker.ts +83 -83
- package/src/coordination/failure-modes.ts +50 -50
- package/src/core/decay.ts +63 -63
- package/src/core/embeddings.ts +110 -110
- 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/write-pipeline.ts +15 -0
- package/src/engine/activation.ts +328 -11
- package/src/engine/confidence.ts +120 -120
- package/src/engine/connections.ts +94 -0
- package/src/engine/consolidation-scheduler.ts +242 -242
- 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 +366 -366
- package/src/engine/staging.ts +74 -74
- package/src/mcp.ts +2 -2
- package/src/storage/factory.ts +147 -147
- package/src/storage/index.ts +3 -3
- package/src/storage/pglite-schema.ts +166 -166
- package/src/storage/pglite.ts +1363 -1363
- 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 +1 -0
- package/src/types/eval.ts +100 -100
- package/src/types/index.ts +6 -6
package/src/engine/eval.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/engine/eviction.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/engine/index.ts
CHANGED
|
@@ -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';
|