cozo-memory 1.1.8 → 1.2.1
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/dist/adaptive-retrieval.js +10 -0
- package/dist/dynamic-fusion.js +15 -2
- package/dist/emotional-salience.js +295 -0
- package/dist/hybrid-search.js +51 -18
- package/dist/index.js +705 -9
- package/dist/logger.js +56 -0
- package/dist/memory-activation.js +64 -30
- package/dist/memory-service.js +68 -0
- package/dist/migrate-logging.js +113 -0
- package/dist/performance-monitor.js +108 -0
- package/dist/pre-storage-reasoning.js +351 -0
- package/dist/temporal-conflict-resolution.js +10 -6
- package/dist/test-activation-mcp.js +118 -0
- package/dist/test-advanced-search-mcp.js +204 -0
- package/dist/test-conflicts-mcp.js +173 -0
- package/dist/test-emotional-salience.js +177 -0
- package/dist/test-hierarchical-mcp.js +135 -0
- package/dist/test-large-dataset.js +502 -0
- package/dist/test-logical-edges-mcp.js +215 -0
- package/dist/test-metadata-check.js +69 -0
- package/dist/test-metadata-update.js +92 -0
- package/dist/test-pre-storage-reasoning.js +149 -0
- package/dist/test-salience-mcp.js +94 -0
- package/dist/test-spreading-mcp.js +155 -0
- package/dist/test-suggest-connections-mcp.js +172 -0
- package/dist/test-zettelkasten-evolution.js +255 -0
- package/dist/test-zettelkasten-fixed.js +74 -0
- package/dist/test-zettelkasten-live.js +117 -0
- package/dist/test-zettelkasten-mcp.js +96 -0
- package/dist/zettelkasten-evolution.js +342 -0
- package/package.json +1 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const index_1 = require("./index");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const TEST_DB_PATH = 'test_advanced_search_mcp';
|
|
39
|
+
async function runTest() {
|
|
40
|
+
console.error('=== Testing qafd_search and hierarchical_memory_query MCP Tools ===\n');
|
|
41
|
+
// Clean up old test database
|
|
42
|
+
const dbFile = `${TEST_DB_PATH}.db`;
|
|
43
|
+
if (fs.existsSync(dbFile)) {
|
|
44
|
+
try {
|
|
45
|
+
fs.unlinkSync(dbFile);
|
|
46
|
+
console.error('[Cleanup] Removed old test database');
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
console.error('[Cleanup] Warning: Could not remove old database:', e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const server = new index_1.MemoryServer(TEST_DB_PATH);
|
|
53
|
+
await server.initPromise;
|
|
54
|
+
try {
|
|
55
|
+
console.error('1. Creating test entities and relationships...');
|
|
56
|
+
const entity1 = await server.createEntity({
|
|
57
|
+
name: 'Machine Learning',
|
|
58
|
+
type: 'Topic',
|
|
59
|
+
metadata: {}
|
|
60
|
+
});
|
|
61
|
+
const entity2 = await server.createEntity({
|
|
62
|
+
name: 'Neural Networks',
|
|
63
|
+
type: 'Topic',
|
|
64
|
+
metadata: {}
|
|
65
|
+
});
|
|
66
|
+
const entity3 = await server.createEntity({
|
|
67
|
+
name: 'Deep Learning',
|
|
68
|
+
type: 'Topic',
|
|
69
|
+
metadata: {}
|
|
70
|
+
});
|
|
71
|
+
console.error(`✓ Created 3 entities\n`);
|
|
72
|
+
// Create relationships
|
|
73
|
+
await server.createRelation({
|
|
74
|
+
from_id: entity1.id,
|
|
75
|
+
to_id: entity2.id,
|
|
76
|
+
relation_type: 'includes',
|
|
77
|
+
strength: 0.9
|
|
78
|
+
});
|
|
79
|
+
await server.createRelation({
|
|
80
|
+
from_id: entity2.id,
|
|
81
|
+
to_id: entity3.id,
|
|
82
|
+
relation_type: 'specializes_to',
|
|
83
|
+
strength: 0.85
|
|
84
|
+
});
|
|
85
|
+
console.error('✓ Created relationships\n');
|
|
86
|
+
// Add observations at different levels
|
|
87
|
+
await server.addObservation({
|
|
88
|
+
entity_id: entity1.id,
|
|
89
|
+
text: 'Machine learning is a subset of artificial intelligence',
|
|
90
|
+
metadata: { memory_level: 0 },
|
|
91
|
+
deduplicate: false
|
|
92
|
+
});
|
|
93
|
+
await server.addObservation({
|
|
94
|
+
entity_id: entity2.id,
|
|
95
|
+
text: 'Neural networks are inspired by biological neurons',
|
|
96
|
+
metadata: { memory_level: 0 },
|
|
97
|
+
deduplicate: false
|
|
98
|
+
});
|
|
99
|
+
await server.addObservation({
|
|
100
|
+
entity_id: entity3.id,
|
|
101
|
+
text: 'Deep learning uses multiple layers of neural networks',
|
|
102
|
+
metadata: { memory_level: 1 },
|
|
103
|
+
deduplicate: false
|
|
104
|
+
});
|
|
105
|
+
console.error('✓ Added observations at different memory levels\n');
|
|
106
|
+
console.error('2. Testing qafd_search (Query-Aware Flow Diffusion)...');
|
|
107
|
+
const qafdResult = await server.getQueryAwareTraversal().hybridSearch('artificial intelligence and neural networks', {
|
|
108
|
+
seedTopK: 2,
|
|
109
|
+
maxHops: 2,
|
|
110
|
+
dampingFactor: 0.85,
|
|
111
|
+
minScore: 0.05,
|
|
112
|
+
topK: 10
|
|
113
|
+
});
|
|
114
|
+
console.error(`✓ QAFD search completed: ${qafdResult.length} results found`);
|
|
115
|
+
if (qafdResult.length > 0) {
|
|
116
|
+
console.error('\n3. Analyzing QAFD results...');
|
|
117
|
+
qafdResult.slice(0, 3).forEach((result, i) => {
|
|
118
|
+
console.error(`\n Result ${i + 1}:`);
|
|
119
|
+
console.error(` Entity: ${result.name || result.entity_name || 'Unknown'}`);
|
|
120
|
+
console.error(` Score: ${result.score?.toFixed(4) || result.finalScore?.toFixed(4) || 'N/A'}`);
|
|
121
|
+
console.error(` Hops: ${result.hops || result.hop || 0}`);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
console.error('\n4. Testing hierarchical_memory_query...');
|
|
125
|
+
// Query all levels
|
|
126
|
+
const queryEmbedding = await server.embeddingService.embed('neural networks and deep learning');
|
|
127
|
+
const allLevelsResult = await server.db.run(`
|
|
128
|
+
?[id, entity_id, text, memory_level, dist] :=
|
|
129
|
+
~observation:semantic{
|
|
130
|
+
id |
|
|
131
|
+
query: vec($embedding),
|
|
132
|
+
k: 10,
|
|
133
|
+
ef: 100,
|
|
134
|
+
bind_distance: dist
|
|
135
|
+
},
|
|
136
|
+
*observation{id, entity_id, text, metadata, @ "NOW"},
|
|
137
|
+
memory_level = get(metadata, "memory_level", 0)
|
|
138
|
+
|
|
139
|
+
:order dist
|
|
140
|
+
`, { embedding: queryEmbedding });
|
|
141
|
+
const observations = allLevelsResult.rows.map((r) => ({
|
|
142
|
+
id: r[0],
|
|
143
|
+
entity_id: r[1],
|
|
144
|
+
text: r[2],
|
|
145
|
+
memory_level: r[3],
|
|
146
|
+
distance: r[4]
|
|
147
|
+
}));
|
|
148
|
+
console.error(`✓ Hierarchical memory query completed: ${observations.length} results found`);
|
|
149
|
+
if (observations.length > 0) {
|
|
150
|
+
console.error('\n5. Analyzing hierarchical memory results...');
|
|
151
|
+
const byLevel = {};
|
|
152
|
+
observations.forEach((obs) => {
|
|
153
|
+
byLevel[obs.memory_level] = (byLevel[obs.memory_level] || 0) + 1;
|
|
154
|
+
});
|
|
155
|
+
console.error(' Distribution by level:');
|
|
156
|
+
Object.entries(byLevel).forEach(([level, count]) => {
|
|
157
|
+
console.error(` L${level}: ${count} observations`);
|
|
158
|
+
});
|
|
159
|
+
console.error('\n Top 3 results:');
|
|
160
|
+
observations.slice(0, 3).forEach((obs, i) => {
|
|
161
|
+
console.error(`\n ${i + 1}. Level ${obs.memory_level}`);
|
|
162
|
+
console.error(` Text: ${obs.text.substring(0, 60)}...`);
|
|
163
|
+
console.error(` Distance: ${obs.distance.toFixed(4)}`);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
console.error('\n6. Testing hierarchical_memory_query with level filter...');
|
|
167
|
+
const l0OnlyResult = await server.db.run(`
|
|
168
|
+
?[id, entity_id, text, memory_level, dist] :=
|
|
169
|
+
~observation:semantic{
|
|
170
|
+
id |
|
|
171
|
+
query: vec($embedding),
|
|
172
|
+
k: 10,
|
|
173
|
+
ef: 100,
|
|
174
|
+
bind_distance: dist
|
|
175
|
+
},
|
|
176
|
+
*observation{id, entity_id, text, metadata, @ "NOW"},
|
|
177
|
+
memory_level = get(metadata, "memory_level", 0),
|
|
178
|
+
memory_level = 0
|
|
179
|
+
|
|
180
|
+
:order dist
|
|
181
|
+
`, { embedding: queryEmbedding });
|
|
182
|
+
console.error(`✓ L0-only query completed: ${l0OnlyResult.rows.length} results found`);
|
|
183
|
+
console.error('\n=== ✓ Advanced Search MCP Tools Test Passed ===\n');
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.error('\n=== ✗ Test Failed ===');
|
|
187
|
+
console.error('Error:', error);
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
// Cleanup
|
|
192
|
+
server.db.close();
|
|
193
|
+
if (fs.existsSync(dbFile)) {
|
|
194
|
+
try {
|
|
195
|
+
fs.unlinkSync(dbFile);
|
|
196
|
+
console.error('[Cleanup] Test database removed');
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
console.error('[Cleanup] Warning: Could not remove test database');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
runTest().catch(console.error);
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const index_1 = require("./index");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const TEST_DB_PATH = 'test_conflicts_mcp';
|
|
39
|
+
async function runTest() {
|
|
40
|
+
console.error('=== Testing detect_conflicts and resolve_conflicts MCP Tools ===\n');
|
|
41
|
+
// Clean up old test database
|
|
42
|
+
const dbFile = `${TEST_DB_PATH}.db`;
|
|
43
|
+
if (fs.existsSync(dbFile)) {
|
|
44
|
+
try {
|
|
45
|
+
fs.unlinkSync(dbFile);
|
|
46
|
+
console.error('[Cleanup] Removed old test database');
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
console.error('[Cleanup] Warning: Could not remove old database:', e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const server = new index_1.MemoryServer(TEST_DB_PATH);
|
|
53
|
+
await server.initPromise;
|
|
54
|
+
try {
|
|
55
|
+
console.error('1. Creating test entity...');
|
|
56
|
+
const entityResult = await server.createEntity({
|
|
57
|
+
name: 'Project Alpha',
|
|
58
|
+
type: 'Project',
|
|
59
|
+
metadata: {}
|
|
60
|
+
});
|
|
61
|
+
const entityId = entityResult.id;
|
|
62
|
+
console.error(`✓ Created entity: ${entityId}\n`);
|
|
63
|
+
console.error('2. Adding observations with potential conflicts...');
|
|
64
|
+
// Add first observation
|
|
65
|
+
const obs1 = await server.addObservation({
|
|
66
|
+
entity_id: entityId,
|
|
67
|
+
text: 'Project status is pending approval',
|
|
68
|
+
metadata: { timestamp: Date.now() }
|
|
69
|
+
});
|
|
70
|
+
console.error(`✓ Added observation 1: ${obs1.id?.substring(0, 8)}...`);
|
|
71
|
+
// Wait a bit to ensure different timestamps
|
|
72
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
73
|
+
// Add redundant observation (very similar)
|
|
74
|
+
const obs2 = await server.addObservation({
|
|
75
|
+
entity_id: entityId,
|
|
76
|
+
text: 'Project status is pending approval and waiting',
|
|
77
|
+
metadata: { timestamp: Date.now() }
|
|
78
|
+
});
|
|
79
|
+
console.error(`✓ Added observation 2 (redundant): ${obs2.id?.substring(0, 8)}...`);
|
|
80
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
81
|
+
// Add superseding observation
|
|
82
|
+
const obs3 = await server.addObservation({
|
|
83
|
+
entity_id: entityId,
|
|
84
|
+
text: 'Project status updated: now approved and in progress',
|
|
85
|
+
metadata: { timestamp: Date.now() }
|
|
86
|
+
});
|
|
87
|
+
console.error(`✓ Added observation 3 (superseding): ${obs3.id?.substring(0, 8)}...`);
|
|
88
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
89
|
+
// Add contradictory observation
|
|
90
|
+
const obs4 = await server.addObservation({
|
|
91
|
+
entity_id: entityId,
|
|
92
|
+
text: 'Project is not approved and has been rejected',
|
|
93
|
+
metadata: { timestamp: Date.now() }
|
|
94
|
+
});
|
|
95
|
+
console.error(`✓ Added observation 4 (contradictory): ${obs4.id?.substring(0, 8)}...\n`);
|
|
96
|
+
console.error('3. Testing detect_conflicts...');
|
|
97
|
+
const conflicts = await server.getConflictService().detectConflicts(entityId);
|
|
98
|
+
console.error(`✓ Conflict detection completed: ${conflicts.length} conflicts found`);
|
|
99
|
+
if (conflicts.length > 0) {
|
|
100
|
+
console.error('\n4. Analyzing detected conflicts...');
|
|
101
|
+
conflicts.forEach((conflict, i) => {
|
|
102
|
+
console.error(`\n Conflict ${i + 1}:`);
|
|
103
|
+
console.error(` Type: ${conflict.conflict_type}`);
|
|
104
|
+
console.error(` Confidence: ${conflict.confidence.toFixed(2)} (${conflict.confidence_level})`);
|
|
105
|
+
console.error(` Older: "${conflict.older_text.substring(0, 50)}..."`);
|
|
106
|
+
console.error(` Newer: "${conflict.newer_text.substring(0, 50)}..."`);
|
|
107
|
+
console.error(` Reason: ${conflict.reason}`);
|
|
108
|
+
});
|
|
109
|
+
// Verify conflict types
|
|
110
|
+
console.error('\n5. Verifying conflict types...');
|
|
111
|
+
const redundancyConflicts = conflicts.filter(c => c.conflict_type === 'temporal_redundancy');
|
|
112
|
+
const contradictionConflicts = conflicts.filter(c => c.conflict_type === 'semantic_contradiction');
|
|
113
|
+
const supersededConflicts = conflicts.filter(c => c.conflict_type === 'superseded_fact');
|
|
114
|
+
console.error(` - Temporal Redundancy: ${redundancyConflicts.length}`);
|
|
115
|
+
console.error(` - Semantic Contradiction: ${contradictionConflicts.length}`);
|
|
116
|
+
console.error(` - Superseded Fact: ${supersededConflicts.length}`);
|
|
117
|
+
// Check confidence levels
|
|
118
|
+
const highConfidence = conflicts.filter(c => c.confidence_level === 'high');
|
|
119
|
+
const mediumConfidence = conflicts.filter(c => c.confidence_level === 'medium');
|
|
120
|
+
const lowConfidence = conflicts.filter(c => c.confidence_level === 'low');
|
|
121
|
+
console.error('\n6. Confidence distribution:');
|
|
122
|
+
console.error(` - High: ${highConfidence.length}`);
|
|
123
|
+
console.error(` - Medium: ${mediumConfidence.length}`);
|
|
124
|
+
console.error(` - Low: ${lowConfidence.length}`);
|
|
125
|
+
console.error('\n7. Testing resolve_conflicts...');
|
|
126
|
+
const resolution = await server.getConflictService().resolveConflicts(entityId);
|
|
127
|
+
console.error(`✓ Conflict resolution completed:`);
|
|
128
|
+
console.error(` - Resolved conflicts: ${resolution.resolved_conflicts}`);
|
|
129
|
+
console.error(` - Invalidated observations: ${resolution.invalidated_observations.length}`);
|
|
130
|
+
console.error(` - Audit trail entries: ${resolution.audit_observations.length}`);
|
|
131
|
+
if (resolution.invalidated_observations.length > 0) {
|
|
132
|
+
console.error('\n8. Verifying invalidated observations...');
|
|
133
|
+
console.error(` Invalidated IDs: ${resolution.invalidated_observations.map(id => id.substring(0, 8)).join(', ')}...`);
|
|
134
|
+
}
|
|
135
|
+
if (resolution.audit_observations.length > 0) {
|
|
136
|
+
console.error('\n9. Verifying audit trail...');
|
|
137
|
+
console.error(` Audit IDs: ${resolution.audit_observations.map(id => id.substring(0, 8)).join(', ')}...`);
|
|
138
|
+
}
|
|
139
|
+
console.error('\n10. Re-checking for conflicts after resolution...');
|
|
140
|
+
const remainingConflicts = await server.getConflictService().detectConflicts(entityId);
|
|
141
|
+
console.error(`✓ Remaining conflicts: ${remainingConflicts.length} (expected: 0)`);
|
|
142
|
+
if (remainingConflicts.length === 0) {
|
|
143
|
+
console.error(' ✓ All conflicts successfully resolved!');
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
console.error(' ⚠ Some conflicts remain (this may be expected for certain conflict types)');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
console.error('⚠ No conflicts detected (observations may be too dissimilar)');
|
|
151
|
+
}
|
|
152
|
+
console.error('\n=== ✓ Conflict Detection and Resolution MCP Tools Test Passed ===\n');
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
console.error('\n=== ✗ Test Failed ===');
|
|
156
|
+
console.error('Error:', error);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
// Cleanup
|
|
161
|
+
server.db.close();
|
|
162
|
+
if (fs.existsSync(dbFile)) {
|
|
163
|
+
try {
|
|
164
|
+
fs.unlinkSync(dbFile);
|
|
165
|
+
console.error('[Cleanup] Test database removed');
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
console.error('[Cleanup] Warning: Could not remove test database');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
runTest().catch(console.error);
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const cozo_node_1 = require("cozo-node");
|
|
4
|
+
const emotional_salience_1 = require("./emotional-salience");
|
|
5
|
+
async function testEmotionalSalience() {
|
|
6
|
+
console.log('=== Emotional Salience Weighting Test ===\n');
|
|
7
|
+
const db = new cozo_node_1.CozoDb();
|
|
8
|
+
const salienceService = new emotional_salience_1.EmotionalSalienceService(db, {
|
|
9
|
+
enableSalience: true,
|
|
10
|
+
salienceBoostFactor: 2.0,
|
|
11
|
+
decaySlowdownFactor: 0.5,
|
|
12
|
+
minSalienceThreshold: 0.3
|
|
13
|
+
});
|
|
14
|
+
try {
|
|
15
|
+
// Initialize database schema
|
|
16
|
+
await db.run(`
|
|
17
|
+
:create entity {
|
|
18
|
+
id: String,
|
|
19
|
+
=>
|
|
20
|
+
name: String,
|
|
21
|
+
type: String,
|
|
22
|
+
}
|
|
23
|
+
`);
|
|
24
|
+
await db.run(`
|
|
25
|
+
:create observation {
|
|
26
|
+
id: String,
|
|
27
|
+
=>
|
|
28
|
+
entity_id: String,
|
|
29
|
+
text: String,
|
|
30
|
+
metadata: Json?,
|
|
31
|
+
}
|
|
32
|
+
`);
|
|
33
|
+
console.log('✓ Database initialized\n');
|
|
34
|
+
// Test 1: Create test observations with varying emotional salience
|
|
35
|
+
console.log('Test 1: Creating observations with different salience levels...');
|
|
36
|
+
const testObservations = [
|
|
37
|
+
{
|
|
38
|
+
text: 'CRITICAL: Never forget to backup the database before deployment. This is extremely important!',
|
|
39
|
+
expected: 'high'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
text: 'Important reminder: The deadline for the project is next Friday.',
|
|
43
|
+
expected: 'medium'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
text: 'Interesting discovery: The new algorithm is 20% faster than the old one.',
|
|
47
|
+
expected: 'medium'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
text: 'Note: The meeting is scheduled for 3 PM tomorrow.',
|
|
51
|
+
expected: 'low'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
text: 'The weather is nice today.',
|
|
55
|
+
expected: 'neutral'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
text: 'URGENT: Security vulnerability detected in authentication module. Immediate action required!',
|
|
59
|
+
expected: 'high'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
text: 'Surprising breakthrough in machine learning research announced today.',
|
|
63
|
+
expected: 'medium'
|
|
64
|
+
}
|
|
65
|
+
];
|
|
66
|
+
// Create entity
|
|
67
|
+
const entityResult = await db.run(`
|
|
68
|
+
?[id, name, type] <- [['test-entity', 'Test Entity', 'Test']]
|
|
69
|
+
:put entity {id, name, type}
|
|
70
|
+
`);
|
|
71
|
+
for (const obs of testObservations) {
|
|
72
|
+
const obsId = `obs-${Math.random().toString(36).substring(7)}`;
|
|
73
|
+
await db.run(`
|
|
74
|
+
?[id, entity_id, text, metadata] <- [[
|
|
75
|
+
$id,
|
|
76
|
+
'test-entity',
|
|
77
|
+
$text,
|
|
78
|
+
{}
|
|
79
|
+
]]
|
|
80
|
+
:put observation {id, entity_id, text, metadata}
|
|
81
|
+
`, { id: obsId, text: obs.text });
|
|
82
|
+
}
|
|
83
|
+
console.log(`✓ Created ${testObservations.length} test observations\n`);
|
|
84
|
+
// Test 2: Calculate salience scores
|
|
85
|
+
console.log('Test 2: Calculating salience scores...');
|
|
86
|
+
const scores = await salienceService.scoreAllObservations();
|
|
87
|
+
console.log(`\nSalience Scores (sorted by score):`);
|
|
88
|
+
console.log('─'.repeat(80));
|
|
89
|
+
for (const score of scores.slice(0, 10)) {
|
|
90
|
+
console.log(`Score: ${score.salienceScore.toFixed(3)} | Category: ${score.category.toUpperCase()}`);
|
|
91
|
+
console.log(`Text: ${score.text.substring(0, 70)}${score.text.length > 70 ? '...' : ''}`);
|
|
92
|
+
console.log(`Keywords: ${score.detectedKeywords.join(', ')}`);
|
|
93
|
+
console.log(`Boost: Strength ×${score.boost.strengthMultiplier.toFixed(2)}, Decay -${(score.boost.decayReduction * 100).toFixed(0)}%`);
|
|
94
|
+
console.log(`Reason: ${score.reason}`);
|
|
95
|
+
console.log('─'.repeat(80));
|
|
96
|
+
}
|
|
97
|
+
// Test 3: Verify keyword detection
|
|
98
|
+
console.log('\nTest 3: Verifying keyword detection accuracy...');
|
|
99
|
+
let correctDetections = 0;
|
|
100
|
+
for (let i = 0; i < testObservations.length; i++) {
|
|
101
|
+
const expected = testObservations[i].expected;
|
|
102
|
+
const actual = scores.find(s => s.text === testObservations[i].text)?.category || 'neutral';
|
|
103
|
+
const match = expected === actual;
|
|
104
|
+
correctDetections += match ? 1 : 0;
|
|
105
|
+
console.log(`${match ? '✓' : '✗'} Expected: ${expected.padEnd(8)} | Actual: ${actual.padEnd(8)} | "${testObservations[i].text.substring(0, 50)}..."`);
|
|
106
|
+
}
|
|
107
|
+
console.log(`\nAccuracy: ${correctDetections}/${testObservations.length} (${(correctDetections / testObservations.length * 100).toFixed(1)}%)\n`);
|
|
108
|
+
// Test 4: Apply salience metadata (dry run)
|
|
109
|
+
console.log('Test 4: Applying salience metadata (dry run)...');
|
|
110
|
+
const dryRunResult = await salienceService.applySalienceMetadata(true);
|
|
111
|
+
console.log(`Would update ${dryRunResult.updated} observations (dry run)`);
|
|
112
|
+
console.log(`Observations with salience >= threshold: ${dryRunResult.scores.length}\n`);
|
|
113
|
+
// Test 5: Apply salience metadata (actual)
|
|
114
|
+
console.log('Test 5: Applying salience metadata (actual)...');
|
|
115
|
+
const applyResult = await salienceService.applySalienceMetadata(false);
|
|
116
|
+
console.log(`✓ Updated ${applyResult.updated} observations with salience metadata\n`);
|
|
117
|
+
// Test 6: Get statistics
|
|
118
|
+
console.log('Test 6: Getting salience statistics...');
|
|
119
|
+
const stats = await salienceService.getSalienceStats();
|
|
120
|
+
console.log(`Total Observations: ${stats.totalObservations}`);
|
|
121
|
+
console.log(`With Salience (>= threshold): ${stats.withSalience}`);
|
|
122
|
+
console.log(`Average Salience: ${stats.averageSalience.toFixed(3)}`);
|
|
123
|
+
console.log(`\nDistribution:`);
|
|
124
|
+
console.log(` High (>= 0.7): ${stats.distribution.high}`);
|
|
125
|
+
console.log(` Medium (0.4-0.7): ${stats.distribution.medium}`);
|
|
126
|
+
console.log(` Low (0.3-0.4): ${stats.distribution.low}`);
|
|
127
|
+
console.log(` Neutral (< 0.3): ${stats.distribution.neutral}`);
|
|
128
|
+
console.log(`\nTop Keywords:`);
|
|
129
|
+
for (const { keyword, count } of stats.topKeywords.slice(0, 5)) {
|
|
130
|
+
console.log(` ${keyword.padEnd(20)} ${count}`);
|
|
131
|
+
}
|
|
132
|
+
console.log();
|
|
133
|
+
// Test 7: Get specific observation salience
|
|
134
|
+
console.log('Test 7: Getting salience for specific observation...');
|
|
135
|
+
const firstScore = scores[0];
|
|
136
|
+
const specificSalience = await salienceService.getObservationSalience(firstScore.observationId);
|
|
137
|
+
if (specificSalience) {
|
|
138
|
+
console.log(`✓ Retrieved salience for observation: ${specificSalience.observationId}`);
|
|
139
|
+
console.log(` Score: ${specificSalience.salienceScore.toFixed(3)}`);
|
|
140
|
+
console.log(` Category: ${specificSalience.category}`);
|
|
141
|
+
console.log(` Keywords: ${specificSalience.detectedKeywords.join(', ')}`);
|
|
142
|
+
}
|
|
143
|
+
console.log();
|
|
144
|
+
// Test 8: Test edge cases
|
|
145
|
+
console.log('Test 8: Testing edge cases...');
|
|
146
|
+
const edgeCases = [
|
|
147
|
+
{ text: '', expected: 0 },
|
|
148
|
+
{ text: 'CRITICAL URGENT IMPORTANT NEVER FORGET', expected: 1.0 },
|
|
149
|
+
{ text: 'critical critical critical', expected: 1.0 }, // Duplicate keywords
|
|
150
|
+
{ text: 'This is critically important and urgent!', expected: 0.8 }
|
|
151
|
+
];
|
|
152
|
+
for (const testCase of edgeCases) {
|
|
153
|
+
const result = salienceService.calculateSalienceScore(testCase.text);
|
|
154
|
+
const pass = Math.abs(result.score - testCase.expected) < 0.2; // Allow 0.2 tolerance
|
|
155
|
+
console.log(`${pass ? '✓' : '✗'} "${testCase.text}" => ${result.score.toFixed(3)} (expected ~${testCase.expected})`);
|
|
156
|
+
}
|
|
157
|
+
console.log();
|
|
158
|
+
// Test 9: Integration with Memory Activation
|
|
159
|
+
console.log('Test 9: Demonstrating integration with Memory Activation...');
|
|
160
|
+
console.log('Salience boosts can be applied to ACT-R Memory Activation:');
|
|
161
|
+
console.log(' - High salience (0.8): Strength ×1.8, Decay -40%');
|
|
162
|
+
console.log(' - Medium salience (0.5): Strength ×1.5, Decay -25%');
|
|
163
|
+
console.log(' - Low salience (0.3): Strength ×1.3, Decay -15%');
|
|
164
|
+
console.log(' - Neutral (0.0): No boost applied');
|
|
165
|
+
console.log('\nThis slows down Ebbinghaus forgetting curve for emotionally salient memories.\n');
|
|
166
|
+
console.log('=== All Tests Completed Successfully ===');
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.error('Test failed:', error);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
db.close();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Run tests
|
|
177
|
+
testEmotionalSalience().catch(console.error);
|