cozo-memory 1.1.4 → 1.1.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 +161 -1159
- package/dist/adaptive-query-fusion.js +397 -0
- package/dist/dynamic-fusion.js +63 -8
- package/dist/explainable-retrieval.js +552 -0
- package/dist/hierarchical-memory.js +358 -0
- package/dist/proactive-suggestions.js +382 -0
- package/dist/temporal-conflict-resolution.js +386 -0
- package/dist/temporal-pattern-detection-backup.js +358 -0
- package/dist/temporal-pattern-detection.js +482 -0
- package/dist/test-adaptive-query-fusion.js +208 -0
- package/dist/test-explainable-retrieval.js +408 -0
- package/dist/test-hierarchical-and-patterns.js +17 -0
- package/dist/test-hierarchical-memory.js +205 -0
- package/dist/test-proactive-suggestions.js +240 -0
- package/dist/test-temporal-conflict-resolution.js +228 -0
- package/dist/test-temporal-patterns.js +317 -0
- package/package.json +1 -1
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Test: Temporal Pattern Detection
|
|
4
|
+
*
|
|
5
|
+
* Tests detection of recurring events, cyclical relationships,
|
|
6
|
+
* temporal correlations, and seasonal trends
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const cozo_node_1 = require("cozo-node");
|
|
10
|
+
const embedding_service_1 = require("./embedding-service");
|
|
11
|
+
const temporal_pattern_detection_1 = require("./temporal-pattern-detection");
|
|
12
|
+
const uuid_1 = require("uuid");
|
|
13
|
+
async function testTemporalPatterns() {
|
|
14
|
+
console.log('\n=== Testing Temporal Pattern Detection ===\n');
|
|
15
|
+
const db = new cozo_node_1.CozoDb('mem', '');
|
|
16
|
+
const embeddings = new embedding_service_1.EmbeddingService();
|
|
17
|
+
const patternDetection = new temporal_pattern_detection_1.TemporalPatternDetectionService(db, embeddings, {
|
|
18
|
+
min_occurrences: 3,
|
|
19
|
+
min_confidence: 0.5,
|
|
20
|
+
time_window_days: 365,
|
|
21
|
+
similarity_threshold: 0.7,
|
|
22
|
+
seasonal_buckets: 12
|
|
23
|
+
});
|
|
24
|
+
try {
|
|
25
|
+
// Setup schema
|
|
26
|
+
console.log('Setting up schema...');
|
|
27
|
+
await db.run(`
|
|
28
|
+
:create entity {
|
|
29
|
+
id: String =>
|
|
30
|
+
name: String,
|
|
31
|
+
type: String,
|
|
32
|
+
embedding: <F32; 1024>,
|
|
33
|
+
name_embedding: <F32; 1024>,
|
|
34
|
+
metadata: Json,
|
|
35
|
+
created_at: Validity
|
|
36
|
+
}
|
|
37
|
+
`);
|
|
38
|
+
await db.run(`
|
|
39
|
+
:create observation {
|
|
40
|
+
id: String,
|
|
41
|
+
created_at: Validity =>
|
|
42
|
+
entity_id: String,
|
|
43
|
+
text: String,
|
|
44
|
+
embedding: <F32; 1024>,
|
|
45
|
+
metadata: Json
|
|
46
|
+
}
|
|
47
|
+
`);
|
|
48
|
+
await db.run(`
|
|
49
|
+
:create relationship {
|
|
50
|
+
from_id: String,
|
|
51
|
+
to_id: String,
|
|
52
|
+
created_at: Validity =>
|
|
53
|
+
relation_type: String,
|
|
54
|
+
strength: Float,
|
|
55
|
+
metadata: Json
|
|
56
|
+
}
|
|
57
|
+
`);
|
|
58
|
+
// Clean up any existing temporal_pattern relation from previous runs
|
|
59
|
+
try {
|
|
60
|
+
await db.run(`:remove temporal_pattern`);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// Relation might not exist, that's fine
|
|
64
|
+
}
|
|
65
|
+
// Create test entities
|
|
66
|
+
console.log('\n1. Creating test entities...');
|
|
67
|
+
const projectId = (0, uuid_1.v4)();
|
|
68
|
+
const budgetId = (0, uuid_1.v4)();
|
|
69
|
+
const teamId = (0, uuid_1.v4)();
|
|
70
|
+
const entities = [
|
|
71
|
+
{ id: projectId, name: 'Quarterly Review Project', type: 'Project' },
|
|
72
|
+
{ id: budgetId, name: 'Budget Department', type: 'Department' },
|
|
73
|
+
{ id: teamId, name: 'Development Team', type: 'Team' }
|
|
74
|
+
];
|
|
75
|
+
const now = Date.now() * 1000;
|
|
76
|
+
for (const entity of entities) {
|
|
77
|
+
const embedding = await embeddings.embed(entity.name);
|
|
78
|
+
await db.run(`
|
|
79
|
+
?[id, created_at, name, type, embedding, name_embedding, metadata] :=
|
|
80
|
+
id = $id,
|
|
81
|
+
created_at = $created_at,
|
|
82
|
+
name = $name,
|
|
83
|
+
type = $type,
|
|
84
|
+
embedding = $embedding,
|
|
85
|
+
name_embedding = $name_embedding,
|
|
86
|
+
metadata = $metadata
|
|
87
|
+
|
|
88
|
+
:put entity {
|
|
89
|
+
id, created_at => name, type, embedding, name_embedding, metadata
|
|
90
|
+
}
|
|
91
|
+
`, {
|
|
92
|
+
id: entity.id,
|
|
93
|
+
created_at: [now, true],
|
|
94
|
+
name: entity.name,
|
|
95
|
+
type: entity.type,
|
|
96
|
+
embedding,
|
|
97
|
+
name_embedding: embedding,
|
|
98
|
+
metadata: {}
|
|
99
|
+
});
|
|
100
|
+
console.log(` ✓ Created entity: ${entity.name}`);
|
|
101
|
+
}
|
|
102
|
+
// Create relationships for cyclical pattern
|
|
103
|
+
console.log('\n2. Creating cyclical relationships...');
|
|
104
|
+
const relationships = [
|
|
105
|
+
{ from: projectId, to: budgetId, type: 'requires_approval_from' },
|
|
106
|
+
{ from: budgetId, to: teamId, type: 'allocates_resources_to' },
|
|
107
|
+
{ from: teamId, to: projectId, type: 'works_on' }
|
|
108
|
+
];
|
|
109
|
+
for (const rel of relationships) {
|
|
110
|
+
await db.run(`
|
|
111
|
+
?[from_id, to_id, created_at, relation_type, strength, metadata] :=
|
|
112
|
+
from_id = $from_id,
|
|
113
|
+
to_id = $to_id,
|
|
114
|
+
created_at = $created_at,
|
|
115
|
+
relation_type = $relation_type,
|
|
116
|
+
strength = $strength,
|
|
117
|
+
metadata = $metadata
|
|
118
|
+
|
|
119
|
+
:put relationship {
|
|
120
|
+
from_id, to_id, created_at => relation_type, strength, metadata
|
|
121
|
+
}
|
|
122
|
+
`, {
|
|
123
|
+
from_id: rel.from,
|
|
124
|
+
to_id: rel.to,
|
|
125
|
+
created_at: [now, true],
|
|
126
|
+
relation_type: rel.type,
|
|
127
|
+
strength: 1.0,
|
|
128
|
+
metadata: {}
|
|
129
|
+
});
|
|
130
|
+
console.log(` ✓ Created relationship: ${rel.type}`);
|
|
131
|
+
}
|
|
132
|
+
// Create recurring event observations (quarterly reviews)
|
|
133
|
+
console.log('\n3. Creating recurring event observations...');
|
|
134
|
+
const recurringText = 'Quarterly budget review meeting scheduled';
|
|
135
|
+
const recurringEmbedding = await embeddings.embed(recurringText);
|
|
136
|
+
// Create 5 occurrences at ~90 day intervals
|
|
137
|
+
const quarterlyIntervalMs = 90 * 24 * 60 * 60 * 1000;
|
|
138
|
+
for (let i = 0; i < 5; i++) {
|
|
139
|
+
const obsId = (0, uuid_1.v4)();
|
|
140
|
+
const obsTime = now - (4 - i) * quarterlyIntervalMs * 1000; // microseconds
|
|
141
|
+
await db.run(`
|
|
142
|
+
?[id, created_at, entity_id, text, embedding, metadata] :=
|
|
143
|
+
id = $id,
|
|
144
|
+
created_at = $created_at,
|
|
145
|
+
entity_id = $entity_id,
|
|
146
|
+
text = $text,
|
|
147
|
+
embedding = $embedding,
|
|
148
|
+
metadata = $metadata
|
|
149
|
+
|
|
150
|
+
:put observation {
|
|
151
|
+
id, created_at => entity_id, text, embedding, metadata
|
|
152
|
+
}
|
|
153
|
+
`, {
|
|
154
|
+
id: obsId,
|
|
155
|
+
created_at: [obsTime, true],
|
|
156
|
+
entity_id: projectId,
|
|
157
|
+
text: recurringText,
|
|
158
|
+
embedding: recurringEmbedding,
|
|
159
|
+
metadata: {}
|
|
160
|
+
});
|
|
161
|
+
const date = new Date(obsTime / 1000);
|
|
162
|
+
console.log(` ✓ Created occurrence ${i + 1}/5 at ${date.toISOString().split('T')[0]}`);
|
|
163
|
+
}
|
|
164
|
+
// Create temporal correlation observations
|
|
165
|
+
console.log('\n4. Creating temporal correlation observations...');
|
|
166
|
+
const correlatedEvents = [
|
|
167
|
+
{ text: 'Sprint planning initiated', days_ago: 7 },
|
|
168
|
+
{ text: 'Budget allocation requested', days_ago: 6 },
|
|
169
|
+
{ text: 'Sprint planning initiated', days_ago: 21 },
|
|
170
|
+
{ text: 'Budget allocation requested', days_ago: 20 },
|
|
171
|
+
{ text: 'Sprint planning initiated', days_ago: 35 },
|
|
172
|
+
{ text: 'Budget allocation requested', days_ago: 34 }
|
|
173
|
+
];
|
|
174
|
+
for (const event of correlatedEvents) {
|
|
175
|
+
const obsId = (0, uuid_1.v4)();
|
|
176
|
+
const obsTime = now - (event.days_ago * 24 * 60 * 60 * 1000 * 1000);
|
|
177
|
+
const obsEmbedding = await embeddings.embed(event.text);
|
|
178
|
+
await db.run(`
|
|
179
|
+
?[id, created_at, entity_id, text, embedding, metadata] :=
|
|
180
|
+
id = $id,
|
|
181
|
+
created_at = $created_at,
|
|
182
|
+
entity_id = $entity_id,
|
|
183
|
+
text = $text,
|
|
184
|
+
embedding = $embedding,
|
|
185
|
+
metadata = $metadata
|
|
186
|
+
|
|
187
|
+
:put observation {
|
|
188
|
+
id, created_at => entity_id, text, embedding, metadata
|
|
189
|
+
}
|
|
190
|
+
`, {
|
|
191
|
+
id: obsId,
|
|
192
|
+
created_at: [obsTime, true],
|
|
193
|
+
entity_id: projectId,
|
|
194
|
+
text: event.text,
|
|
195
|
+
embedding: obsEmbedding,
|
|
196
|
+
metadata: {}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
console.log(` ✓ Created ${correlatedEvents.length} correlated observations`);
|
|
200
|
+
// Create seasonal trend observations (more activity in certain months)
|
|
201
|
+
console.log('\n5. Creating seasonal trend observations...');
|
|
202
|
+
const monthlyActivity = [
|
|
203
|
+
{ month: 0, count: 2 }, // January
|
|
204
|
+
{ month: 1, count: 2 }, // February
|
|
205
|
+
{ month: 2, count: 3 }, // March
|
|
206
|
+
{ month: 3, count: 8 }, // April (high activity)
|
|
207
|
+
{ month: 4, count: 2 }, // May
|
|
208
|
+
{ month: 5, count: 2 }, // June
|
|
209
|
+
{ month: 6, count: 2 }, // July
|
|
210
|
+
{ month: 7, count: 2 }, // August
|
|
211
|
+
{ month: 8, count: 3 }, // September
|
|
212
|
+
{ month: 9, count: 8 }, // October (high activity)
|
|
213
|
+
{ month: 10, count: 2 }, // November
|
|
214
|
+
{ month: 11, count: 2 } // December
|
|
215
|
+
];
|
|
216
|
+
for (const activity of monthlyActivity) {
|
|
217
|
+
for (let i = 0; i < activity.count; i++) {
|
|
218
|
+
const obsId = (0, uuid_1.v4)();
|
|
219
|
+
const date = new Date(2024, activity.month, 1 + i);
|
|
220
|
+
const obsTime = date.getTime() * 1000; // microseconds
|
|
221
|
+
const obsText = `Activity in ${date.toLocaleString('default', { month: 'long' })}`;
|
|
222
|
+
const obsEmbedding = await embeddings.embed(obsText);
|
|
223
|
+
await db.run(`
|
|
224
|
+
?[id, created_at, entity_id, text, embedding, metadata] :=
|
|
225
|
+
id = $id,
|
|
226
|
+
created_at = $created_at,
|
|
227
|
+
entity_id = $entity_id,
|
|
228
|
+
text = $text,
|
|
229
|
+
embedding = $embedding,
|
|
230
|
+
metadata = $metadata
|
|
231
|
+
|
|
232
|
+
:put observation {
|
|
233
|
+
id, created_at => entity_id, text, embedding, metadata
|
|
234
|
+
}
|
|
235
|
+
`, {
|
|
236
|
+
id: obsId,
|
|
237
|
+
created_at: [obsTime, true],
|
|
238
|
+
entity_id: projectId,
|
|
239
|
+
text: obsText,
|
|
240
|
+
embedding: obsEmbedding,
|
|
241
|
+
metadata: {}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
console.log(` ✓ Created seasonal observations across 12 months`);
|
|
246
|
+
// Detect all patterns
|
|
247
|
+
console.log('\n6. Detecting patterns...');
|
|
248
|
+
const patterns = await patternDetection.detectPatterns(projectId);
|
|
249
|
+
console.log(` ✓ Found ${patterns.length} patterns\n`);
|
|
250
|
+
// Display detected patterns
|
|
251
|
+
console.log('7. Pattern details:\n');
|
|
252
|
+
const recurringPatterns = patterns.filter(p => p.pattern_type === temporal_pattern_detection_1.PatternType.RECURRING_EVENT);
|
|
253
|
+
console.log(` Recurring Events (${recurringPatterns.length}):`);
|
|
254
|
+
for (const pattern of recurringPatterns) {
|
|
255
|
+
console.log(` • ${pattern.description}`);
|
|
256
|
+
console.log(` Frequency: ${pattern.frequency} occurrences`);
|
|
257
|
+
console.log(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
|
|
258
|
+
console.log(` Interval: ~${pattern.interval_days?.toFixed(0)} days`);
|
|
259
|
+
}
|
|
260
|
+
const cyclicalPatterns = patterns.filter(p => p.pattern_type === temporal_pattern_detection_1.PatternType.CYCLICAL_RELATIONSHIP);
|
|
261
|
+
console.log(`\n Cyclical Relationships (${cyclicalPatterns.length}):`);
|
|
262
|
+
for (const pattern of cyclicalPatterns) {
|
|
263
|
+
console.log(` • ${pattern.description}`);
|
|
264
|
+
console.log(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
|
|
265
|
+
}
|
|
266
|
+
const correlationPatterns = patterns.filter(p => p.pattern_type === temporal_pattern_detection_1.PatternType.TEMPORAL_CORRELATION);
|
|
267
|
+
console.log(`\n Temporal Correlations (${correlationPatterns.length}):`);
|
|
268
|
+
for (const pattern of correlationPatterns) {
|
|
269
|
+
console.log(` • ${pattern.description}`);
|
|
270
|
+
console.log(` Frequency: ${pattern.frequency} occurrences`);
|
|
271
|
+
console.log(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
|
|
272
|
+
}
|
|
273
|
+
const seasonalPatterns = patterns.filter(p => p.pattern_type === temporal_pattern_detection_1.PatternType.SEASONAL_TREND);
|
|
274
|
+
console.log(`\n Seasonal Trends (${seasonalPatterns.length}):`);
|
|
275
|
+
for (const pattern of seasonalPatterns) {
|
|
276
|
+
console.log(` • ${pattern.description}`);
|
|
277
|
+
console.log(` Frequency: ${pattern.frequency} occurrences`);
|
|
278
|
+
console.log(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
|
|
279
|
+
}
|
|
280
|
+
// Store patterns
|
|
281
|
+
console.log('\n8. Storing patterns...');
|
|
282
|
+
for (const pattern of patterns.slice(0, 3)) { // Store first 3
|
|
283
|
+
await patternDetection.storePattern(pattern);
|
|
284
|
+
console.log(` ✓ Stored pattern: ${pattern.pattern_type}`);
|
|
285
|
+
}
|
|
286
|
+
// Retrieve stored patterns
|
|
287
|
+
console.log('\n9. Retrieving stored patterns...');
|
|
288
|
+
const storedPatterns = await patternDetection.getStoredPatterns(projectId);
|
|
289
|
+
console.log(` ✓ Retrieved ${storedPatterns.length} stored patterns`);
|
|
290
|
+
// Test configuration
|
|
291
|
+
console.log('\n10. Testing configuration...');
|
|
292
|
+
const config = patternDetection.getConfig();
|
|
293
|
+
console.log(` Min occurrences: ${config.min_occurrences}`);
|
|
294
|
+
console.log(` Min confidence: ${config.min_confidence}`);
|
|
295
|
+
console.log(` Time window: ${config.time_window_days} days`);
|
|
296
|
+
console.log(` Similarity threshold: ${config.similarity_threshold}`);
|
|
297
|
+
console.log(` Seasonal buckets: ${config.seasonal_buckets}`);
|
|
298
|
+
// Update configuration
|
|
299
|
+
patternDetection.updateConfig({
|
|
300
|
+
min_confidence: 0.7
|
|
301
|
+
});
|
|
302
|
+
console.log(` ✓ Updated min confidence to 0.7`);
|
|
303
|
+
console.log('\n✅ All temporal pattern detection tests passed!\n');
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
console.error('\n❌ Test failed:', error.message);
|
|
307
|
+
if (error.display) {
|
|
308
|
+
console.error('CozoDB Error:', error.display);
|
|
309
|
+
}
|
|
310
|
+
console.error(error.stack);
|
|
311
|
+
}
|
|
312
|
+
finally {
|
|
313
|
+
db.close();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Run tests
|
|
317
|
+
testTemporalPatterns().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozo-memory",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"mcpName": "io.github.tobs-code/cozo-memory",
|
|
5
5
|
"description": "Local-first persistent memory system for AI agents with hybrid search, graph reasoning, and MCP integration",
|
|
6
6
|
"main": "dist/index.js",
|