@smallironman/mcp-memory-keeper 0.12.2-fork1

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.
Files changed (110) hide show
  1. package/CHANGELOG.md +542 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1281 -0
  4. package/bin/mcp-memory-keeper +54 -0
  5. package/dist/__tests__/e2e/issue33-reproduce.test.js +234 -0
  6. package/dist/__tests__/e2e/server-e2e.test.js +341 -0
  7. package/dist/__tests__/helpers/database-test-helper.js +160 -0
  8. package/dist/__tests__/helpers/test-server.js +92 -0
  9. package/dist/__tests__/integration/advanced-features.test.js +614 -0
  10. package/dist/__tests__/integration/backward-compatibility.test.js +245 -0
  11. package/dist/__tests__/integration/batchOperationsE2E.test.js +396 -0
  12. package/dist/__tests__/integration/batchOperationsHandler.test.js +1230 -0
  13. package/dist/__tests__/integration/channelManagementHandler.test.js +1291 -0
  14. package/dist/__tests__/integration/channels.test.js +376 -0
  15. package/dist/__tests__/integration/checkpoint.test.js +251 -0
  16. package/dist/__tests__/integration/concurrent-access.test.js +190 -0
  17. package/dist/__tests__/integration/context-operations.test.js +243 -0
  18. package/dist/__tests__/integration/contextDiff.test.js +852 -0
  19. package/dist/__tests__/integration/contextDiffHandler.test.js +976 -0
  20. package/dist/__tests__/integration/contextExportHandler.test.js +510 -0
  21. package/dist/__tests__/integration/contextGetPaginationDefaults.test.js +298 -0
  22. package/dist/__tests__/integration/contextReassignChannelHandler.test.js +908 -0
  23. package/dist/__tests__/integration/contextRelationshipsHandler.test.js +1151 -0
  24. package/dist/__tests__/integration/contextSearch.test.js +1054 -0
  25. package/dist/__tests__/integration/contextSearchHandler.test.js +552 -0
  26. package/dist/__tests__/integration/contextWatchActual.test.js +165 -0
  27. package/dist/__tests__/integration/contextWatchHandler.test.js +1500 -0
  28. package/dist/__tests__/integration/database-initialization.test.js +134 -0
  29. package/dist/__tests__/integration/enhanced-context-operations.test.js +1082 -0
  30. package/dist/__tests__/integration/enhancedContextGetHandler.test.js +915 -0
  31. package/dist/__tests__/integration/enhancedContextTimelineHandler.test.js +716 -0
  32. package/dist/__tests__/integration/error-cases.test.js +411 -0
  33. package/dist/__tests__/integration/export-import.test.js +367 -0
  34. package/dist/__tests__/integration/feature-flags.test.js +542 -0
  35. package/dist/__tests__/integration/file-operations.test.js +264 -0
  36. package/dist/__tests__/integration/filterBySessionId.test.js +251 -0
  37. package/dist/__tests__/integration/git-integration.test.js +241 -0
  38. package/dist/__tests__/integration/index-tools.test.js +496 -0
  39. package/dist/__tests__/integration/issue11-actual-bug-demo.test.js +304 -0
  40. package/dist/__tests__/integration/issue11-search-filters-bug.test.js +561 -0
  41. package/dist/__tests__/integration/issue12-checkpoint-restore-behavior.test.js +621 -0
  42. package/dist/__tests__/integration/issue13-key-validation.test.js +433 -0
  43. package/dist/__tests__/integration/issue24-final-fix.test.js +241 -0
  44. package/dist/__tests__/integration/issue24-fix-validation.test.js +158 -0
  45. package/dist/__tests__/integration/issue24-reproduce.test.js +225 -0
  46. package/dist/__tests__/integration/issue24-token-limit.test.js +199 -0
  47. package/dist/__tests__/integration/issue33-array-items-schema.test.js +165 -0
  48. package/dist/__tests__/integration/knowledge-graph.test.js +338 -0
  49. package/dist/__tests__/integration/migrations.test.js +528 -0
  50. package/dist/__tests__/integration/multi-agent.test.js +546 -0
  51. package/dist/__tests__/integration/pagination-critical-fix.test.js +296 -0
  52. package/dist/__tests__/integration/paginationDefaultsHandler.test.js +600 -0
  53. package/dist/__tests__/integration/project-directory.test.js +291 -0
  54. package/dist/__tests__/integration/resource-cleanup.test.js +149 -0
  55. package/dist/__tests__/integration/retention.test.js +513 -0
  56. package/dist/__tests__/integration/search.test.js +333 -0
  57. package/dist/__tests__/integration/semantic-search.test.js +266 -0
  58. package/dist/__tests__/integration/server-initialization.test.js +305 -0
  59. package/dist/__tests__/integration/session-management.test.js +219 -0
  60. package/dist/__tests__/integration/simplified-sharing.test.js +346 -0
  61. package/dist/__tests__/integration/smart-compaction.test.js +230 -0
  62. package/dist/__tests__/integration/summarization.test.js +308 -0
  63. package/dist/__tests__/integration/tokenLimitEnforcement.test.js +134 -0
  64. package/dist/__tests__/integration/tool-profiles-integration.test.js +150 -0
  65. package/dist/__tests__/integration/watcher-migration-validation.test.js +544 -0
  66. package/dist/__tests__/security/input-validation.test.js +115 -0
  67. package/dist/__tests__/utils/agents.test.js +473 -0
  68. package/dist/__tests__/utils/database.test.js +177 -0
  69. package/dist/__tests__/utils/git.test.js +122 -0
  70. package/dist/__tests__/utils/knowledge-graph.test.js +297 -0
  71. package/dist/__tests__/utils/migrationHealthCheck.test.js +302 -0
  72. package/dist/__tests__/utils/project-directory-messages.test.js +192 -0
  73. package/dist/__tests__/utils/timezone-safe-dates.js +119 -0
  74. package/dist/__tests__/utils/token-limits.test.js +225 -0
  75. package/dist/__tests__/utils/tool-profiles.test.js +374 -0
  76. package/dist/__tests__/utils/validation.test.js +200 -0
  77. package/dist/__tests__/utils/vector-store.test.js +231 -0
  78. package/dist/handlers/contextWatchHandlers.js +206 -0
  79. package/dist/index.js +4425 -0
  80. package/dist/migrations/003_add_channels.js +174 -0
  81. package/dist/migrations/004_add_context_watch.js +151 -0
  82. package/dist/migrations/005_add_context_watch.js +98 -0
  83. package/dist/migrations/simplify-sharing.js +117 -0
  84. package/dist/repositories/BaseRepository.js +30 -0
  85. package/dist/repositories/CheckpointRepository.js +140 -0
  86. package/dist/repositories/ContextRepository.js +2017 -0
  87. package/dist/repositories/FileRepository.js +104 -0
  88. package/dist/repositories/RepositoryManager.js +62 -0
  89. package/dist/repositories/SessionRepository.js +66 -0
  90. package/dist/repositories/WatcherRepository.js +252 -0
  91. package/dist/repositories/index.js +15 -0
  92. package/dist/test-helpers/database-helper.js +128 -0
  93. package/dist/types/entities.js +3 -0
  94. package/dist/utils/agents.js +791 -0
  95. package/dist/utils/channels.js +150 -0
  96. package/dist/utils/database.js +780 -0
  97. package/dist/utils/feature-flags.js +476 -0
  98. package/dist/utils/git.js +145 -0
  99. package/dist/utils/knowledge-graph.js +264 -0
  100. package/dist/utils/migrationHealthCheck.js +373 -0
  101. package/dist/utils/migrations.js +452 -0
  102. package/dist/utils/retention.js +460 -0
  103. package/dist/utils/timestamps.js +112 -0
  104. package/dist/utils/token-limits.js +350 -0
  105. package/dist/utils/tool-profiles.js +242 -0
  106. package/dist/utils/validation.js +296 -0
  107. package/dist/utils/vector-store.js +247 -0
  108. package/examples/config.json +31 -0
  109. package/examples/project-directory-setup.md +114 -0
  110. package/package.json +85 -0
