agent-working-memory 0.5.4 → 0.5.6
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 +87 -46
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +21 -5
- package/dist/api/routes.js.map +1 -1
- package/dist/cli.js +67 -67
- package/dist/coordination/index.d.ts +11 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +39 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/mcp-tools.d.ts +8 -0
- package/dist/coordination/mcp-tools.d.ts.map +1 -0
- package/dist/coordination/mcp-tools.js +216 -0
- package/dist/coordination/mcp-tools.js.map +1 -0
- package/dist/coordination/routes.d.ts +9 -0
- package/dist/coordination/routes.d.ts.map +1 -0
- package/dist/coordination/routes.js +434 -0
- package/dist/coordination/routes.js.map +1 -0
- package/dist/coordination/schema.d.ts +12 -0
- package/dist/coordination/schema.d.ts.map +1 -0
- package/dist/coordination/schema.js +91 -0
- package/dist/coordination/schema.js.map +1 -0
- package/dist/coordination/schemas.d.ts +208 -0
- package/dist/coordination/schemas.d.ts.map +1 -0
- package/dist/coordination/schemas.js +109 -0
- package/dist/coordination/schemas.js.map +1 -0
- package/dist/coordination/stale.d.ts +25 -0
- package/dist/coordination/stale.d.ts.map +1 -0
- package/dist/coordination/stale.js +53 -0
- package/dist/coordination/stale.js.map +1 -0
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +90 -79
- package/dist/mcp.js.map +1 -1
- package/dist/storage/sqlite.d.ts +3 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +285 -281
- package/dist/storage/sqlite.js.map +1 -1
- package/package.json +55 -55
- package/src/api/index.ts +3 -3
- package/src/api/routes.ts +551 -536
- package/src/cli.ts +397 -397
- package/src/coordination/index.ts +47 -0
- package/src/coordination/mcp-tools.ts +313 -0
- package/src/coordination/routes.ts +656 -0
- package/src/coordination/schema.ts +94 -0
- package/src/coordination/schemas.ts +136 -0
- package/src/coordination/stale.ts +89 -0
- package/src/core/decay.ts +63 -63
- package/src/core/embeddings.ts +88 -88
- package/src/core/hebbian.ts +93 -93
- package/src/core/index.ts +5 -5
- package/src/core/logger.ts +36 -36
- package/src/core/query-expander.ts +66 -66
- package/src/core/reranker.ts +101 -101
- package/src/engine/activation.ts +656 -656
- package/src/engine/connections.ts +103 -103
- package/src/engine/consolidation-scheduler.ts +125 -125
- package/src/engine/eval.ts +102 -102
- package/src/engine/eviction.ts +101 -101
- package/src/engine/index.ts +8 -8
- package/src/engine/retraction.ts +100 -100
- package/src/engine/staging.ts +74 -74
- package/src/index.ts +137 -121
- package/src/mcp.ts +1024 -1013
- package/src/storage/index.ts +3 -3
- package/src/storage/sqlite.ts +968 -963
- package/src/types/agent.ts +67 -67
- package/src/types/checkpoint.ts +46 -46
- package/src/types/engram.ts +217 -217
- package/src/types/eval.ts +100 -100
- package/src/types/index.ts +6 -6
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 { EngramStore } from '../storage/sqlite.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
|
-
enforceCapacity(agentId: string, config: AgentConfig): { evicted: number; edgesPruned: number } {
|
|
29
|
-
let evicted = 0;
|
|
30
|
-
let edgesPruned = 0;
|
|
31
|
-
|
|
32
|
-
// Active engram budget
|
|
33
|
-
const activeCount = this.store.getActiveCount(agentId);
|
|
34
|
-
if (activeCount > config.maxActiveEngrams) {
|
|
35
|
-
const excess = activeCount - config.maxActiveEngrams;
|
|
36
|
-
const candidates = this.store.getEvictionCandidates(agentId, excess);
|
|
37
|
-
for (const engram of candidates) {
|
|
38
|
-
this.store.updateStage(engram.id, 'archived');
|
|
39
|
-
evicted++;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Staging budget
|
|
44
|
-
const stagingCount = this.store.getStagingCount(agentId);
|
|
45
|
-
if (stagingCount > config.maxStagingEngrams) {
|
|
46
|
-
const expired = this.store.getExpiredStaging();
|
|
47
|
-
for (const engram of expired) {
|
|
48
|
-
this.store.deleteEngram(engram.id);
|
|
49
|
-
evicted++;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Edge pruning — cap per engram
|
|
54
|
-
const engrams = this.store.getEngramsByAgent(agentId, 'active');
|
|
55
|
-
for (const engram of engrams) {
|
|
56
|
-
const edgeCount = 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 = this.store.getWeakestAssociation(engram.id);
|
|
62
|
-
if (weakest) {
|
|
63
|
-
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
|
-
decayEdges(agentId: string, halfLifeDays: number = 7): number {
|
|
79
|
-
const associations = 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
|
-
this.store.deleteAssociation(assoc.id);
|
|
90
|
-
decayed++;
|
|
91
|
-
} else if (Math.abs(newWeight - assoc.weight) > 0.001) {
|
|
92
|
-
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 { EngramStore } from '../storage/sqlite.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
|
+
enforceCapacity(agentId: string, config: AgentConfig): { evicted: number; edgesPruned: number } {
|
|
29
|
+
let evicted = 0;
|
|
30
|
+
let edgesPruned = 0;
|
|
31
|
+
|
|
32
|
+
// Active engram budget
|
|
33
|
+
const activeCount = this.store.getActiveCount(agentId);
|
|
34
|
+
if (activeCount > config.maxActiveEngrams) {
|
|
35
|
+
const excess = activeCount - config.maxActiveEngrams;
|
|
36
|
+
const candidates = this.store.getEvictionCandidates(agentId, excess);
|
|
37
|
+
for (const engram of candidates) {
|
|
38
|
+
this.store.updateStage(engram.id, 'archived');
|
|
39
|
+
evicted++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Staging budget
|
|
44
|
+
const stagingCount = this.store.getStagingCount(agentId);
|
|
45
|
+
if (stagingCount > config.maxStagingEngrams) {
|
|
46
|
+
const expired = this.store.getExpiredStaging();
|
|
47
|
+
for (const engram of expired) {
|
|
48
|
+
this.store.deleteEngram(engram.id);
|
|
49
|
+
evicted++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Edge pruning — cap per engram
|
|
54
|
+
const engrams = this.store.getEngramsByAgent(agentId, 'active');
|
|
55
|
+
for (const engram of engrams) {
|
|
56
|
+
const edgeCount = 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 = this.store.getWeakestAssociation(engram.id);
|
|
62
|
+
if (weakest) {
|
|
63
|
+
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
|
+
decayEdges(agentId: string, halfLifeDays: number = 7): number {
|
|
79
|
+
const associations = 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
|
+
this.store.deleteAssociation(assoc.id);
|
|
90
|
+
decayed++;
|
|
91
|
+
} else if (Math.abs(newWeight - assoc.weight) > 0.001) {
|
|
92
|
+
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';
|
package/src/engine/retraction.ts
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
// Copyright 2026 Robert Winter / Complete Ideas
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
/**
|
|
4
|
-
* Retraction Engine — negative memory / invalidation.
|
|
5
|
-
*
|
|
6
|
-
* Codex critique: "You need explicit anti-salience for wrong info.
|
|
7
|
-
* Otherwise wrong memories persist and compound mistakes."
|
|
8
|
-
*
|
|
9
|
-
* When an agent discovers a memory is wrong:
|
|
10
|
-
* 1. The original engram is marked retracted (not deleted — audit trail)
|
|
11
|
-
* 2. An invalidation association is created
|
|
12
|
-
* 3. Optionally, a counter-engram with correct info is created
|
|
13
|
-
* 4. Confidence of associated engrams is reduced (contamination check)
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { EngramStore } from '../storage/sqlite.js';
|
|
17
|
-
import type { Retraction } from '../types/index.js';
|
|
18
|
-
|
|
19
|
-
export class RetractionEngine {
|
|
20
|
-
private store: EngramStore;
|
|
21
|
-
|
|
22
|
-
constructor(store: EngramStore) {
|
|
23
|
-
this.store = store;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Retract a memory — mark it invalid and optionally create a correction.
|
|
28
|
-
*/
|
|
29
|
-
retract(retraction: Retraction): { retractedId: string; correctionId: string | null; associatesAffected: number } {
|
|
30
|
-
const target = this.store.getEngram(retraction.targetEngramId);
|
|
31
|
-
if (!target) {
|
|
32
|
-
throw new Error(`Engram ${retraction.targetEngramId} not found`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Mark the original as retracted
|
|
36
|
-
this.store.retractEngram(target.id, null);
|
|
37
|
-
|
|
38
|
-
let correctionId: string | null = null;
|
|
39
|
-
|
|
40
|
-
// Create counter-engram if correction content provided
|
|
41
|
-
if (retraction.counterContent) {
|
|
42
|
-
const correction = this.store.createEngram({
|
|
43
|
-
agentId: retraction.agentId,
|
|
44
|
-
concept: `correction:${target.concept}`,
|
|
45
|
-
content: retraction.counterContent,
|
|
46
|
-
tags: [...target.tags, 'correction', 'retraction'],
|
|
47
|
-
salience: Math.max(target.salience, 0.6), // Corrections are at least moderately salient
|
|
48
|
-
confidence: 0.7,
|
|
49
|
-
reasonCodes: ['retraction_correction', `invalidates:${target.id}`],
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
correctionId = correction.id;
|
|
53
|
-
|
|
54
|
-
// Create invalidation link
|
|
55
|
-
this.store.upsertAssociation(
|
|
56
|
-
correction.id, target.id, 1.0, 'invalidation', 1.0
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
// Update retracted_by to point to correction
|
|
60
|
-
this.store.retractEngram(target.id, correction.id);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Reduce confidence of closely associated engrams (contamination spread)
|
|
64
|
-
const associatesAffected = this.propagateConfidenceReduction(target.id, 0.1, 1);
|
|
65
|
-
|
|
66
|
-
return { retractedId: target.id, correctionId, associatesAffected };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Reduce confidence of engrams associated with a retracted engram.
|
|
71
|
-
* Shallow propagation (depth 1) to avoid over-penalizing.
|
|
72
|
-
*/
|
|
73
|
-
private propagateConfidenceReduction(
|
|
74
|
-
engramId: string,
|
|
75
|
-
penalty: number,
|
|
76
|
-
maxDepth: number,
|
|
77
|
-
currentDepth: number = 0
|
|
78
|
-
): number {
|
|
79
|
-
if (currentDepth >= maxDepth) return 0;
|
|
80
|
-
|
|
81
|
-
let affected = 0;
|
|
82
|
-
const associations = this.store.getAssociationsFor(engramId);
|
|
83
|
-
for (const assoc of associations) {
|
|
84
|
-
if (assoc.type === 'invalidation') continue; // Don't penalize corrections
|
|
85
|
-
|
|
86
|
-
const neighborId = assoc.fromEngramId === engramId
|
|
87
|
-
? assoc.toEngramId
|
|
88
|
-
: assoc.fromEngramId;
|
|
89
|
-
const neighbor = this.store.getEngram(neighborId);
|
|
90
|
-
if (!neighbor || neighbor.retracted) continue;
|
|
91
|
-
|
|
92
|
-
// Scale penalty by association weight
|
|
93
|
-
const scaledPenalty = penalty * assoc.weight;
|
|
94
|
-
const newConfidence = Math.max(0.1, neighbor.confidence - scaledPenalty);
|
|
95
|
-
this.store.updateConfidence(neighborId, newConfidence);
|
|
96
|
-
affected++;
|
|
97
|
-
}
|
|
98
|
-
return affected;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
1
|
+
// Copyright 2026 Robert Winter / Complete Ideas
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Retraction Engine — negative memory / invalidation.
|
|
5
|
+
*
|
|
6
|
+
* Codex critique: "You need explicit anti-salience for wrong info.
|
|
7
|
+
* Otherwise wrong memories persist and compound mistakes."
|
|
8
|
+
*
|
|
9
|
+
* When an agent discovers a memory is wrong:
|
|
10
|
+
* 1. The original engram is marked retracted (not deleted — audit trail)
|
|
11
|
+
* 2. An invalidation association is created
|
|
12
|
+
* 3. Optionally, a counter-engram with correct info is created
|
|
13
|
+
* 4. Confidence of associated engrams is reduced (contamination check)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { EngramStore } from '../storage/sqlite.js';
|
|
17
|
+
import type { Retraction } from '../types/index.js';
|
|
18
|
+
|
|
19
|
+
export class RetractionEngine {
|
|
20
|
+
private store: EngramStore;
|
|
21
|
+
|
|
22
|
+
constructor(store: EngramStore) {
|
|
23
|
+
this.store = store;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Retract a memory — mark it invalid and optionally create a correction.
|
|
28
|
+
*/
|
|
29
|
+
retract(retraction: Retraction): { retractedId: string; correctionId: string | null; associatesAffected: number } {
|
|
30
|
+
const target = this.store.getEngram(retraction.targetEngramId);
|
|
31
|
+
if (!target) {
|
|
32
|
+
throw new Error(`Engram ${retraction.targetEngramId} not found`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Mark the original as retracted
|
|
36
|
+
this.store.retractEngram(target.id, null);
|
|
37
|
+
|
|
38
|
+
let correctionId: string | null = null;
|
|
39
|
+
|
|
40
|
+
// Create counter-engram if correction content provided
|
|
41
|
+
if (retraction.counterContent) {
|
|
42
|
+
const correction = this.store.createEngram({
|
|
43
|
+
agentId: retraction.agentId,
|
|
44
|
+
concept: `correction:${target.concept}`,
|
|
45
|
+
content: retraction.counterContent,
|
|
46
|
+
tags: [...target.tags, 'correction', 'retraction'],
|
|
47
|
+
salience: Math.max(target.salience, 0.6), // Corrections are at least moderately salient
|
|
48
|
+
confidence: 0.7,
|
|
49
|
+
reasonCodes: ['retraction_correction', `invalidates:${target.id}`],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
correctionId = correction.id;
|
|
53
|
+
|
|
54
|
+
// Create invalidation link
|
|
55
|
+
this.store.upsertAssociation(
|
|
56
|
+
correction.id, target.id, 1.0, 'invalidation', 1.0
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Update retracted_by to point to correction
|
|
60
|
+
this.store.retractEngram(target.id, correction.id);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Reduce confidence of closely associated engrams (contamination spread)
|
|
64
|
+
const associatesAffected = this.propagateConfidenceReduction(target.id, 0.1, 1);
|
|
65
|
+
|
|
66
|
+
return { retractedId: target.id, correctionId, associatesAffected };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Reduce confidence of engrams associated with a retracted engram.
|
|
71
|
+
* Shallow propagation (depth 1) to avoid over-penalizing.
|
|
72
|
+
*/
|
|
73
|
+
private propagateConfidenceReduction(
|
|
74
|
+
engramId: string,
|
|
75
|
+
penalty: number,
|
|
76
|
+
maxDepth: number,
|
|
77
|
+
currentDepth: number = 0
|
|
78
|
+
): number {
|
|
79
|
+
if (currentDepth >= maxDepth) return 0;
|
|
80
|
+
|
|
81
|
+
let affected = 0;
|
|
82
|
+
const associations = this.store.getAssociationsFor(engramId);
|
|
83
|
+
for (const assoc of associations) {
|
|
84
|
+
if (assoc.type === 'invalidation') continue; // Don't penalize corrections
|
|
85
|
+
|
|
86
|
+
const neighborId = assoc.fromEngramId === engramId
|
|
87
|
+
? assoc.toEngramId
|
|
88
|
+
: assoc.fromEngramId;
|
|
89
|
+
const neighbor = this.store.getEngram(neighborId);
|
|
90
|
+
if (!neighbor || neighbor.retracted) continue;
|
|
91
|
+
|
|
92
|
+
// Scale penalty by association weight
|
|
93
|
+
const scaledPenalty = penalty * assoc.weight;
|
|
94
|
+
const newConfidence = Math.max(0.1, neighbor.confidence - scaledPenalty);
|
|
95
|
+
this.store.updateConfidence(neighborId, newConfidence);
|
|
96
|
+
affected++;
|
|
97
|
+
}
|
|
98
|
+
return affected;
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/engine/staging.ts
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
// Copyright 2026 Robert Winter / Complete Ideas
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
/**
|
|
4
|
-
* Staging Buffer — weak signal handler.
|
|
5
|
-
*
|
|
6
|
-
* Observations that don't meet the salience threshold for active memory
|
|
7
|
-
* go to staging. The staging buffer periodically:
|
|
8
|
-
* 1. Checks staged engrams against active memory for resonance
|
|
9
|
-
* 2. Promotes resonant engrams to active
|
|
10
|
-
* 3. Discards expired engrams that never resonated
|
|
11
|
-
*
|
|
12
|
-
* Modeled on hippocampal consolidation — provisional encoding
|
|
13
|
-
* that only persists if reactivated.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { EngramStore } from '../storage/sqlite.js';
|
|
17
|
-
import type { ActivationEngine } from './activation.js';
|
|
18
|
-
|
|
19
|
-
export class StagingBuffer {
|
|
20
|
-
private store: EngramStore;
|
|
21
|
-
private engine: ActivationEngine;
|
|
22
|
-
private checkInterval: ReturnType<typeof setInterval> | null = null;
|
|
23
|
-
|
|
24
|
-
constructor(store: EngramStore, engine: ActivationEngine) {
|
|
25
|
-
this.store = store;
|
|
26
|
-
this.engine = engine;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Start the periodic staging check.
|
|
31
|
-
*/
|
|
32
|
-
start(intervalMs: number = 60_000): void {
|
|
33
|
-
this.checkInterval = setInterval(() => this.sweep(), intervalMs);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
stop(): void {
|
|
37
|
-
if (this.checkInterval) {
|
|
38
|
-
clearInterval(this.checkInterval);
|
|
39
|
-
this.checkInterval = null;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Sweep staged engrams: promote or discard.
|
|
45
|
-
*/
|
|
46
|
-
async sweep(): Promise<{ promoted: string[]; discarded: string[] }> {
|
|
47
|
-
const promoted: string[] = [];
|
|
48
|
-
const discarded: string[] = [];
|
|
49
|
-
|
|
50
|
-
const expired = this.store.getExpiredStaging();
|
|
51
|
-
for (const engram of expired) {
|
|
52
|
-
// Check if this engram resonates with active memory
|
|
53
|
-
const results = await this.engine.activate({
|
|
54
|
-
agentId: engram.agentId,
|
|
55
|
-
context: `${engram.concept} ${engram.content}`,
|
|
56
|
-
limit: 3,
|
|
57
|
-
minScore: 0.3,
|
|
58
|
-
internal: true,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
if (results.length > 0) {
|
|
62
|
-
// Resonance found — promote to active
|
|
63
|
-
this.store.updateStage(engram.id, 'active');
|
|
64
|
-
promoted.push(engram.id);
|
|
65
|
-
} else {
|
|
66
|
-
// No resonance — discard
|
|
67
|
-
this.store.deleteEngram(engram.id);
|
|
68
|
-
discarded.push(engram.id);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return { promoted, discarded };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
1
|
+
// Copyright 2026 Robert Winter / Complete Ideas
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Staging Buffer — weak signal handler.
|
|
5
|
+
*
|
|
6
|
+
* Observations that don't meet the salience threshold for active memory
|
|
7
|
+
* go to staging. The staging buffer periodically:
|
|
8
|
+
* 1. Checks staged engrams against active memory for resonance
|
|
9
|
+
* 2. Promotes resonant engrams to active
|
|
10
|
+
* 3. Discards expired engrams that never resonated
|
|
11
|
+
*
|
|
12
|
+
* Modeled on hippocampal consolidation — provisional encoding
|
|
13
|
+
* that only persists if reactivated.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { EngramStore } from '../storage/sqlite.js';
|
|
17
|
+
import type { ActivationEngine } from './activation.js';
|
|
18
|
+
|
|
19
|
+
export class StagingBuffer {
|
|
20
|
+
private store: EngramStore;
|
|
21
|
+
private engine: ActivationEngine;
|
|
22
|
+
private checkInterval: ReturnType<typeof setInterval> | null = null;
|
|
23
|
+
|
|
24
|
+
constructor(store: EngramStore, engine: ActivationEngine) {
|
|
25
|
+
this.store = store;
|
|
26
|
+
this.engine = engine;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Start the periodic staging check.
|
|
31
|
+
*/
|
|
32
|
+
start(intervalMs: number = 60_000): void {
|
|
33
|
+
this.checkInterval = setInterval(() => this.sweep(), intervalMs);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
stop(): void {
|
|
37
|
+
if (this.checkInterval) {
|
|
38
|
+
clearInterval(this.checkInterval);
|
|
39
|
+
this.checkInterval = null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Sweep staged engrams: promote or discard.
|
|
45
|
+
*/
|
|
46
|
+
async sweep(): Promise<{ promoted: string[]; discarded: string[] }> {
|
|
47
|
+
const promoted: string[] = [];
|
|
48
|
+
const discarded: string[] = [];
|
|
49
|
+
|
|
50
|
+
const expired = this.store.getExpiredStaging();
|
|
51
|
+
for (const engram of expired) {
|
|
52
|
+
// Check if this engram resonates with active memory
|
|
53
|
+
const results = await this.engine.activate({
|
|
54
|
+
agentId: engram.agentId,
|
|
55
|
+
context: `${engram.concept} ${engram.content}`,
|
|
56
|
+
limit: 3,
|
|
57
|
+
minScore: 0.3,
|
|
58
|
+
internal: true,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (results.length > 0) {
|
|
62
|
+
// Resonance found — promote to active
|
|
63
|
+
this.store.updateStage(engram.id, 'active');
|
|
64
|
+
promoted.push(engram.id);
|
|
65
|
+
} else {
|
|
66
|
+
// No resonance — discard
|
|
67
|
+
this.store.deleteEngram(engram.id);
|
|
68
|
+
discarded.push(engram.id);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { promoted, discarded };
|
|
73
|
+
}
|
|
74
|
+
}
|