@danielsimonjr/memory-mcp 0.47.1 → 9.8.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.
Files changed (207) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +2000 -194
  3. package/dist/__tests__/file-path.test.js +5 -5
  4. package/dist/__tests__/knowledge-graph.test.js +3 -8
  5. package/dist/core/EntityManager.d.ts +266 -0
  6. package/dist/core/EntityManager.d.ts.map +1 -0
  7. package/dist/core/EntityManager.js +85 -133
  8. package/dist/core/GraphEventEmitter.d.ts +202 -0
  9. package/dist/core/GraphEventEmitter.d.ts.map +1 -0
  10. package/dist/core/GraphEventEmitter.js +346 -0
  11. package/dist/core/GraphStorage.d.ts +395 -0
  12. package/dist/core/GraphStorage.d.ts.map +1 -0
  13. package/dist/core/GraphStorage.js +643 -31
  14. package/dist/core/GraphTraversal.d.ts +141 -0
  15. package/dist/core/GraphTraversal.d.ts.map +1 -0
  16. package/dist/core/GraphTraversal.js +573 -0
  17. package/dist/core/HierarchyManager.d.ts +111 -0
  18. package/dist/core/HierarchyManager.d.ts.map +1 -0
  19. package/dist/{features → core}/HierarchyManager.js +14 -9
  20. package/dist/core/ManagerContext.d.ts +72 -0
  21. package/dist/core/ManagerContext.d.ts.map +1 -0
  22. package/dist/core/ManagerContext.js +118 -0
  23. package/dist/core/ObservationManager.d.ts +85 -0
  24. package/dist/core/ObservationManager.d.ts.map +1 -0
  25. package/dist/core/ObservationManager.js +51 -57
  26. package/dist/core/RelationManager.d.ts +131 -0
  27. package/dist/core/RelationManager.d.ts.map +1 -0
  28. package/dist/core/RelationManager.js +31 -7
  29. package/dist/core/SQLiteStorage.d.ts +354 -0
  30. package/dist/core/SQLiteStorage.d.ts.map +1 -0
  31. package/dist/core/SQLiteStorage.js +917 -0
  32. package/dist/core/StorageFactory.d.ts +45 -0
  33. package/dist/core/StorageFactory.d.ts.map +1 -0
  34. package/dist/core/StorageFactory.js +64 -0
  35. package/dist/core/TransactionManager.d.ts +464 -0
  36. package/dist/core/TransactionManager.d.ts.map +1 -0
  37. package/dist/core/TransactionManager.js +490 -13
  38. package/dist/core/index.d.ts +17 -0
  39. package/dist/core/index.d.ts.map +1 -0
  40. package/dist/core/index.js +12 -2
  41. package/dist/features/AnalyticsManager.d.ts +44 -0
  42. package/dist/features/AnalyticsManager.d.ts.map +1 -0
  43. package/dist/features/AnalyticsManager.js +14 -13
  44. package/dist/features/ArchiveManager.d.ts +133 -0
  45. package/dist/features/ArchiveManager.d.ts.map +1 -0
  46. package/dist/features/ArchiveManager.js +221 -14
  47. package/dist/features/CompressionManager.d.ts +117 -0
  48. package/dist/features/CompressionManager.d.ts.map +1 -0
  49. package/dist/features/CompressionManager.js +189 -20
  50. package/dist/features/IOManager.d.ts +225 -0
  51. package/dist/features/IOManager.d.ts.map +1 -0
  52. package/dist/features/IOManager.js +1041 -0
  53. package/dist/features/StreamingExporter.d.ts +123 -0
  54. package/dist/features/StreamingExporter.d.ts.map +1 -0
  55. package/dist/features/StreamingExporter.js +203 -0
  56. package/dist/features/TagManager.d.ts +147 -0
  57. package/dist/features/TagManager.d.ts.map +1 -0
  58. package/dist/features/index.d.ts +12 -0
  59. package/dist/features/index.d.ts.map +1 -0
  60. package/dist/features/index.js +5 -6
  61. package/dist/index.d.ts +9 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +12 -45
  64. package/dist/memory.jsonl +1 -18
  65. package/dist/search/BasicSearch.d.ts +51 -0
  66. package/dist/search/BasicSearch.d.ts.map +1 -0
  67. package/dist/search/BasicSearch.js +9 -3
  68. package/dist/search/BooleanSearch.d.ts +98 -0
  69. package/dist/search/BooleanSearch.d.ts.map +1 -0
  70. package/dist/search/BooleanSearch.js +156 -9
  71. package/dist/search/EmbeddingService.d.ts +178 -0
  72. package/dist/search/EmbeddingService.d.ts.map +1 -0
  73. package/dist/search/EmbeddingService.js +358 -0
  74. package/dist/search/FuzzySearch.d.ts +118 -0
  75. package/dist/search/FuzzySearch.d.ts.map +1 -0
  76. package/dist/search/FuzzySearch.js +241 -25
  77. package/dist/search/QueryCostEstimator.d.ts +111 -0
  78. package/dist/search/QueryCostEstimator.d.ts.map +1 -0
  79. package/dist/search/QueryCostEstimator.js +355 -0
  80. package/dist/search/RankedSearch.d.ts +71 -0
  81. package/dist/search/RankedSearch.d.ts.map +1 -0
  82. package/dist/search/RankedSearch.js +54 -6
  83. package/dist/search/SavedSearchManager.d.ts +79 -0
  84. package/dist/search/SavedSearchManager.d.ts.map +1 -0
  85. package/dist/search/SearchFilterChain.d.ts +120 -0
  86. package/dist/search/SearchFilterChain.d.ts.map +1 -0
  87. package/dist/search/SearchFilterChain.js +2 -4
  88. package/dist/search/SearchManager.d.ts +326 -0
  89. package/dist/search/SearchManager.d.ts.map +1 -0
  90. package/dist/search/SearchManager.js +148 -0
  91. package/dist/search/SearchSuggestions.d.ts +27 -0
  92. package/dist/search/SearchSuggestions.d.ts.map +1 -0
  93. package/dist/search/SearchSuggestions.js +1 -1
  94. package/dist/search/SemanticSearch.d.ts +149 -0
  95. package/dist/search/SemanticSearch.d.ts.map +1 -0
  96. package/dist/search/SemanticSearch.js +323 -0
  97. package/dist/search/TFIDFEventSync.d.ts +85 -0
  98. package/dist/search/TFIDFEventSync.d.ts.map +1 -0
  99. package/dist/search/TFIDFEventSync.js +133 -0
  100. package/dist/search/TFIDFIndexManager.d.ts +151 -0
  101. package/dist/search/TFIDFIndexManager.d.ts.map +1 -0
  102. package/dist/search/TFIDFIndexManager.js +232 -17
  103. package/dist/search/VectorStore.d.ts +235 -0
  104. package/dist/search/VectorStore.d.ts.map +1 -0
  105. package/dist/search/VectorStore.js +311 -0
  106. package/dist/search/index.d.ts +21 -0
  107. package/dist/search/index.d.ts.map +1 -0
  108. package/dist/search/index.js +12 -0
  109. package/dist/server/MCPServer.d.ts +21 -0
  110. package/dist/server/MCPServer.d.ts.map +1 -0
  111. package/dist/server/MCPServer.js +4 -4
  112. package/dist/server/responseCompressor.d.ts +94 -0
  113. package/dist/server/responseCompressor.d.ts.map +1 -0
  114. package/dist/server/responseCompressor.js +127 -0
  115. package/dist/server/toolDefinitions.d.ts +27 -0
  116. package/dist/server/toolDefinitions.d.ts.map +1 -0
  117. package/dist/server/toolDefinitions.js +189 -18
  118. package/dist/server/toolHandlers.d.ts +41 -0
  119. package/dist/server/toolHandlers.d.ts.map +1 -0
  120. package/dist/server/toolHandlers.js +467 -75
  121. package/dist/types/index.d.ts +13 -0
  122. package/dist/types/index.d.ts.map +1 -0
  123. package/dist/types/index.js +1 -1
  124. package/dist/types/types.d.ts +1654 -0
  125. package/dist/types/types.d.ts.map +1 -0
  126. package/dist/types/types.js +9 -0
  127. package/dist/utils/compressedCache.d.ts +192 -0
  128. package/dist/utils/compressedCache.d.ts.map +1 -0
  129. package/dist/utils/compressedCache.js +309 -0
  130. package/dist/utils/compressionUtil.d.ts +214 -0
  131. package/dist/utils/compressionUtil.d.ts.map +1 -0
  132. package/dist/utils/compressionUtil.js +247 -0
  133. package/dist/utils/constants.d.ts +245 -0
  134. package/dist/utils/constants.d.ts.map +1 -0
  135. package/dist/utils/constants.js +124 -0
  136. package/dist/utils/entityUtils.d.ts +321 -0
  137. package/dist/utils/entityUtils.d.ts.map +1 -0
  138. package/dist/utils/entityUtils.js +434 -4
  139. package/dist/utils/errors.d.ts +95 -0
  140. package/dist/utils/errors.d.ts.map +1 -0
  141. package/dist/utils/errors.js +24 -0
  142. package/dist/utils/formatters.d.ts +145 -0
  143. package/dist/utils/formatters.d.ts.map +1 -0
  144. package/dist/utils/{paginationUtils.js → formatters.js} +54 -3
  145. package/dist/utils/index.d.ts +23 -0
  146. package/dist/utils/index.d.ts.map +1 -0
  147. package/dist/utils/index.js +69 -31
  148. package/dist/utils/indexes.d.ts +270 -0
  149. package/dist/utils/indexes.d.ts.map +1 -0
  150. package/dist/utils/indexes.js +526 -0
  151. package/dist/utils/logger.d.ts +24 -0
  152. package/dist/utils/logger.d.ts.map +1 -0
  153. package/dist/utils/operationUtils.d.ts +124 -0
  154. package/dist/utils/operationUtils.d.ts.map +1 -0
  155. package/dist/utils/operationUtils.js +175 -0
  156. package/dist/utils/parallelUtils.d.ts +72 -0
  157. package/dist/utils/parallelUtils.d.ts.map +1 -0
  158. package/dist/utils/parallelUtils.js +169 -0
  159. package/dist/utils/schemas.d.ts +374 -0
  160. package/dist/utils/schemas.d.ts.map +1 -0
  161. package/dist/utils/schemas.js +302 -2
  162. package/dist/utils/searchAlgorithms.d.ts +99 -0
  163. package/dist/utils/searchAlgorithms.d.ts.map +1 -0
  164. package/dist/utils/searchAlgorithms.js +167 -0
  165. package/dist/utils/searchCache.d.ts +108 -0
  166. package/dist/utils/searchCache.d.ts.map +1 -0
  167. package/dist/utils/taskScheduler.d.ts +290 -0
  168. package/dist/utils/taskScheduler.d.ts.map +1 -0
  169. package/dist/utils/taskScheduler.js +466 -0
  170. package/dist/workers/index.d.ts +12 -0
  171. package/dist/workers/index.d.ts.map +1 -0
  172. package/dist/workers/index.js +9 -0
  173. package/dist/workers/levenshteinWorker.d.ts +60 -0
  174. package/dist/workers/levenshteinWorker.d.ts.map +1 -0
  175. package/dist/workers/levenshteinWorker.js +98 -0
  176. package/package.json +17 -4
  177. package/dist/__tests__/edge-cases/edge-cases.test.js +0 -406
  178. package/dist/__tests__/integration/workflows.test.js +0 -449
  179. package/dist/__tests__/performance/benchmarks.test.js +0 -413
  180. package/dist/__tests__/unit/core/EntityManager.test.js +0 -334
  181. package/dist/__tests__/unit/core/GraphStorage.test.js +0 -205
  182. package/dist/__tests__/unit/core/RelationManager.test.js +0 -274
  183. package/dist/__tests__/unit/features/CompressionManager.test.js +0 -350
  184. package/dist/__tests__/unit/search/BasicSearch.test.js +0 -311
  185. package/dist/__tests__/unit/search/BooleanSearch.test.js +0 -432
  186. package/dist/__tests__/unit/search/FuzzySearch.test.js +0 -448
  187. package/dist/__tests__/unit/search/RankedSearch.test.js +0 -379
  188. package/dist/__tests__/unit/utils/levenshtein.test.js +0 -77
  189. package/dist/core/KnowledgeGraphManager.js +0 -423
  190. package/dist/features/BackupManager.js +0 -311
  191. package/dist/features/ExportManager.js +0 -305
  192. package/dist/features/ImportExportManager.js +0 -50
  193. package/dist/features/ImportManager.js +0 -328
  194. package/dist/types/analytics.types.js +0 -6
  195. package/dist/types/entity.types.js +0 -7
  196. package/dist/types/import-export.types.js +0 -7
  197. package/dist/types/search.types.js +0 -7
  198. package/dist/types/tag.types.js +0 -6
  199. package/dist/utils/dateUtils.js +0 -89
  200. package/dist/utils/filterUtils.js +0 -155
  201. package/dist/utils/levenshtein.js +0 -62
  202. package/dist/utils/pathUtils.js +0 -115
  203. package/dist/utils/responseFormatter.js +0 -55
  204. package/dist/utils/tagUtils.js +0 -107
  205. package/dist/utils/tfidf.js +0 -90
  206. package/dist/utils/validationHelper.js +0 -99
  207. package/dist/utils/validationUtils.js +0 -109