@@ -0,0 +1,791 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentCoordinator = exports.SynthesizerAgent = exports.AnalyzerAgent = exports.Agent = void 0;
4
+ // Base Agent class
5
+ class Agent {
6
+ name;
7
+ capabilities;
8
+ constructor(name, capabilities) {
9
+ this.name = name;
10
+ this.capabilities = capabilities;
11
+ }
12
+ canHandle(task) {
13
+ return this.capabilities.some(cap => cap.inputTypes.includes(task.type));
14
+ }
15
+ getName() {
16
+ return this.name;
17
+ }
18
+ }
19
+ exports.Agent = Agent;
20
+ // Analyzer Agent - Analyzes context to extract insights
21
+ class AnalyzerAgent extends Agent {
22
+ db;
23
+ knowledgeGraph;
24
+ vectorStore;
25
+ constructor(db, knowledgeGraph, vectorStore) {
26
+ super('analyzer', [
27
+ {
28
+ name: 'pattern_detection',
29
+ description: 'Detect patterns in saved context',
30
+ inputTypes: ['analyze'],
31
+ outputTypes: ['patterns', 'insights'],
32
+ },
33
+ {
34
+ name: 'relationship_extraction',
35
+ description: 'Extract relationships between entities',
36
+ inputTypes: ['analyze'],
37
+ outputTypes: ['relationships'],
38
+ },
39
+ {
40
+ name: 'trend_analysis',
41
+ description: 'Analyze trends over time',
42
+ inputTypes: ['analyze'],
43
+ outputTypes: ['trends'],
44
+ },
45
+ ]);
46
+ this.db = db;
47
+ this.knowledgeGraph = knowledgeGraph;
48
+ this.vectorStore = vectorStore;
49
+ }
50
+ async process(task) {
51
+ const startTime = Date.now();
52
+ switch (task.input.analysisType) {
53
+ case 'patterns':
54
+ return this.analyzePatterns(task, startTime);
55
+ case 'relationships':
56
+ return this.analyzeRelationships(task, startTime);
57
+ case 'trends':
58
+ return this.analyzeTrends(task, startTime);
59
+ case 'comprehensive':
60
+ return this.comprehensiveAnalysis(task, startTime);
61
+ default:
62
+ return {
63
+ taskId: task.id,
64
+ agentType: this.name,
65
+ output: { error: 'Unknown analysis type' },
66
+ confidence: 0,
67
+ processingTime: Date.now() - startTime,
68
+ };
69
+ }
70
+ }
71
+ async analyzePatterns(task, startTime) {
72
+ const { sessionId, categories, timeframe } = task.input;
73
+ // Get context items
74
+ let query = `
75
+ SELECT key, value, category, priority, created_at
76
+ FROM context_items
77
+ WHERE session_id = ?
78
+ `;
79
+ const params = [sessionId];
80
+ if (categories && categories.length > 0) {
81
+ query += ` AND category IN (${categories.map(() => '?').join(',')})`;
82
+ params.push(...categories);
83
+ }
84
+ if (timeframe) {
85
+ query += ` AND created_at >= datetime('now', ?)`;
86
+ params.push(timeframe);
87
+ }
88
+ const items = this.db.prepare(query).all(...params);
89
+ // Analyze patterns
90
+ const patterns = {
91
+ categoryDistribution: this.getCategoryDistribution(items),
92
+ priorityDistribution: this.getPriorityDistribution(items),
93
+ temporalPatterns: this.getTemporalPatterns(items),
94
+ keywordFrequency: this.getKeywordFrequency(items),
95
+ workflowPatterns: this.detectWorkflowPatterns(items),
96
+ };
97
+ const confidence = items.length > 10 ? 0.9 : 0.7;
98
+ return {
99
+ taskId: task.id,
100
+ agentType: this.name,
101
+ output: {
102
+ patterns,
103
+ itemCount: items.length,
104
+ insights: this.generatePatternInsights(patterns),
105
+ },
106
+ confidence,
107
+ reasoning: `Analyzed ${items.length} context items to identify patterns`,
108
+ processingTime: Date.now() - startTime,
109
+ };
110
+ }
111
+ async analyzeRelationships(task, startTime) {
112
+ const { sessionId, entityType, _maxDepth = 2 } = task.input;
113
+ // Get entities and relationships from knowledge graph
114
+ let entityQuery = 'SELECT * FROM entities WHERE session_id = ?';
115
+ const entityParams = [sessionId];
116
+ if (entityType) {
117
+ entityQuery += ' AND type = ?';
118
+ entityParams.push(entityType);
119
+ }
120
+ const entities = this.db.prepare(entityQuery).all(...entityParams);
121
+ const relationships = [];
122
+ for (const entity of entities) {
123
+ const relations = this.db
124
+ .prepare(`
125
+ SELECT r.*, e.name as object_name, e.type as object_type
126
+ FROM relations r
127
+ JOIN entities e ON r.object_id = e.id
128
+ WHERE r.subject_id = ?
129
+ `)
130
+ .all(entity.id);
131
+ relationships.push({
132
+ entity,
133
+ relationships: relations.map(r => ({
134
+ predicate: r.predicate,
135
+ objectId: r.object_id,
136
+ objectName: r.object_name,
137
+ objectType: r.object_type,
138
+ confidence: r.confidence,
139
+ })),
140
+ });
141
+ }
142
+ // Analyze relationship patterns
143
+ const analysis = {
144
+ entityCount: entities.length,
145
+ relationshipTypes: this.getRelationshipTypes(relationships),
146
+ clusters: this.detectClusters(relationships),
147
+ centralNodes: this.findCentralNodes(relationships),
148
+ isolatedEntities: this.findIsolatedEntities(entities, relationships),
149
+ };
150
+ return {
151
+ taskId: task.id,
152
+ agentType: this.name,
153
+ output: {
154
+ analysis,
155
+ recommendations: this.generateRelationshipRecommendations(analysis),
156
+ },
157
+ confidence: 0.85,
158
+ reasoning: `Analyzed ${entities.length} entities and their relationships`,
159
+ processingTime: Date.now() - startTime,
160
+ };
161
+ }
162
+ async analyzeTrends(task, startTime) {
163
+ const { sessionId, metric: _metric, timeframe = '-7 days' } = task.input;
164
+ // Get time-series data
165
+ const query = `
166
+ SELECT
167
+ date(created_at) as date,
168
+ COUNT(*) as count,
169
+ category,
170
+ priority
171
+ FROM context_items
172
+ WHERE session_id = ?
173
+ AND created_at >= datetime('now', ?)
174
+ GROUP BY date(created_at), category, priority
175
+ ORDER BY date
176
+ `;
177
+ const trends = this.db.prepare(query).all(sessionId, timeframe);
178
+ // Analyze trends
179
+ const analysis = {
180
+ activityTrend: this.calculateActivityTrend(trends),
181
+ categoryTrends: this.calculateCategoryTrends(trends),
182
+ priorityShifts: this.detectPriorityShifts(trends),
183
+ predictions: this.generatePredictions(trends),
184
+ };
185
+ return {
186
+ taskId: task.id,
187
+ agentType: this.name,
188
+ output: {
189
+ trends: analysis,
190
+ summary: this.generateTrendSummary(analysis),
191
+ },
192
+ confidence: 0.8,
193
+ reasoning: `Analyzed trends over ${timeframe} period`,
194
+ processingTime: Date.now() - startTime,
195
+ };
196
+ }
197
+ async comprehensiveAnalysis(task, startTime) {
198
+ // Run all analysis types
199
+ const [patterns, relationships, trends] = await Promise.all([
200
+ this.analyzePatterns({ ...task, input: { ...task.input, analysisType: 'patterns' } }, Date.now()),
201
+ this.analyzeRelationships({ ...task, input: { ...task.input, analysisType: 'relationships' } }, Date.now()),
202
+ this.analyzeTrends({ ...task, input: { ...task.input, analysisType: 'trends' } }, Date.now()),
203
+ ]);
204
+ return {
205
+ taskId: task.id,
206
+ agentType: this.name,
207
+ output: {
208
+ patterns: patterns.output,
209
+ relationships: relationships.output,
210
+ trends: trends.output,
211
+ overallInsights: this.generateOverallInsights(patterns.output, relationships.output, trends.output),
212
+ },
213
+ confidence: 0.9,
214
+ reasoning: 'Performed comprehensive analysis across patterns, relationships, and trends',
215
+ processingTime: Date.now() - startTime,
216
+ };
217
+ }
218
+ // Helper methods
219
+ getCategoryDistribution(items) {
220
+ const distribution = {};
221
+ for (const item of items) {
222
+ const category = item.category || 'uncategorized';
223
+ distribution[category] = (distribution[category] || 0) + 1;
224
+ }
225
+ return distribution;
226
+ }
227
+ getPriorityDistribution(items) {
228
+ const distribution = {};
229
+ for (const item of items) {
230
+ const priority = item.priority || 'normal';
231
+ distribution[priority] = (distribution[priority] || 0) + 1;
232
+ }
233
+ return distribution;
234
+ }
235
+ getTemporalPatterns(items) {
236
+ // Group by hour of day and day of week
237
+ const hourly = {};
238
+ const daily = {};
239
+ for (const item of items) {
240
+ const date = new Date(item.created_at);
241
+ const hour = date.getHours();
242
+ const day = date.toLocaleDateString('en-US', { weekday: 'long' });
243
+ hourly[hour] = (hourly[hour] || 0) + 1;
244
+ daily[day] = (daily[day] || 0) + 1;
245
+ }
246
+ return { hourly, daily };
247
+ }
248
+ getKeywordFrequency(items) {
249
+ const frequency = {};
250
+ const stopWords = new Set([
251
+ 'the',
252
+ 'a',
253
+ 'an',
254
+ 'and',
255
+ 'or',
256
+ 'but',
257
+ 'in',
258
+ 'on',
259
+ 'at',
260
+ 'to',
261
+ 'for',
262
+ ]);
263
+ for (const item of items) {
264
+ const text = `${item.key} ${item.value}`.toLowerCase();
265
+ const words = text.match(/\b\w+\b/g) || [];
266
+ for (const word of words) {
267
+ if (word.length > 3 && !stopWords.has(word)) {
268
+ frequency[word] = (frequency[word] || 0) + 1;
269
+ }
270
+ }
271
+ }
272
+ // Return top 20 keywords
273
+ return Object.fromEntries(Object.entries(frequency)
274
+ .sort(([, a], [, b]) => b - a)
275
+ .slice(0, 20));
276
+ }
277
+ detectWorkflowPatterns(items) {
278
+ // Simple workflow detection based on temporal ordering and categories
279
+ const workflows = [];
280
+ const sortedItems = [...items].sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
281
+ let currentWorkflow = [];
282
+ let lastCategory = '';
283
+ for (const item of sortedItems) {
284
+ if (item.category !== lastCategory && currentWorkflow.length > 0) {
285
+ workflows.push({
286
+ steps: currentWorkflow.length,
287
+ categories: [...new Set(currentWorkflow.map(i => i.category))],
288
+ duration: new Date(currentWorkflow[currentWorkflow.length - 1].created_at).getTime() -
289
+ new Date(currentWorkflow[0].created_at).getTime(),
290
+ });
291
+ currentWorkflow = [];
292
+ }
293
+ currentWorkflow.push(item);
294
+ lastCategory = item.category;
295
+ }
296
+ return workflows;
297
+ }
298
+ generatePatternInsights(patterns) {
299
+ const insights = [];
300
+ // Category insights
301
+ const topCategory = Object.entries(patterns.categoryDistribution).sort(([, a], [, b]) => b - a)[0];
302
+ if (topCategory) {
303
+ insights.push(`Most activity in '${topCategory[0]}' category (${topCategory[1]} items)`);
304
+ }
305
+ // Priority insights
306
+ if (patterns.priorityDistribution.high > patterns.priorityDistribution.normal) {
307
+ insights.push('High concentration of high-priority items - consider delegating or breaking down tasks');
308
+ }
309
+ // Temporal insights
310
+ const peakHour = Object.entries(patterns.temporalPatterns.hourly).sort(([, a], [, b]) => b - a)[0];
311
+ if (peakHour) {
312
+ insights.push(`Peak activity at ${peakHour[0]}:00 hours`);
313
+ }
314
+ return insights;
315
+ }
316
+ getRelationshipTypes(relationships) {
317
+ const types = {};
318
+ for (const rel of relationships) {
319
+ for (const r of rel.relationships) {
320
+ types[r.predicate] = (types[r.predicate] || 0) + 1;
321
+ }
322
+ }
323
+ return types;
324
+ }
325
+ detectClusters(relationships) {
326
+ // Simple clustering based on connectivity
327
+ const clusters = [];
328
+ const visited = new Set();
329
+ for (const rel of relationships) {
330
+ if (!visited.has(rel.entity.id)) {
331
+ const cluster = this.buildCluster(rel.entity.id, relationships, visited);
332
+ if (cluster.size > 1) {
333
+ clusters.push(cluster);
334
+ }
335
+ }
336
+ }
337
+ return clusters;
338
+ }
339
+ buildCluster(entityId, relationships, visited) {
340
+ const cluster = {
341
+ entities: [entityId],
342
+ size: 1,
343
+ };
344
+ visited.add(entityId);
345
+ const relatedEntities = relationships.find(r => r.entity.id === entityId)?.relationships || [];
346
+ for (const related of relatedEntities) {
347
+ if (!visited.has(related.objectId)) {
348
+ const subCluster = this.buildCluster(related.objectId, relationships, visited);
349
+ cluster.entities.push(...subCluster.entities);
350
+ cluster.size += subCluster.size;
351
+ }
352
+ }
353
+ return cluster;
354
+ }
355
+ findCentralNodes(relationships) {
356
+ const connectionCount = {};
357
+ for (const rel of relationships) {
358
+ connectionCount[rel.entity.id] = rel.relationships.length;
359
+ }
360
+ return Object.entries(connectionCount)
361
+ .sort(([, a], [, b]) => b - a)
362
+ .slice(0, 5)
363
+ .map(([id, count]) => ({ entityId: id, connections: count }));
364
+ }
365
+ findIsolatedEntities(entities, relationships) {
366
+ const connected = new Set(relationships.map(r => r.entity.id));
367
+ return entities.filter(e => !connected.has(e.id));
368
+ }
369
+ generateRelationshipRecommendations(analysis) {
370
+ const recommendations = [];
371
+ if (analysis.isolatedEntities.length > 0) {
372
+ recommendations.push(`${analysis.isolatedEntities.length} isolated entities found - consider documenting their relationships`);
373
+ }
374
+ if (analysis.clusters.length > 1) {
375
+ recommendations.push(`${analysis.clusters.length} separate clusters detected - look for cross-cluster connections`);
376
+ }
377
+ if (analysis.centralNodes.length > 0) {
378
+ recommendations.push(`Key entities: ${analysis.centralNodes
379
+ .slice(0, 3)
380
+ .map((n) => n.entityId)
381
+ .join(', ')}`);
382
+ }
383
+ return recommendations;
384
+ }
385
+ calculateActivityTrend(trends) {
386
+ const dailyCounts = trends.reduce((acc, item) => {
387
+ acc[item.date] = (acc[item.date] || 0) + item.count;
388
+ return acc;
389
+ }, {});
390
+ const values = Object.values(dailyCounts);
391
+ const avg = values.reduce((a, b) => a + b, 0) / values.length;
392
+ const recent = values.slice(-3).reduce((a, b) => a + b, 0) / 3;
393
+ return {
394
+ direction: recent > avg ? 'increasing' : recent < avg ? 'decreasing' : 'stable',
395
+ averageDaily: avg,
396
+ recentDaily: recent,
397
+ };
398
+ }
399
+ calculateCategoryTrends(trends) {
400
+ const categoryTrends = {};
401
+ for (const trend of trends) {
402
+ if (!categoryTrends[trend.category]) {
403
+ categoryTrends[trend.category] = { dates: [], counts: [] };
404
+ }
405
+ categoryTrends[trend.category].dates.push(trend.date);
406
+ categoryTrends[trend.category].counts.push(trend.count);
407
+ }
408
+ return categoryTrends;
409
+ }
410
+ detectPriorityShifts(trends) {
411
+ const priorityByDate = {};
412
+ for (const trend of trends) {
413
+ if (!priorityByDate[trend.date]) {
414
+ priorityByDate[trend.date] = {};
415
+ }
416
+ priorityByDate[trend.date][trend.priority] = trend.count;
417
+ }
418
+ return priorityByDate;
419
+ }
420
+ generatePredictions(trends) {
421
+ // Simple linear prediction
422
+ return {
423
+ nextDayEstimate: Math.round(trends[trends.length - 1]?.count * 1.1 || 0),
424
+ confidence: 0.6,
425
+ };
426
+ }
427
+ generateTrendSummary(analysis) {
428
+ return `Activity is ${analysis.activityTrend.direction} with an average of ${analysis.activityTrend.averageDaily.toFixed(1)} items per day`;
429
+ }
430
+ generateOverallInsights(patterns, relationships, trends) {
431
+ return [
432
+ ...(patterns.insights || []),
433
+ ...(relationships.recommendations || []),
434
+ trends.summary || '',
435
+ ].filter(Boolean);
436
+ }
437
+ }
438
+ exports.AnalyzerAgent = AnalyzerAgent;
439
+ // Synthesizer Agent - Synthesizes information from multiple sources
440
+ class SynthesizerAgent extends Agent {
441
+ db;
442
+ vectorStore;
443
+ constructor(db, vectorStore) {
444
+ super('synthesizer', [
445
+ {
446
+ name: 'summarization',
447
+ description: 'Create summaries from multiple context items',
448
+ inputTypes: ['synthesize'],
449
+ outputTypes: ['summary'],
450
+ },
451
+ {
452
+ name: 'merge_insights',
453
+ description: 'Merge insights from multiple agents',
454
+ inputTypes: ['synthesize'],
455
+ outputTypes: ['merged_insights'],
456
+ },
457
+ {
458
+ name: 'generate_recommendations',
459
+ description: 'Generate actionable recommendations',
460
+ inputTypes: ['synthesize'],
461
+ outputTypes: ['recommendations'],
462
+ },
463
+ ]);
464
+ this.db = db;
465
+ this.vectorStore = vectorStore;
466
+ }
467
+ async process(task) {
468
+ const startTime = Date.now();
469
+ switch (task.input.synthesisType) {
470
+ case 'summary':
471
+ return this.createSummary(task, startTime);
472
+ case 'merge':
473
+ return this.mergeInsights(task, startTime);
474
+ case 'recommendations':
475
+ return this.generateRecommendations(task, startTime);
476
+ default:
477
+ return {
478
+ taskId: task.id,
479
+ agentType: this.name,
480
+ output: { error: 'Unknown synthesis type' },
481
+ confidence: 0,
482
+ processingTime: Date.now() - startTime,
483
+ };
484
+ }
485
+ }
486
+ async createSummary(task, startTime) {
487
+ const { sessionId, categories, maxLength = 1000 } = task.input;
488
+ // Get relevant context items
489
+ let query = `
490
+ SELECT key, value, category, priority, created_at
491
+ FROM context_items
492
+ WHERE session_id = ?
493
+ `;
494
+ const params = [sessionId];
495
+ if (categories && categories.length > 0) {
496
+ query += ` AND category IN (${categories.map(() => '?').join(',')})`;
497
+ params.push(...categories);
498
+ }
499
+ query += ` ORDER BY priority DESC, created_at DESC LIMIT 50`;
500
+ const items = this.db.prepare(query).all(...params);
501
+ // Create structured summary
502
+ const summary = {
503
+ overview: this.createOverview(items),
504
+ byCategory: this.summarizeByCategory(items),
505
+ keyDecisions: this.extractKeyDecisions(items),
506
+ currentTasks: this.extractCurrentTasks(items),
507
+ recentProgress: this.extractRecentProgress(items),
508
+ };
509
+ // Trim to maxLength
510
+ const formattedSummary = this.formatSummary(summary, maxLength);
511
+ return {
512
+ taskId: task.id,
513
+ agentType: this.name,
514
+ output: {
515
+ summary: formattedSummary,
516
+ itemCount: items.length,
517
+ categories: [...new Set(items.map((i) => i.category))].filter(Boolean),
518
+ },
519
+ confidence: 0.85,
520
+ reasoning: `Synthesized ${items.length} items into structured summary`,
521
+ processingTime: Date.now() - startTime,
522
+ };
523
+ }
524
+ async mergeInsights(task, startTime) {
525
+ const { insights } = task.input;
526
+ if (!Array.isArray(insights) || insights.length === 0) {
527
+ return {
528
+ taskId: task.id,
529
+ agentType: this.name,
530
+ output: { error: 'No insights provided to merge' },
531
+ confidence: 0,
532
+ processingTime: Date.now() - startTime,
533
+ };
534
+ }
535
+ // Merge and deduplicate insights
536
+ const merged = {
537
+ patterns: this.mergePatterns(insights),
538
+ relationships: this.mergeRelationships(insights),
539
+ trends: this.mergeTrends(insights),
540
+ overallThemes: this.identifyThemes(insights),
541
+ conflicts: this.identifyConflicts(insights),
542
+ };
543
+ return {
544
+ taskId: task.id,
545
+ agentType: this.name,
546
+ output: merged,
547
+ confidence: 0.8,
548
+ reasoning: `Merged ${insights.length} insight sources`,
549
+ processingTime: Date.now() - startTime,
550
+ };
551
+ }
552
+ async generateRecommendations(task, startTime) {
553
+ const { analysisResults, context: _context } = task.input;
554
+ // If no analysisResults provided, try to extract from context (for chaining)
555
+ let analysis = analysisResults;
556
+ if (!analysis && task.context) {
557
+ // Extract analysis data from previous agent output
558
+ if (task.context.patterns || task.context.trends) {
559
+ analysis = {
560
+ highPriorityCount: task.context.patterns?.priorityDistribution?.high || 0,
561
+ contextSize: task.context.itemCount || 0,
562
+ staleTasks: false,
563
+ };
564
+ }
565
+ }
566
+ const recommendations = {
567
+ immediate: this.getImmediateRecommendations(analysis),
568
+ shortTerm: this.getShortTermRecommendations(analysis),
569
+ longTerm: this.getLongTermRecommendations(analysis),
570
+ warnings: this.getWarnings(analysis),
571
+ };
572
+ return {
573
+ taskId: task.id,
574
+ agentType: this.name,
575
+ output: recommendations,
576
+ confidence: 0.75,
577
+ reasoning: 'Generated recommendations based on analysis results',
578
+ processingTime: Date.now() - startTime,
579
+ };
580
+ }
581
+ // Helper methods
582
+ createOverview(items) {
583
+ const totalItems = items.length;
584
+ const highPriority = items.filter(i => i.priority === 'high').length;
585
+ const categories = [...new Set(items.map(i => i.category))].filter(Boolean);
586
+ return `${totalItems} context items across ${categories.length} categories, with ${highPriority} high-priority items`;
587
+ }
588
+ summarizeByCategory(items) {
589
+ const byCategory = {};
590
+ for (const item of items) {
591
+ const category = item.category || 'uncategorized';
592
+ if (!byCategory[category]) {
593
+ byCategory[category] = {
594
+ count: 0,
595
+ items: [],
596
+ priorities: { high: 0, normal: 0, low: 0 },
597
+ };
598
+ }
599
+ byCategory[category].count++;
600
+ byCategory[category].items.push({
601
+ key: item.key,
602
+ value: item.value.substring(0, 100) + (item.value.length > 100 ? '...' : ''),
603
+ });
604
+ byCategory[category].priorities[item.priority || 'normal']++;
605
+ }
606
+ return byCategory;
607
+ }
608
+ extractKeyDecisions(items) {
609
+ return items
610
+ .filter(i => i.category === 'decision' && i.priority === 'high')
611
+ .map(i => `${i.key}: ${i.value}`)
612
+ .slice(0, 5);
613
+ }
614
+ extractCurrentTasks(items) {
615
+ return items
616
+ .filter(i => i.category === 'task')
617
+ .sort((a, b) => {
618
+ const priorityOrder = { high: 0, normal: 1, low: 2 };
619
+ return ((priorityOrder[a.priority] || 1) -
620
+ (priorityOrder[b.priority] || 1));
621
+ })
622
+ .map(i => `[${i.priority}] ${i.key}: ${i.value}`)
623
+ .slice(0, 10);
624
+ }
625
+ extractRecentProgress(items) {
626
+ const oneDayAgo = new Date();
627
+ oneDayAgo.setDate(oneDayAgo.getDate() - 1);
628
+ return items
629
+ .filter(i => i.category === 'progress' && new Date(i.created_at) > oneDayAgo)
630
+ .map(i => i.value)
631
+ .slice(0, 5);
632
+ }
633
+ formatSummary(summary, maxLength) {
634
+ let formatted = `# Context Summary\n\n${summary.overview}\n\n`;
635
+ if (summary.keyDecisions.length > 0) {
636
+ formatted += `## Key Decisions\n${summary.keyDecisions.map((d) => `- ${d}`).join('\n')}\n\n`;
637
+ }
638
+ if (summary.currentTasks.length > 0) {
639
+ formatted += `## Current Tasks\n${summary.currentTasks.map((t) => `- ${t}`).join('\n')}\n\n`;
640
+ }
641
+ if (summary.recentProgress.length > 0) {
642
+ formatted += `## Recent Progress\n${summary.recentProgress.map((p) => `- ${p}`).join('\n')}\n\n`;
643
+ }
644
+ // Trim if needed
645
+ if (formatted.length > maxLength) {
646
+ formatted = formatted.substring(0, maxLength - 3) + '...';
647
+ }
648
+ return formatted;
649
+ }
650
+ mergePatterns(insights) {
651
+ const merged = {};
652
+ for (const insight of insights) {
653
+ if (insight.patterns) {
654
+ Object.entries(insight.patterns).forEach(([key, value]) => {
655
+ if (!merged[key]) {
656
+ merged[key] = value;
657
+ }
658
+ else if (Array.isArray(value)) {
659
+ merged[key] = [...new Set([...merged[key], ...value])];
660
+ }
661
+ });
662
+ }
663
+ }
664
+ return merged;
665
+ }
666
+ mergeRelationships(insights) {
667
+ const entities = new Map();
668
+ const relationships = new Map();
669
+ for (const insight of insights) {
670
+ if (insight.relationships) {
671
+ // Merge logic for relationships
672
+ }
673
+ }
674
+ return { entities: entities.size, relationships: relationships.size };
675
+ }
676
+ mergeTrends(insights) {
677
+ const trends = [];
678
+ for (const insight of insights) {
679
+ if (insight.trends) {
680
+ trends.push(insight.trends);
681
+ }
682
+ }
683
+ return trends;
684
+ }
685
+ identifyThemes(insights) {
686
+ const themes = new Set();
687
+ // Extract common themes from insights
688
+ for (const insight of insights) {
689
+ if (insight &&
690
+ typeof insight === 'object' &&
691
+ insight.themes &&
692
+ Array.isArray(insight.themes)) {
693
+ insight.themes.forEach((theme) => themes.add(theme));
694
+ }
695
+ }
696
+ return Array.from(themes);
697
+ }
698
+ identifyConflicts(_insights) {
699
+ // Identify conflicting information between insights
700
+ return [];
701
+ }
702
+ getImmediateRecommendations(analysis) {
703
+ const recommendations = [];
704
+ if (analysis && analysis.highPriorityCount > 5) {
705
+ recommendations.push('Consider breaking down high-priority tasks into smaller items');
706
+ }
707
+ if (analysis && analysis.staleTasks) {
708
+ recommendations.push("Review and update stale tasks that haven't been touched recently");
709
+ }
710
+ return recommendations;
711
+ }
712
+ getShortTermRecommendations(_analysis) {
713
+ return ['Create checkpoints before major changes', "Document key decisions as they're made"];
714
+ }
715
+ getLongTermRecommendations(_analysis) {
716
+ return [
717
+ 'Establish regular review cycles for context cleanup',
718
+ 'Consider archiving old sessions',
719
+ ];
720
+ }
721
+ getWarnings(analysis) {
722
+ const warnings = [];
723
+ if (analysis && analysis.contextSize > 1000) {
724
+ warnings.push('Context size is large - consider compaction');
725
+ }
726
+ return warnings;
727
+ }
728
+ }
729
+ exports.SynthesizerAgent = SynthesizerAgent;
730
+ // Agent Coordinator - Manages multiple agents
731
+ class AgentCoordinator {
732
+ agents = new Map();
733
+ taskQueue = [];
734
+ results = new Map();
735
+ registerAgent(agent) {
736
+ this.agents.set(agent.getName(), agent);
737
+ }
738
+ async delegate(task) {
739
+ // Find suitable agents
740
+ const suitableAgents = Array.from(this.agents.values()).filter(agent => agent.canHandle(task));
741
+ if (suitableAgents.length === 0) {
742
+ return [
743
+ {
744
+ taskId: task.id,
745
+ agentType: 'coordinator',
746
+ output: { error: 'No suitable agent found for task' },
747
+ confidence: 0,
748
+ processingTime: 0,
749
+ },
750
+ ];
751
+ }
752
+ // Process with all suitable agents in parallel
753
+ const results = await Promise.all(suitableAgents.map(agent => agent.process(task)));
754
+ // Store results
755
+ results.forEach(result => {
756
+ this.results.set(`${task.id}-${result.agentType}`, result);
757
+ });
758
+ return results;
759
+ }
760
+ async processChain(tasks) {
761
+ const chainResults = [];
762
+ let previousOutput = null;
763
+ for (const task of tasks) {
764
+ // Pass previous output as context
765
+ if (previousOutput) {
766
+ task.context = previousOutput;
767
+ }
768
+ const results = await this.delegate(task);
769
+ chainResults.push(...results);
770
+ // Use the highest confidence result as input for next task
771
+ previousOutput = results.reduce((best, current) => current.confidence > best.confidence ? current : best).output;
772
+ }
773
+ return chainResults;
774
+ }
775
+ getBestResult(taskId) {
776
+ const taskResults = Array.from(this.results.entries())
777
+ .filter(([key]) => key.startsWith(taskId))
778
+ .map(([, result]) => result);
779
+ if (taskResults.length === 0)
780
+ return null;
781
+ return taskResults.reduce((best, current) => current.confidence > best.confidence ? current : best);
782
+ }
783
+ getAgentCapabilities() {
784
+ const capabilities = {};
785
+ this.agents.forEach((agent, name) => {
786
+ capabilities[name] = agent.capabilities;
787
+ });
788
+ return capabilities;
789
+ }
790
+ }
791
+ exports.AgentCoordinator = AgentCoordinator;