claude-cortex 1.0.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 +291 -0
- package/dist/api/events.d.ts +134 -0
- package/dist/api/events.d.ts.map +1 -0
- package/dist/api/events.js +73 -0
- package/dist/api/events.js.map +1 -0
- package/dist/api/visualization-server.d.ts +11 -0
- package/dist/api/visualization-server.d.ts.map +1 -0
- package/dist/api/visualization-server.js +653 -0
- package/dist/api/visualization-server.js.map +1 -0
- package/dist/context/project-context.d.ts +57 -0
- package/dist/context/project-context.d.ts.map +1 -0
- package/dist/context/project-context.js +135 -0
- package/dist/context/project-context.js.map +1 -0
- package/dist/database/init.d.ts +49 -0
- package/dist/database/init.d.ts.map +1 -0
- package/dist/database/init.js +336 -0
- package/dist/database/init.js.map +1 -0
- package/dist/embeddings/generator.d.ts +20 -0
- package/dist/embeddings/generator.d.ts.map +1 -0
- package/dist/embeddings/generator.js +77 -0
- package/dist/embeddings/generator.js.map +1 -0
- package/dist/embeddings/index.d.ts +2 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +2 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/errors.d.ts +74 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +131 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/activation.d.ts +69 -0
- package/dist/memory/activation.d.ts.map +1 -0
- package/dist/memory/activation.js +168 -0
- package/dist/memory/activation.js.map +1 -0
- package/dist/memory/consolidate.d.ts +96 -0
- package/dist/memory/consolidate.d.ts.map +1 -0
- package/dist/memory/consolidate.js +400 -0
- package/dist/memory/consolidate.js.map +1 -0
- package/dist/memory/contradiction.d.ts +69 -0
- package/dist/memory/contradiction.d.ts.map +1 -0
- package/dist/memory/contradiction.js +286 -0
- package/dist/memory/contradiction.js.map +1 -0
- package/dist/memory/decay.d.ts +62 -0
- package/dist/memory/decay.d.ts.map +1 -0
- package/dist/memory/decay.js +184 -0
- package/dist/memory/decay.js.map +1 -0
- package/dist/memory/salience.d.ts +36 -0
- package/dist/memory/salience.d.ts.map +1 -0
- package/dist/memory/salience.js +200 -0
- package/dist/memory/salience.js.map +1 -0
- package/dist/memory/similarity.d.ts +57 -0
- package/dist/memory/similarity.d.ts.map +1 -0
- package/dist/memory/similarity.js +114 -0
- package/dist/memory/similarity.js.map +1 -0
- package/dist/memory/store.d.ts +170 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +973 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/types.d.ts +91 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +30 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +466 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/context.d.ts +135 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +273 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/forget.d.ts +53 -0
- package/dist/tools/forget.d.ts.map +1 -0
- package/dist/tools/forget.js +179 -0
- package/dist/tools/forget.js.map +1 -0
- package/dist/tools/recall.d.ts +74 -0
- package/dist/tools/recall.d.ts.map +1 -0
- package/dist/tools/recall.js +140 -0
- package/dist/tools/recall.js.map +1 -0
- package/dist/tools/remember.d.ts +65 -0
- package/dist/tools/remember.d.ts.map +1 -0
- package/dist/tools/remember.js +147 -0
- package/dist/tools/remember.js.map +1 -0
- package/dist/worker/brain-worker.d.ts +100 -0
- package/dist/worker/brain-worker.d.ts.map +1 -0
- package/dist/worker/brain-worker.js +261 -0
- package/dist/worker/brain-worker.js.map +1 -0
- package/dist/worker/link-discovery.d.ts +47 -0
- package/dist/worker/link-discovery.d.ts.map +1 -0
- package/dist/worker/link-discovery.js +103 -0
- package/dist/worker/link-discovery.js.map +1 -0
- package/dist/worker/predictive-consolidation.d.ts +46 -0
- package/dist/worker/predictive-consolidation.d.ts.map +1 -0
- package/dist/worker/predictive-consolidation.js +110 -0
- package/dist/worker/predictive-consolidation.js.map +1 -0
- package/dist/worker/types.d.ts +91 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +22 -0
- package/dist/worker/types.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spreading Activation System
|
|
3
|
+
*
|
|
4
|
+
* Implements brain-like spreading activation where accessing a memory
|
|
5
|
+
* "primes" related memories, making them easier to recall.
|
|
6
|
+
*
|
|
7
|
+
* EPHEMERAL: This cache is session-only and does not persist to disk.
|
|
8
|
+
* Each MCP server restart starts with a fresh activation state.
|
|
9
|
+
*
|
|
10
|
+
* Based on spreading activation theory in cognitive psychology:
|
|
11
|
+
* - Collins & Loftus (1975) semantic network model
|
|
12
|
+
* - Activation spreads through associative links
|
|
13
|
+
* - Activation decays over time (exponential decay)
|
|
14
|
+
*/
|
|
15
|
+
import { getRelatedMemories } from './store.js';
|
|
16
|
+
/**
|
|
17
|
+
* In-memory activation cache
|
|
18
|
+
* Ephemeral - cleared on process restart
|
|
19
|
+
*/
|
|
20
|
+
const activationCache = new Map();
|
|
21
|
+
// Configuration
|
|
22
|
+
const DECAY_HALF_LIFE_MINUTES = 30; // Activation halves every 30 minutes
|
|
23
|
+
const SPREAD_FACTOR = 0.5; // How much activation spreads (50% of link strength)
|
|
24
|
+
const MAX_SPREAD_DEPTH = 1; // Only spread to direct neighbors (not neighbors of neighbors)
|
|
25
|
+
const MAX_ACTIVATION_BOOST = 0.2; // Cap search boost at 20%
|
|
26
|
+
/**
|
|
27
|
+
* Activate a memory and spread activation to linked memories
|
|
28
|
+
*
|
|
29
|
+
* When a memory is accessed, it becomes fully activated (1.0).
|
|
30
|
+
* Linked memories receive partial activation based on link strength.
|
|
31
|
+
*
|
|
32
|
+
* @param memoryId - The ID of the memory being accessed
|
|
33
|
+
*/
|
|
34
|
+
export function activateMemory(memoryId) {
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
// Fully activate the accessed memory
|
|
37
|
+
activationCache.set(memoryId, {
|
|
38
|
+
memoryId,
|
|
39
|
+
activationLevel: 1.0,
|
|
40
|
+
timestamp: now,
|
|
41
|
+
});
|
|
42
|
+
// Spread activation to linked memories
|
|
43
|
+
try {
|
|
44
|
+
const related = getRelatedMemories(memoryId);
|
|
45
|
+
for (const link of related) {
|
|
46
|
+
// Calculate spread amount: link strength * spread factor
|
|
47
|
+
const spreadAmount = link.strength * SPREAD_FACTOR;
|
|
48
|
+
// Get existing activation (if any)
|
|
49
|
+
const existing = activationCache.get(link.memory.id);
|
|
50
|
+
const existingLevel = existing
|
|
51
|
+
? getDecayedActivation(existing, now)
|
|
52
|
+
: 0;
|
|
53
|
+
// Add activation (cap at 1.0)
|
|
54
|
+
const newLevel = Math.min(1.0, existingLevel + spreadAmount);
|
|
55
|
+
activationCache.set(link.memory.id, {
|
|
56
|
+
memoryId: link.memory.id,
|
|
57
|
+
activationLevel: newLevel,
|
|
58
|
+
timestamp: now,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
// Don't fail memory access if spreading fails
|
|
64
|
+
console.error('[claude-cortex] Activation spreading failed:', e);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Calculate decayed activation level
|
|
69
|
+
*
|
|
70
|
+
* Uses exponential decay: level * 0.5^(minutes / half_life)
|
|
71
|
+
*/
|
|
72
|
+
function getDecayedActivation(entry, now) {
|
|
73
|
+
const ageMinutes = (now - entry.timestamp) / (1000 * 60);
|
|
74
|
+
const decayFactor = Math.pow(0.5, ageMinutes / DECAY_HALF_LIFE_MINUTES);
|
|
75
|
+
return entry.activationLevel * decayFactor;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the activation boost for a memory in search scoring
|
|
79
|
+
*
|
|
80
|
+
* Returns 0 if memory is not activated or activation has fully decayed.
|
|
81
|
+
* Returns up to MAX_ACTIVATION_BOOST for fully activated memories.
|
|
82
|
+
*
|
|
83
|
+
* @param memoryId - The ID of the memory to check
|
|
84
|
+
* @returns Activation boost (0 to MAX_ACTIVATION_BOOST)
|
|
85
|
+
*/
|
|
86
|
+
export function getActivationBoost(memoryId) {
|
|
87
|
+
const entry = activationCache.get(memoryId);
|
|
88
|
+
if (!entry)
|
|
89
|
+
return 0;
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
const decayedLevel = getDecayedActivation(entry, now);
|
|
92
|
+
// If activation is negligible, clean up the entry
|
|
93
|
+
if (decayedLevel < 0.01) {
|
|
94
|
+
activationCache.delete(memoryId);
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
// Scale to max boost (e.g., 1.0 activation -> 0.2 boost)
|
|
98
|
+
return decayedLevel * MAX_ACTIVATION_BOOST;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get current activation level for a memory (for debugging/dashboard)
|
|
102
|
+
*
|
|
103
|
+
* @param memoryId - The ID of the memory to check
|
|
104
|
+
* @returns Current activation level (0-1) or null if not activated
|
|
105
|
+
*/
|
|
106
|
+
export function getActivationLevel(memoryId) {
|
|
107
|
+
const entry = activationCache.get(memoryId);
|
|
108
|
+
if (!entry)
|
|
109
|
+
return null;
|
|
110
|
+
const decayedLevel = getDecayedActivation(entry, Date.now());
|
|
111
|
+
if (decayedLevel < 0.01)
|
|
112
|
+
return null;
|
|
113
|
+
return decayedLevel;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get all currently activated memories with their levels
|
|
117
|
+
* Useful for dashboard visualization
|
|
118
|
+
*
|
|
119
|
+
* @returns Array of {memoryId, activationLevel} for all activated memories
|
|
120
|
+
*/
|
|
121
|
+
export function getActiveMemories() {
|
|
122
|
+
const now = Date.now();
|
|
123
|
+
const active = [];
|
|
124
|
+
for (const entry of activationCache.values()) {
|
|
125
|
+
const level = getDecayedActivation(entry, now);
|
|
126
|
+
if (level >= 0.01) {
|
|
127
|
+
active.push({ memoryId: entry.memoryId, activationLevel: level });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return active.sort((a, b) => b.activationLevel - a.activationLevel);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Clear the activation cache
|
|
134
|
+
* Useful for testing or manual reset
|
|
135
|
+
*/
|
|
136
|
+
export function clearActivationCache() {
|
|
137
|
+
activationCache.clear();
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Prune stale entries from the activation cache
|
|
141
|
+
* Call periodically to prevent memory bloat
|
|
142
|
+
*/
|
|
143
|
+
export function pruneActivationCache() {
|
|
144
|
+
const now = Date.now();
|
|
145
|
+
let pruned = 0;
|
|
146
|
+
for (const [memoryId, entry] of activationCache) {
|
|
147
|
+
if (getDecayedActivation(entry, now) < 0.01) {
|
|
148
|
+
activationCache.delete(memoryId);
|
|
149
|
+
pruned++;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return pruned;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get activation cache statistics
|
|
156
|
+
*/
|
|
157
|
+
export function getActivationStats() {
|
|
158
|
+
const active = getActiveMemories();
|
|
159
|
+
const avgActivation = active.length > 0
|
|
160
|
+
? active.reduce((sum, a) => sum + a.activationLevel, 0) / active.length
|
|
161
|
+
: 0;
|
|
162
|
+
return {
|
|
163
|
+
totalEntries: activationCache.size,
|
|
164
|
+
activeEntries: active.length,
|
|
165
|
+
averageActivation: avgActivation,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=activation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activation.js","sourceRoot":"","sources":["../../src/memory/activation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Consolidation System
|
|
3
|
+
*
|
|
4
|
+
* Like sleep consolidation in human brains, this system:
|
|
5
|
+
* - Moves worthy short-term memories to long-term storage
|
|
6
|
+
* - Strengthens frequently accessed memories
|
|
7
|
+
* - Cleans up decayed/irrelevant memories
|
|
8
|
+
* - Merges similar memories to reduce redundancy
|
|
9
|
+
*/
|
|
10
|
+
import { Memory, MemoryConfig, ConsolidationResult, ContextSummary } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Run full consolidation process
|
|
13
|
+
* This is like the brain's sleep consolidation - should be run periodically
|
|
14
|
+
*/
|
|
15
|
+
export declare function consolidate(config?: MemoryConfig): ConsolidationResult;
|
|
16
|
+
/**
|
|
17
|
+
* Enforce maximum memory limits
|
|
18
|
+
* Removes lowest-priority memories when limits are exceeded
|
|
19
|
+
*/
|
|
20
|
+
export declare function enforceMemoryLimits(config?: MemoryConfig): number;
|
|
21
|
+
/**
|
|
22
|
+
* Find and merge similar memories
|
|
23
|
+
* Reduces redundancy while preserving important information
|
|
24
|
+
*/
|
|
25
|
+
export declare function mergeSimilarMemories(project?: string, similarityThreshold?: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Generate a context summary for session start
|
|
28
|
+
* Provides a high-level view of relevant memories
|
|
29
|
+
*/
|
|
30
|
+
export declare function generateContextSummary(project?: string, config?: MemoryConfig): Promise<ContextSummary>;
|
|
31
|
+
/**
|
|
32
|
+
* Format context summary as a readable string
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatContextSummary(summary: ContextSummary): string;
|
|
35
|
+
/**
|
|
36
|
+
* Start a new session
|
|
37
|
+
* Creates a session record and returns relevant context
|
|
38
|
+
*/
|
|
39
|
+
export declare function startSession(project?: string): Promise<{
|
|
40
|
+
sessionId: number;
|
|
41
|
+
context: ContextSummary;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* End a session
|
|
45
|
+
* Updates session record with summary
|
|
46
|
+
*/
|
|
47
|
+
export declare function endSession(sessionId: number, summary?: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Get suggested context for the current query
|
|
50
|
+
* Returns memories that might be relevant to what the user is working on
|
|
51
|
+
*/
|
|
52
|
+
export declare function getSuggestedContext(currentContext: string, project?: string, limit?: number): Promise<Memory[]>;
|
|
53
|
+
/**
|
|
54
|
+
* Export memories as JSON (for backup/transfer)
|
|
55
|
+
*/
|
|
56
|
+
export declare function exportMemories(project?: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Import memories from JSON
|
|
59
|
+
*/
|
|
60
|
+
export declare function importMemories(json: string): number;
|
|
61
|
+
/**
|
|
62
|
+
* Vacuum database to reclaim space after deletions
|
|
63
|
+
* Run periodically or after major cleanup operations
|
|
64
|
+
*/
|
|
65
|
+
export declare function vacuumDatabase(): {
|
|
66
|
+
success: boolean;
|
|
67
|
+
message: string;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Preview what consolidation would do without actually doing it
|
|
71
|
+
* Useful for dry-run mode
|
|
72
|
+
*/
|
|
73
|
+
export declare function previewConsolidation(config?: MemoryConfig): {
|
|
74
|
+
toPromote: Memory[];
|
|
75
|
+
toDelete: Memory[];
|
|
76
|
+
totalShortTerm: number;
|
|
77
|
+
totalLongTerm: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Check if consolidation should be triggered based on memory state
|
|
81
|
+
* Returns true if consolidation is recommended
|
|
82
|
+
*/
|
|
83
|
+
export declare function shouldTriggerConsolidation(config?: MemoryConfig): {
|
|
84
|
+
shouldRun: boolean;
|
|
85
|
+
reason: string;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Full cleanup: consolidate + vacuum
|
|
89
|
+
* Best run periodically to keep database healthy
|
|
90
|
+
*/
|
|
91
|
+
export declare function fullCleanup(config?: MemoryConfig): {
|
|
92
|
+
consolidation: ConsolidationResult;
|
|
93
|
+
vacuumed: boolean;
|
|
94
|
+
merged: number;
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=consolidate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidate.d.ts","sourceRoot":"","sources":["../../src/memory/consolidate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,MAAM,EACN,YAAY,EAEZ,mBAAmB,EACnB,cAAc,EACf,MAAM,YAAY,CAAC;AAuBpB;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,GAAE,YAA6B,GACpC,mBAAmB,CA0DrB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,GAAE,YAA6B,GAAG,MAAM,CA+CjF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,CAAC,EAAE,MAAM,EAChB,mBAAmB,GAAE,MAAY,GAChC,MAAM,CA6CR;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,CAAC,EAAE,MAAM,EAChB,MAAM,GAAE,YAA6B,GACpC,OAAO,CAAC,cAAc,CAAC,CAqCzB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAuCpE;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC;CACzB,CAAC,CAcD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAwBN;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,GAAE,MAAU,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC,CAWnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAavD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgCnD;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAQtE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,GAAE,YAA6B,GACpC;IACD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB,CA8BA;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,GAAE,YAA6B,GACpC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA2BxC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,GAAE,YAA6B,GACpC;IAAE,aAAa,EAAE,mBAAmB,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAe3E"}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Consolidation System
|
|
3
|
+
*
|
|
4
|
+
* Like sleep consolidation in human brains, this system:
|
|
5
|
+
* - Moves worthy short-term memories to long-term storage
|
|
6
|
+
* - Strengthens frequently accessed memories
|
|
7
|
+
* - Cleans up decayed/irrelevant memories
|
|
8
|
+
* - Merges similar memories to reduce redundancy
|
|
9
|
+
*/
|
|
10
|
+
import { getDatabase, withTransaction } from '../database/init.js';
|
|
11
|
+
import { DEFAULT_CONFIG, } from './types.js';
|
|
12
|
+
import { getMemoriesByType, getRecentMemories, promoteMemory, deleteMemory, searchMemories, getMemoryStats, updateDecayScores, } from './store.js';
|
|
13
|
+
import { processDecay, } from './decay.js';
|
|
14
|
+
import { detectContradictions, linkContradictions, } from './contradiction.js';
|
|
15
|
+
/**
|
|
16
|
+
* Run full consolidation process
|
|
17
|
+
* This is like the brain's sleep consolidation - should be run periodically
|
|
18
|
+
*/
|
|
19
|
+
export function consolidate(config = DEFAULT_CONFIG) {
|
|
20
|
+
// Wrap entire consolidation in a transaction for atomicity
|
|
21
|
+
return withTransaction(() => {
|
|
22
|
+
const db = getDatabase();
|
|
23
|
+
let consolidated = 0;
|
|
24
|
+
let decayed = 0;
|
|
25
|
+
let deleted = 0;
|
|
26
|
+
// Get all short-term memories
|
|
27
|
+
const shortTermMemories = getMemoriesByType('short_term', config.maxShortTermMemories * 2);
|
|
28
|
+
// Process decay for all memories
|
|
29
|
+
const { toDelete, toPromote, updated } = processDecay(shortTermMemories, config);
|
|
30
|
+
// Promote worthy memories
|
|
31
|
+
for (const id of toPromote) {
|
|
32
|
+
promoteMemory(id);
|
|
33
|
+
consolidated++;
|
|
34
|
+
}
|
|
35
|
+
// Delete decayed memories (excluding those just promoted)
|
|
36
|
+
for (const id of toDelete) {
|
|
37
|
+
if (!toPromote.includes(id)) {
|
|
38
|
+
deleteMemory(id);
|
|
39
|
+
deleted++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Update decayed scores in database
|
|
43
|
+
const updateStmt = db.prepare('UPDATE memories SET salience = ? WHERE id = ?');
|
|
44
|
+
for (const [id, score] of updated) {
|
|
45
|
+
if (!toDelete.includes(id)) {
|
|
46
|
+
updateStmt.run(score, id);
|
|
47
|
+
decayed++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Enforce memory limits
|
|
51
|
+
deleted += enforceMemoryLimits(config);
|
|
52
|
+
// Persist updated decay scores for efficient sorting
|
|
53
|
+
updateDecayScores();
|
|
54
|
+
// ORGANIC FEATURE: Contradiction Detection (Phase 3)
|
|
55
|
+
// Detect and link contradicting memories during consolidation
|
|
56
|
+
let contradictionsFound = 0;
|
|
57
|
+
let contradictionsLinked = 0;
|
|
58
|
+
try {
|
|
59
|
+
const contradictions = detectContradictions({ minScore: 0.5, limit: 50 });
|
|
60
|
+
contradictionsFound = contradictions.length;
|
|
61
|
+
contradictionsLinked = linkContradictions(contradictions);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
console.error('[claude-cortex] Contradiction detection failed:', e);
|
|
65
|
+
}
|
|
66
|
+
return { consolidated, decayed, deleted, contradictionsFound, contradictionsLinked };
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Enforce maximum memory limits
|
|
71
|
+
* Removes lowest-priority memories when limits are exceeded
|
|
72
|
+
*/
|
|
73
|
+
export function enforceMemoryLimits(config = DEFAULT_CONFIG) {
|
|
74
|
+
// Note: If called within consolidate(), this is already in a transaction
|
|
75
|
+
// If called standalone, we wrap it for safety
|
|
76
|
+
const db = getDatabase();
|
|
77
|
+
let deleted = 0;
|
|
78
|
+
// Check short-term memory limit
|
|
79
|
+
const shortTermCount = db.prepare("SELECT COUNT(*) as count FROM memories WHERE type = 'short_term'").get().count;
|
|
80
|
+
if (shortTermCount > config.maxShortTermMemories) {
|
|
81
|
+
const toRemove = shortTermCount - config.maxShortTermMemories;
|
|
82
|
+
const lowPriority = db.prepare(`
|
|
83
|
+
SELECT id FROM memories
|
|
84
|
+
WHERE type = 'short_term'
|
|
85
|
+
ORDER BY salience ASC, last_accessed ASC
|
|
86
|
+
LIMIT ?
|
|
87
|
+
`).all(toRemove);
|
|
88
|
+
for (const { id } of lowPriority) {
|
|
89
|
+
deleteMemory(id);
|
|
90
|
+
deleted++;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Check long-term memory limit (more lenient)
|
|
94
|
+
const longTermCount = db.prepare("SELECT COUNT(*) as count FROM memories WHERE type = 'long_term'").get().count;
|
|
95
|
+
if (longTermCount > config.maxLongTermMemories) {
|
|
96
|
+
const toRemove = longTermCount - config.maxLongTermMemories;
|
|
97
|
+
const lowPriority = db.prepare(`
|
|
98
|
+
SELECT id FROM memories
|
|
99
|
+
WHERE type = 'long_term'
|
|
100
|
+
ORDER BY salience ASC, access_count ASC, last_accessed ASC
|
|
101
|
+
LIMIT ?
|
|
102
|
+
`).all(toRemove);
|
|
103
|
+
for (const { id } of lowPriority) {
|
|
104
|
+
deleteMemory(id);
|
|
105
|
+
deleted++;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return deleted;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Find and merge similar memories
|
|
112
|
+
* Reduces redundancy while preserving important information
|
|
113
|
+
*/
|
|
114
|
+
export function mergeSimilarMemories(project, similarityThreshold = 0.8) {
|
|
115
|
+
// Wrap in transaction for atomic merge operations
|
|
116
|
+
return withTransaction(() => {
|
|
117
|
+
const db = getDatabase();
|
|
118
|
+
let merged = 0;
|
|
119
|
+
// Get all memories (optionally filtered by project)
|
|
120
|
+
let sql = 'SELECT * FROM memories';
|
|
121
|
+
const params = [];
|
|
122
|
+
if (project) {
|
|
123
|
+
sql += ' WHERE project = ?';
|
|
124
|
+
params.push(project);
|
|
125
|
+
}
|
|
126
|
+
sql += ' ORDER BY created_at ASC';
|
|
127
|
+
const memories = db.prepare(sql).all(...params);
|
|
128
|
+
// Simple similarity check based on title and first 100 chars of content
|
|
129
|
+
const seen = new Map(); // key -> id of primary memory
|
|
130
|
+
for (const row of memories) {
|
|
131
|
+
const key = `${row.title.toLowerCase().trim()}|${row.content.slice(0, 100).toLowerCase()}`;
|
|
132
|
+
if (seen.has(key)) {
|
|
133
|
+
// This is a duplicate, merge into the primary
|
|
134
|
+
const primaryId = seen.get(key);
|
|
135
|
+
// Boost the primary memory's salience
|
|
136
|
+
db.prepare(`
|
|
137
|
+
UPDATE memories
|
|
138
|
+
SET salience = MIN(1.0, salience + 0.1),
|
|
139
|
+
access_count = access_count + 1
|
|
140
|
+
WHERE id = ?
|
|
141
|
+
`).run(primaryId);
|
|
142
|
+
// Delete the duplicate
|
|
143
|
+
deleteMemory(row.id);
|
|
144
|
+
merged++;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
seen.set(key, row.id);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return merged;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Generate a context summary for session start
|
|
155
|
+
* Provides a high-level view of relevant memories
|
|
156
|
+
*/
|
|
157
|
+
export async function generateContextSummary(project, config = DEFAULT_CONFIG) {
|
|
158
|
+
// Get recent memories
|
|
159
|
+
const recentMemories = getRecentMemories(10, project);
|
|
160
|
+
// Get key architecture decisions
|
|
161
|
+
const keyDecisions = (await searchMemories({
|
|
162
|
+
query: '',
|
|
163
|
+
project,
|
|
164
|
+
category: 'architecture',
|
|
165
|
+
minSalience: 0.6,
|
|
166
|
+
limit: 5,
|
|
167
|
+
}, config)).map(r => r.memory);
|
|
168
|
+
// Get active patterns
|
|
169
|
+
const activePatterns = (await searchMemories({
|
|
170
|
+
query: '',
|
|
171
|
+
project,
|
|
172
|
+
category: 'pattern',
|
|
173
|
+
minSalience: 0.5,
|
|
174
|
+
limit: 5,
|
|
175
|
+
}, config)).map(r => r.memory);
|
|
176
|
+
// Get pending items
|
|
177
|
+
const pendingItems = (await searchMemories({
|
|
178
|
+
query: '',
|
|
179
|
+
project,
|
|
180
|
+
category: 'todo',
|
|
181
|
+
limit: 10,
|
|
182
|
+
}, config)).map(r => r.memory);
|
|
183
|
+
return {
|
|
184
|
+
project,
|
|
185
|
+
recentMemories,
|
|
186
|
+
keyDecisions,
|
|
187
|
+
activePatterns,
|
|
188
|
+
pendingItems,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Format context summary as a readable string
|
|
193
|
+
*/
|
|
194
|
+
export function formatContextSummary(summary) {
|
|
195
|
+
const lines = [];
|
|
196
|
+
if (summary.project) {
|
|
197
|
+
lines.push(`## Project: ${summary.project}\n`);
|
|
198
|
+
}
|
|
199
|
+
if (summary.keyDecisions.length > 0) {
|
|
200
|
+
lines.push('### Key Decisions');
|
|
201
|
+
for (const memory of summary.keyDecisions) {
|
|
202
|
+
lines.push(`- **${memory.title}**: ${memory.content.slice(0, 100)}${memory.content.length > 100 ? '...' : ''}`);
|
|
203
|
+
}
|
|
204
|
+
lines.push('');
|
|
205
|
+
}
|
|
206
|
+
if (summary.activePatterns.length > 0) {
|
|
207
|
+
lines.push('### Active Patterns');
|
|
208
|
+
for (const memory of summary.activePatterns) {
|
|
209
|
+
lines.push(`- **${memory.title}**: ${memory.content.slice(0, 100)}${memory.content.length > 100 ? '...' : ''}`);
|
|
210
|
+
}
|
|
211
|
+
lines.push('');
|
|
212
|
+
}
|
|
213
|
+
if (summary.pendingItems.length > 0) {
|
|
214
|
+
lines.push('### Pending Items');
|
|
215
|
+
for (const memory of summary.pendingItems) {
|
|
216
|
+
lines.push(`- [ ] ${memory.title}`);
|
|
217
|
+
}
|
|
218
|
+
lines.push('');
|
|
219
|
+
}
|
|
220
|
+
if (summary.recentMemories.length > 0) {
|
|
221
|
+
lines.push('### Recent Context');
|
|
222
|
+
for (const memory of summary.recentMemories.slice(0, 5)) {
|
|
223
|
+
lines.push(`- ${memory.title} (${memory.category})`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return lines.join('\n');
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Start a new session
|
|
230
|
+
* Creates a session record and returns relevant context
|
|
231
|
+
*/
|
|
232
|
+
export async function startSession(project) {
|
|
233
|
+
const db = getDatabase();
|
|
234
|
+
// Create session record
|
|
235
|
+
const result = db.prepare(`
|
|
236
|
+
INSERT INTO sessions (project) VALUES (?)
|
|
237
|
+
`).run(project || null);
|
|
238
|
+
const sessionId = result.lastInsertRowid;
|
|
239
|
+
// Generate context summary
|
|
240
|
+
const context = await generateContextSummary(project);
|
|
241
|
+
return { sessionId, context };
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* End a session
|
|
245
|
+
* Updates session record with summary
|
|
246
|
+
*/
|
|
247
|
+
export function endSession(sessionId, summary) {
|
|
248
|
+
const db = getDatabase();
|
|
249
|
+
// Get counts from this session
|
|
250
|
+
const stats = db.prepare(`
|
|
251
|
+
SELECT
|
|
252
|
+
(SELECT COUNT(*) FROM memories WHERE created_at >= s.started_at) as created,
|
|
253
|
+
(SELECT COUNT(*) FROM memories WHERE last_accessed >= s.started_at) as accessed
|
|
254
|
+
FROM sessions s WHERE s.id = ?
|
|
255
|
+
`).get(sessionId);
|
|
256
|
+
db.prepare(`
|
|
257
|
+
UPDATE sessions
|
|
258
|
+
SET ended_at = CURRENT_TIMESTAMP,
|
|
259
|
+
summary = ?,
|
|
260
|
+
memories_created = ?,
|
|
261
|
+
memories_accessed = ?
|
|
262
|
+
WHERE id = ?
|
|
263
|
+
`).run(summary || null, stats?.created || 0, stats?.accessed || 0, sessionId);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get suggested context for the current query
|
|
267
|
+
* Returns memories that might be relevant to what the user is working on
|
|
268
|
+
*/
|
|
269
|
+
export async function getSuggestedContext(currentContext, project, limit = 5) {
|
|
270
|
+
// Search for relevant memories based on current context
|
|
271
|
+
const results = await searchMemories({
|
|
272
|
+
query: currentContext,
|
|
273
|
+
project,
|
|
274
|
+
minSalience: 0.4,
|
|
275
|
+
limit,
|
|
276
|
+
includeDecayed: false,
|
|
277
|
+
});
|
|
278
|
+
return results.map(r => r.memory);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Export memories as JSON (for backup/transfer)
|
|
282
|
+
*/
|
|
283
|
+
export function exportMemories(project) {
|
|
284
|
+
const db = getDatabase();
|
|
285
|
+
let sql = 'SELECT * FROM memories';
|
|
286
|
+
const params = [];
|
|
287
|
+
if (project) {
|
|
288
|
+
sql += ' WHERE project = ?';
|
|
289
|
+
params.push(project);
|
|
290
|
+
}
|
|
291
|
+
sql += ' ORDER BY created_at ASC';
|
|
292
|
+
const rows = db.prepare(sql).all(...params);
|
|
293
|
+
return JSON.stringify(rows, null, 2);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Import memories from JSON
|
|
297
|
+
*/
|
|
298
|
+
export function importMemories(json) {
|
|
299
|
+
// Wrap in transaction for atomic import
|
|
300
|
+
return withTransaction(() => {
|
|
301
|
+
const db = getDatabase();
|
|
302
|
+
const memories = JSON.parse(json);
|
|
303
|
+
const stmt = db.prepare(`
|
|
304
|
+
INSERT INTO memories (type, category, title, content, project, tags, salience, metadata)
|
|
305
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
306
|
+
`);
|
|
307
|
+
let imported = 0;
|
|
308
|
+
for (const memory of memories) {
|
|
309
|
+
try {
|
|
310
|
+
stmt.run(memory.type, memory.category, memory.title, memory.content, memory.project || null, memory.tags || '[]', memory.salience || 0.5, memory.metadata || '{}');
|
|
311
|
+
imported++;
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
// Skip duplicates or invalid entries
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return imported;
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Vacuum database to reclaim space after deletions
|
|
322
|
+
* Run periodically or after major cleanup operations
|
|
323
|
+
*/
|
|
324
|
+
export function vacuumDatabase() {
|
|
325
|
+
try {
|
|
326
|
+
const db = getDatabase();
|
|
327
|
+
db.exec('VACUUM');
|
|
328
|
+
return { success: true, message: 'Database vacuumed successfully' };
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
return { success: false, message: `Vacuum failed: ${error}` };
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Preview what consolidation would do without actually doing it
|
|
336
|
+
* Useful for dry-run mode
|
|
337
|
+
*/
|
|
338
|
+
export function previewConsolidation(config = DEFAULT_CONFIG) {
|
|
339
|
+
const db = getDatabase();
|
|
340
|
+
// Get all short-term memories
|
|
341
|
+
const shortTermMemories = getMemoriesByType('short_term', config.maxShortTermMemories * 2);
|
|
342
|
+
// Get episodic memories too
|
|
343
|
+
const episodicMemories = getMemoriesByType('episodic', 100);
|
|
344
|
+
// Process decay to see what would happen
|
|
345
|
+
const { toDelete: deleteIds, toPromote: promoteIds } = processDecay([...shortTermMemories, ...episodicMemories], config);
|
|
346
|
+
// Map IDs back to memories
|
|
347
|
+
const allMemories = [...shortTermMemories, ...episodicMemories];
|
|
348
|
+
const toPromote = allMemories.filter(m => promoteIds.includes(m.id));
|
|
349
|
+
const toDelete = allMemories.filter(m => deleteIds.includes(m.id) && !promoteIds.includes(m.id));
|
|
350
|
+
// Get counts
|
|
351
|
+
const totalShortTerm = db.prepare("SELECT COUNT(*) as count FROM memories WHERE type = 'short_term'").get().count;
|
|
352
|
+
const totalLongTerm = db.prepare("SELECT COUNT(*) as count FROM memories WHERE type = 'long_term'").get().count;
|
|
353
|
+
return { toPromote, toDelete, totalShortTerm, totalLongTerm };
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Check if consolidation should be triggered based on memory state
|
|
357
|
+
* Returns true if consolidation is recommended
|
|
358
|
+
*/
|
|
359
|
+
export function shouldTriggerConsolidation(config = DEFAULT_CONFIG) {
|
|
360
|
+
const stats = getMemoryStats();
|
|
361
|
+
const stmFullness = stats.shortTerm / config.maxShortTermMemories;
|
|
362
|
+
// Trigger early when approaching capacity
|
|
363
|
+
if (stmFullness > 0.8) {
|
|
364
|
+
return {
|
|
365
|
+
shouldRun: true,
|
|
366
|
+
reason: `Short-term memory at ${Math.round(stmFullness * 100)}% capacity`,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
// Check if many memories are below threshold
|
|
370
|
+
const db = getDatabase();
|
|
371
|
+
const lowScoreCount = db.prepare(`
|
|
372
|
+
SELECT COUNT(*) as count FROM memories
|
|
373
|
+
WHERE type = 'short_term' AND decayed_score < ?
|
|
374
|
+
`).get(config.salienceThreshold).count;
|
|
375
|
+
if (lowScoreCount > 10) {
|
|
376
|
+
return {
|
|
377
|
+
shouldRun: true,
|
|
378
|
+
reason: `${lowScoreCount} memories below salience threshold`,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
return { shouldRun: false, reason: 'No consolidation needed' };
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Full cleanup: consolidate + vacuum
|
|
385
|
+
* Best run periodically to keep database healthy
|
|
386
|
+
*/
|
|
387
|
+
export function fullCleanup(config = DEFAULT_CONFIG) {
|
|
388
|
+
// Run consolidation
|
|
389
|
+
const consolidation = consolidate(config);
|
|
390
|
+
// Merge similar memories
|
|
391
|
+
const merged = mergeSimilarMemories();
|
|
392
|
+
// Vacuum if we deleted anything
|
|
393
|
+
let vacuumed = false;
|
|
394
|
+
if (consolidation.deleted > 0 || merged > 0) {
|
|
395
|
+
const vacResult = vacuumDatabase();
|
|
396
|
+
vacuumed = vacResult.success;
|
|
397
|
+
}
|
|
398
|
+
return { consolidation, vacuumed, merged };
|
|
399
|
+
}
|
|
400
|
+
//# sourceMappingURL=consolidate.js.map
|