@@ -1,413 +0,0 @@
1
- /**
2
- * Performance Benchmarks
3
- *
4
- * Tests for performance budgets and benchmarks across all operations.
5
- * Uses relative performance testing to avoid flaky failures on slow machines.
6
- *
7
- * Strategy: Run a baseline operation first, then verify that scaled operations
8
- * complete within reasonable multiples of the baseline time.
9
- */
10
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
11
- import { GraphStorage } from '../../core/GraphStorage.js';
12
- import { EntityManager } from '../../core/EntityManager.js';
13
- import { RelationManager } from '../../core/RelationManager.js';
14
- import { CompressionManager } from '../../features/CompressionManager.js';
15
- import { BasicSearch } from '../../search/BasicSearch.js';
16
- import { RankedSearch } from '../../search/RankedSearch.js';
17
- import { BooleanSearch } from '../../search/BooleanSearch.js';
18
- import { FuzzySearch } from '../../search/FuzzySearch.js';
19
- import { promises as fs } from 'fs';
20
- import { join } from 'path';
21
- import { tmpdir } from 'os';
22
- /**
23
- * Performance test configuration.
24
- * Uses generous multipliers to avoid flaky tests while still catching regressions.
25
- */
26
- const PERF_CONFIG = {
27
- // Maximum allowed time for any single operation (prevents infinite hangs)
28
- MAX_ABSOLUTE_TIME_MS: 30000,
29
- // Multiplier for scaled operations (e.g., 100 entities should take < 20x the time of 10)
30
- SCALE_MULTIPLIER: 25,
31
- // Multiplier for complex operations vs simple ones
32
- COMPLEXITY_MULTIPLIER: 15,
33
- };
34
- describe('Performance Benchmarks', () => {
35
- let storage;
36
- let entityManager;
37
- let relationManager;
38
- let compressionManager;
39
- let basicSearch;
40
- let rankedSearch;
41
- let booleanSearch;
42
- let fuzzySearch;
43
- let testDir;
44
- let testFilePath;
45
- beforeEach(async () => {
46
- testDir = join(tmpdir(), `perf-test-${Date.now()}-${Math.random()}`);
47
- await fs.mkdir(testDir, { recursive: true });
48
- testFilePath = join(testDir, 'test-graph.jsonl');
49
- storage = new GraphStorage(testFilePath);
50
- entityManager = new EntityManager(storage);
51
- relationManager = new RelationManager(storage);
52
- compressionManager = new CompressionManager(storage);
53
- basicSearch = new BasicSearch(storage);
54
- rankedSearch = new RankedSearch(storage);
55
- booleanSearch = new BooleanSearch(storage);
56
- fuzzySearch = new FuzzySearch(storage);
57
- });
58
- afterEach(async () => {
59
- try {
60
- await fs.rm(testDir, { recursive: true, force: true });
61
- }
62
- catch {
63
- // Ignore cleanup errors
64
- }
65
- });
66
- describe('Entity Creation Performance', () => {
67
- it('should scale linearly when creating entities', async () => {
68
- // Baseline: create 10 entities
69
- const smallBatch = Array.from({ length: 10 }, (_, i) => ({
70
- name: `SmallEntity${i}`,
71
- entityType: 'test',
72
- observations: [`Observation ${i}`],
73
- }));
74
- const startSmall = Date.now();
75
- await entityManager.createEntities(smallBatch);
76
- const smallDuration = Date.now() - startSmall;
77
- // Scaled: create 100 entities (10x more)
78
- const largeBatch = Array.from({ length: 100 }, (_, i) => ({
79
- name: `LargeEntity${i}`,
80
- entityType: 'test',
81
- observations: [`Observation ${i}`],
82
- importance: (i % 10) + 1,
83
- }));
84
- const startLarge = Date.now();
85
- await entityManager.createEntities(largeBatch);
86
- const largeDuration = Date.now() - startLarge;
87
- // Large batch should complete within reasonable multiple of small batch
88
- // Allow generous multiplier since we're comparing 10x the work
89
- expect(largeDuration).toBeLessThan(Math.max(smallDuration * PERF_CONFIG.SCALE_MULTIPLIER, PERF_CONFIG.MAX_ABSOLUTE_TIME_MS));
90
- });
91
- it('should handle 1000 entities within absolute time limit', async () => {
92
- const entities = Array.from({ length: 1000 }, (_, i) => ({
93
- name: `Entity${i}`,
94
- entityType: 'test',
95
- observations: [`Observation ${i}`],
96
- }));
97
- const startTime = Date.now();
98
- await entityManager.createEntities(entities);
99
- const duration = Date.now() - startTime;
100
- // Just ensure it completes in reasonable time (no specific threshold)
101
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
102
- });
103
- it('should batch update entities efficiently', async () => {
104
- // Create entities first
105
- const entities = Array.from({ length: 100 }, (_, i) => ({
106
- name: `Entity${i}`,
107
- entityType: 'test',
108
- observations: [`Observation ${i}`],
109
- }));
110
- await entityManager.createEntities(entities);
111
- // Single update baseline
112
- const startSingle = Date.now();
113
- await entityManager.updateEntity('Entity0', { importance: 5 });
114
- const singleDuration = Date.now() - startSingle;
115
- // Batch update
116
- const updates = Array.from({ length: 100 }, (_, i) => ({
117
- name: `Entity${i}`,
118
- updates: { importance: 5 },
119
- }));
120
- const startBatch = Date.now();
121
- await entityManager.batchUpdate(updates);
122
- const batchDuration = Date.now() - startBatch;
123
- // Batch of 100 should be faster than 100x single updates
124
- // (demonstrates batching efficiency)
125
- expect(batchDuration).toBeLessThan(Math.max(singleDuration * 100, PERF_CONFIG.MAX_ABSOLUTE_TIME_MS));
126
- });
127
- });
128
- describe('Relation Creation Performance', () => {
129
- it('should scale reasonably when creating relations', async () => {
130
- // Create entities first
131
- const entities = Array.from({ length: 100 }, (_, i) => ({
132
- name: `Entity${i}`,
133
- entityType: 'test',
134
- observations: ['Test'],
135
- }));
136
- await entityManager.createEntities(entities);
137
- // Small batch: 10 relations
138
- const smallRelations = Array.from({ length: 10 }, (_, i) => ({
139
- from: `Entity${i}`,
140
- to: `Entity${i + 1}`,
141
- relationType: 'connects',
142
- }));
143
- const startSmall = Date.now();
144
- await relationManager.createRelations(smallRelations);
145
- const smallDuration = Date.now() - startSmall;
146
- // Large batch: 100 relations
147
- const largeRelations = Array.from({ length: 100 }, (_, i) => ({
148
- from: `Entity${i % 100}`,
149
- to: `Entity${(i + 10) % 100}`,
150
- relationType: 'links',
151
- }));
152
- const startLarge = Date.now();
153
- await relationManager.createRelations(largeRelations);
154
- const largeDuration = Date.now() - startLarge;
155
- expect(largeDuration).toBeLessThan(Math.max(smallDuration * PERF_CONFIG.SCALE_MULTIPLIER, PERF_CONFIG.MAX_ABSOLUTE_TIME_MS));
156
- });
157
- });
158
- describe('Search Performance', () => {
159
- beforeEach(async () => {
160
- // Create a moderate-sized graph
161
- const entities = Array.from({ length: 500 }, (_, i) => ({
162
- name: `Entity${i}`,
163
- entityType: i % 5 === 0 ? 'person' : 'project',
164
- observations: [`This is observation ${i} with some searchable text`],
165
- tags: i % 3 === 0 ? ['tagged', 'test'] : undefined,
166
- importance: (i % 10) + 1,
167
- }));
168
- await entityManager.createEntities(entities);
169
- });
170
- it('should perform basic search within time limit', async () => {
171
- const startTime = Date.now();
172
- const results = await basicSearch.searchNodes('Entity');
173
- const duration = Date.now() - startTime;
174
- expect(results.entities.length).toBeGreaterThan(0);
175
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
176
- });
177
- it('should perform ranked search within time limit', async () => {
178
- const startTime = Date.now();
179
- // Use "person" which only appears in 20% of entities (entityType)
180
- // This ensures TF-IDF returns non-zero scores (IDF > 0 for rare terms)
181
- const results = await rankedSearch.searchNodesRanked('person');
182
- const duration = Date.now() - startTime;
183
- // searchNodesRanked returns SearchResult[] directly (not KnowledgeGraph)
184
- expect(results.length).toBeGreaterThan(0);
185
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
186
- });
187
- it('should perform boolean search within time limit', async () => {
188
- const startTime = Date.now();
189
- const results = await booleanSearch.booleanSearch('person AND observation');
190
- const duration = Date.now() - startTime;
191
- expect(results.entities.length).toBeGreaterThan(0);
192
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
193
- });
194
- it('should perform fuzzy search within time limit', async () => {
195
- const startTime = Date.now();
196
- const results = await fuzzySearch.fuzzySearch('Entty', 0.7);
197
- const duration = Date.now() - startTime;
198
- expect(results.entities.length).toBeGreaterThan(0);
199
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
200
- });
201
- it('should have ranked search complete within reasonable multiple of basic search', async () => {
202
- // Basic search baseline
203
- const startBasic = Date.now();
204
- await basicSearch.searchNodes('observation');
205
- const basicDuration = Date.now() - startBasic;
206
- // Ranked search (more complex)
207
- const startRanked = Date.now();
208
- await rankedSearch.searchNodesRanked('observation');
209
- const rankedDuration = Date.now() - startRanked;
210
- // Ranked search may be slower but should be within reasonable bounds
211
- expect(rankedDuration).toBeLessThan(Math.max(basicDuration * PERF_CONFIG.COMPLEXITY_MULTIPLIER, PERF_CONFIG.MAX_ABSOLUTE_TIME_MS));
212
- });
213
- });
214
- describe('Compression Performance', () => {
215
- it('should scale reasonably for duplicate detection', async () => {
216
- // Small set: 50 entities
217
- const smallEntities = Array.from({ length: 50 }, (_, i) => ({
218
- name: `SmallEntity${i}`,
219
- entityType: 'person',
220
- observations: [i % 10 === 0 ? 'Duplicate observation' : `Unique observation ${i}`],
221
- }));
222
- await entityManager.createEntities(smallEntities);
223
- const startSmall = Date.now();
224
- await compressionManager.findDuplicates(0.8);
225
- const smallDuration = Date.now() - startSmall;
226
- // Larger set: 200 entities (4x more, but O(n²) comparison so expect ~16x time)
227
- const largeEntities = Array.from({ length: 200 }, (_, i) => ({
228
- name: `LargeEntity${i}`,
229
- entityType: 'person',
230
- observations: [i % 20 === 0 ? 'Duplicate observation' : `Unique observation ${i}`],
231
- }));
232
- await entityManager.createEntities(largeEntities);
233
- const startLarge = Date.now();
234
- await compressionManager.findDuplicates(0.8);
235
- const largeDuration = Date.now() - startLarge;
236
- // Allow generous multiplier for O(n²) algorithm
237
- expect(largeDuration).toBeLessThan(Math.max(smallDuration * PERF_CONFIG.SCALE_MULTIPLIER * 2, PERF_CONFIG.MAX_ABSOLUTE_TIME_MS));
238
- });
239
- it('should compress graph within time limit', async () => {
240
- const entities = Array.from({ length: 100 }, (_, i) => ({
241
- name: `Entity${i}`,
242
- entityType: 'person',
243
- observations: [i % 10 === 0 ? 'Similar observation' : `Observation ${i}`],
244
- }));
245
- await entityManager.createEntities(entities);
246
- const startTime = Date.now();
247
- await compressionManager.compressGraph(0.8, false);
248
- const duration = Date.now() - startTime;
249
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
250
- });
251
- });
252
- describe('Graph Loading/Saving Performance', () => {
253
- it('should load and save graphs efficiently', async () => {
254
- // Create entities
255
- const entities = Array.from({ length: 500 }, (_, i) => ({
256
- name: `Entity${i}`,
257
- entityType: 'test',
258
- observations: [`Observation ${i}`],
259
- }));
260
- await entityManager.createEntities(entities);
261
- // Measure load time
262
- const startLoad = Date.now();
263
- const graph = await storage.loadGraph();
264
- const loadDuration = Date.now() - startLoad;
265
- expect(graph.entities.length).toBe(500);
266
- expect(loadDuration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
267
- // Measure save time
268
- const startSave = Date.now();
269
- await storage.saveGraph(graph);
270
- const saveDuration = Date.now() - startSave;
271
- expect(saveDuration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
272
- });
273
- it('should scale load/save times reasonably with graph size', async () => {
274
- // Small graph: 100 entities
275
- const smallEntities = Array.from({ length: 100 }, (_, i) => ({
276
- name: `SmallEntity${i}`,
277
- entityType: 'test',
278
- observations: [`Observation ${i}`],
279
- }));
280
- await entityManager.createEntities(smallEntities);
281
- const startSmallLoad = Date.now();
282
- await storage.loadGraph();
283
- const smallLoadDuration = Date.now() - startSmallLoad;
284
- // Large graph: 1000 entities (10x more)
285
- const largeEntities = Array.from({ length: 1000 }, (_, i) => ({
286
- name: `LargeEntity${i}`,
287
- entityType: 'test',
288
- observations: [`Observation ${i}`],
289
- }));
290
- await entityManager.createEntities(largeEntities);
291
- const startLargeLoad = Date.now();
292
- await storage.loadGraph();
293
- const largeLoadDuration = Date.now() - startLargeLoad;
294
- // 10x data should not take more than 25x time (allows for overhead)
295
- expect(largeLoadDuration).toBeLessThan(Math.max(smallLoadDuration * PERF_CONFIG.SCALE_MULTIPLIER, PERF_CONFIG.MAX_ABSOLUTE_TIME_MS));
296
- });
297
- });
298
- describe('Complex Workflow Performance', () => {
299
- it('should complete full CRUD workflow within time limit', async () => {
300
- const startTime = Date.now();
301
- // Create
302
- await entityManager.createEntities([
303
- { name: 'Entity1', entityType: 'test', observations: ['Test 1'] },
304
- { name: 'Entity2', entityType: 'test', observations: ['Test 2'] },
305
- ]);
306
- // Read
307
- await entityManager.getEntity('Entity1');
308
- // Update
309
- await entityManager.updateEntity('Entity1', { importance: 5 });
310
- // Search
311
- await basicSearch.searchNodes('Entity');
312
- // Delete
313
- await entityManager.deleteEntities(['Entity2']);
314
- const duration = Date.now() - startTime;
315
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
316
- });
317
- it('should handle bulk workflow efficiently', async () => {
318
- const startTime = Date.now();
319
- // Bulk create
320
- const entities = Array.from({ length: 50 }, (_, i) => ({
321
- name: `Entity${i}`,
322
- entityType: 'test',
323
- observations: [`Observation ${i}`],
324
- }));
325
- await entityManager.createEntities(entities);
326
- // Bulk relate
327
- const relations = Array.from({ length: 50 }, (_, i) => ({
328
- from: `Entity${i}`,
329
- to: `Entity${(i + 1) % 50}`,
330
- relationType: 'connects',
331
- }));
332
- await relationManager.createRelations(relations);
333
- // Search
334
- const results = await basicSearch.searchNodes('Entity');
335
- const duration = Date.now() - startTime;
336
- expect(results.entities.length).toBe(50);
337
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
338
- });
339
- it('should handle complex query workflow efficiently', async () => {
340
- // Setup
341
- const entities = Array.from({ length: 100 }, (_, i) => ({
342
- name: `Entity${i}`,
343
- entityType: i % 2 === 0 ? 'person' : 'project',
344
- observations: [`Observation ${i}`],
345
- tags: i % 3 === 0 ? ['important'] : undefined,
346
- importance: (i % 10) + 1,
347
- }));
348
- await entityManager.createEntities(entities);
349
- const startTime = Date.now();
350
- // Multiple complex queries
351
- await rankedSearch.searchNodesRanked('Observation', ['important'], 5);
352
- await booleanSearch.booleanSearch('person AND (important OR project)');
353
- await fuzzySearch.fuzzySearch('Observatn', 0.7);
354
- const duration = Date.now() - startTime;
355
- expect(duration).toBeLessThan(PERF_CONFIG.MAX_ABSOLUTE_TIME_MS);
356
- });
357
- });
358
- describe('Memory Efficiency', () => {
359
- it('should handle 2000 entities without issues', async () => {
360
- // Create in batches due to 1000 entity limit
361
- const batch1 = Array.from({ length: 1000 }, (_, i) => ({
362
- name: `Entity${i}`,
363
- entityType: 'test',
364
- observations: [`Observation ${i}`],
365
- }));
366
- const batch2 = Array.from({ length: 1000 }, (_, i) => ({
367
- name: `Entity${i + 1000}`,
368
- entityType: 'test',
369
- observations: [`Observation ${i + 1000}`],
370
- }));
371
- await entityManager.createEntities(batch1);
372
- await entityManager.createEntities(batch2);
373
- const graph = await storage.loadGraph();
374
- expect(graph.entities).toHaveLength(2000);
375
- });
376
- it('should handle graph with 5000 total elements (entities + relations)', async () => {
377
- // Create 1000 entities
378
- const entities = Array.from({ length: 1000 }, (_, i) => ({
379
- name: `Entity${i}`,
380
- entityType: 'test',
381
- observations: [`Observation ${i}`],
382
- }));
383
- await entityManager.createEntities(entities);
384
- // Create 4000 relations in batches due to 1000 relation limit
385
- const batch1 = Array.from({ length: 1000 }, (_, i) => ({
386
- from: `Entity${i % 1000}`,
387
- to: `Entity${(i + 1) % 1000}`,
388
- relationType: i % 2 === 0 ? 'connects' : 'relates',
389
- }));
390
- const batch2 = Array.from({ length: 1000 }, (_, i) => ({
391
- from: `Entity${(i + 1) % 1000}`,
392
- to: `Entity${(i + 2) % 1000}`,
393
- relationType: i % 2 === 0 ? 'links' : 'relates_to',
394
- }));
395
- const batch3 = Array.from({ length: 1000 }, (_, i) => ({
396
- from: `Entity${(i + 2) % 1000}`,
397
- to: `Entity${(i + 3) % 1000}`,
398
- relationType: i % 2 === 0 ? 'connects_to' : 'associates',
399
- }));
400
- const batch4 = Array.from({ length: 1000 }, (_, i) => ({
401
- from: `Entity${(i + 3) % 1000}`,
402
- to: `Entity${(i + 4) % 1000}`,
403
- relationType: i % 2 === 0 ? 'joins' : 'interacts',
404
- }));
405
- await relationManager.createRelations(batch1);
406
- await relationManager.createRelations(batch2);
407
- await relationManager.createRelations(batch3);
408
- await relationManager.createRelations(batch4);
409
- const graph = await storage.loadGraph();
410
- expect(graph.entities.length + graph.relations.length).toBe(5000);
411
- });
412
- });
413
- });