@soulcraft/brainy 2.15.0 → 3.0.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.
Files changed (204) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +249 -152
  3. package/dist/api/ConfigAPI.d.ts +67 -0
  4. package/dist/api/ConfigAPI.js +166 -0
  5. package/dist/api/DataAPI.d.ts +123 -0
  6. package/dist/api/DataAPI.js +391 -0
  7. package/dist/api/SecurityAPI.d.ts +50 -0
  8. package/dist/api/SecurityAPI.js +139 -0
  9. package/dist/api/UniversalImportAPI.d.ts +134 -0
  10. package/dist/api/UniversalImportAPI.js +615 -0
  11. package/dist/augmentationManager.js +12 -7
  12. package/dist/augmentationPipeline.d.ts +0 -61
  13. package/dist/augmentationPipeline.js +0 -87
  14. package/dist/augmentationRegistry.d.ts +1 -1
  15. package/dist/augmentationRegistry.js +1 -1
  16. package/dist/augmentations/apiServerAugmentation.d.ts +27 -1
  17. package/dist/augmentations/apiServerAugmentation.js +288 -7
  18. package/dist/augmentations/auditLogAugmentation.d.ts +109 -0
  19. package/dist/augmentations/auditLogAugmentation.js +358 -0
  20. package/dist/augmentations/batchProcessingAugmentation.d.ts +3 -2
  21. package/dist/augmentations/batchProcessingAugmentation.js +123 -22
  22. package/dist/augmentations/brainyAugmentation.d.ts +87 -8
  23. package/dist/augmentations/brainyAugmentation.js +159 -2
  24. package/dist/augmentations/cacheAugmentation.d.ts +6 -5
  25. package/dist/augmentations/cacheAugmentation.js +113 -17
  26. package/dist/augmentations/conduitAugmentations.d.ts +2 -2
  27. package/dist/augmentations/conduitAugmentations.js +2 -2
  28. package/dist/augmentations/configResolver.d.ts +122 -0
  29. package/dist/augmentations/configResolver.js +440 -0
  30. package/dist/augmentations/connectionPoolAugmentation.d.ts +3 -1
  31. package/dist/augmentations/connectionPoolAugmentation.js +37 -12
  32. package/dist/augmentations/defaultAugmentations.d.ts +9 -11
  33. package/dist/augmentations/defaultAugmentations.js +4 -11
  34. package/dist/augmentations/discovery/catalogDiscovery.d.ts +142 -0
  35. package/dist/augmentations/discovery/catalogDiscovery.js +249 -0
  36. package/dist/augmentations/discovery/localDiscovery.d.ts +84 -0
  37. package/dist/augmentations/discovery/localDiscovery.js +246 -0
  38. package/dist/augmentations/discovery/runtimeLoader.d.ts +97 -0
  39. package/dist/augmentations/discovery/runtimeLoader.js +337 -0
  40. package/dist/augmentations/discovery.d.ts +152 -0
  41. package/dist/augmentations/discovery.js +441 -0
  42. package/dist/augmentations/display/intelligentComputation.d.ts +1 -1
  43. package/dist/augmentations/display/intelligentComputation.js +4 -4
  44. package/dist/augmentations/entityRegistryAugmentation.d.ts +3 -1
  45. package/dist/augmentations/entityRegistryAugmentation.js +5 -1
  46. package/dist/augmentations/indexAugmentation.d.ts +3 -3
  47. package/dist/augmentations/indexAugmentation.js +2 -2
  48. package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +22 -6
  49. package/dist/augmentations/intelligentVerbScoringAugmentation.js +106 -23
  50. package/dist/augmentations/manifest.d.ts +176 -0
  51. package/dist/augmentations/manifest.js +8 -0
  52. package/dist/augmentations/marketplace/AugmentationMarketplace.d.ts +168 -0
  53. package/dist/augmentations/marketplace/AugmentationMarketplace.js +329 -0
  54. package/dist/augmentations/marketplace/cli.d.ts +47 -0
  55. package/dist/augmentations/marketplace/cli.js +265 -0
  56. package/dist/augmentations/metricsAugmentation.d.ts +3 -3
  57. package/dist/augmentations/metricsAugmentation.js +2 -2
  58. package/dist/augmentations/monitoringAugmentation.d.ts +3 -3
  59. package/dist/augmentations/monitoringAugmentation.js +2 -2
  60. package/dist/augmentations/neuralImport.d.ts +1 -1
  61. package/dist/augmentations/rateLimitAugmentation.d.ts +82 -0
  62. package/dist/augmentations/rateLimitAugmentation.js +321 -0
  63. package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +2 -2
  64. package/dist/augmentations/requestDeduplicatorAugmentation.js +1 -1
  65. package/dist/augmentations/storageAugmentation.d.ts +1 -1
  66. package/dist/augmentations/storageAugmentation.js +2 -2
  67. package/dist/augmentations/storageAugmentations.d.ts +37 -8
  68. package/dist/augmentations/storageAugmentations.js +204 -15
  69. package/dist/augmentations/synapseAugmentation.d.ts +1 -1
  70. package/dist/augmentations/synapseAugmentation.js +35 -16
  71. package/dist/augmentations/typeMatching/intelligentTypeMatcher.d.ts +39 -59
  72. package/dist/augmentations/typeMatching/intelligentTypeMatcher.js +103 -389
  73. package/dist/augmentations/universalDisplayAugmentation.d.ts +2 -2
  74. package/dist/augmentations/universalDisplayAugmentation.js +2 -2
  75. package/dist/brainy-unified.d.ts +106 -0
  76. package/dist/brainy-unified.js +327 -0
  77. package/dist/brainy.d.ts +273 -0
  78. package/dist/brainy.js +1181 -0
  79. package/dist/brainyData.d.ts +29 -72
  80. package/dist/brainyData.js +350 -304
  81. package/dist/brainyDataV3.d.ts +186 -0
  82. package/dist/brainyDataV3.js +337 -0
  83. package/dist/browserFramework.d.ts +6 -6
  84. package/dist/browserFramework.js +11 -8
  85. package/dist/browserFramework.minimal.d.ts +5 -5
  86. package/dist/browserFramework.minimal.js +11 -8
  87. package/dist/config/index.d.ts +2 -2
  88. package/dist/config/index.js +3 -3
  89. package/dist/config/modelAutoConfig.d.ts +6 -7
  90. package/dist/config/modelAutoConfig.js +17 -76
  91. package/dist/cortex/backupRestore.d.ts +2 -2
  92. package/dist/cortex/backupRestore.js +85 -27
  93. package/dist/cortex/healthCheck.d.ts +2 -2
  94. package/dist/cortex/neuralImport.d.ts +2 -2
  95. package/dist/cortex/neuralImport.js +18 -13
  96. package/dist/cortex/performanceMonitor.d.ts +2 -2
  97. package/dist/critical/model-guardian.d.ts +4 -0
  98. package/dist/critical/model-guardian.js +31 -11
  99. package/dist/demo.d.ts +4 -4
  100. package/dist/demo.js +7 -7
  101. package/dist/distributed/cacheSync.d.ts +112 -0
  102. package/dist/distributed/cacheSync.js +265 -0
  103. package/dist/distributed/coordinator.d.ts +193 -0
  104. package/dist/distributed/coordinator.js +548 -0
  105. package/dist/distributed/httpTransport.d.ts +120 -0
  106. package/dist/distributed/httpTransport.js +446 -0
  107. package/dist/distributed/index.d.ts +8 -0
  108. package/dist/distributed/index.js +5 -0
  109. package/dist/distributed/networkTransport.d.ts +132 -0
  110. package/dist/distributed/networkTransport.js +633 -0
  111. package/dist/distributed/queryPlanner.d.ts +104 -0
  112. package/dist/distributed/queryPlanner.js +327 -0
  113. package/dist/distributed/readWriteSeparation.d.ts +134 -0
  114. package/dist/distributed/readWriteSeparation.js +350 -0
  115. package/dist/distributed/shardManager.d.ts +114 -0
  116. package/dist/distributed/shardManager.js +357 -0
  117. package/dist/distributed/shardMigration.d.ts +110 -0
  118. package/dist/distributed/shardMigration.js +289 -0
  119. package/dist/distributed/storageDiscovery.d.ts +160 -0
  120. package/dist/distributed/storageDiscovery.js +551 -0
  121. package/dist/embeddings/EmbeddingManager.d.ts +0 -4
  122. package/dist/embeddings/EmbeddingManager.js +21 -26
  123. package/dist/errors/brainyError.d.ts +5 -1
  124. package/dist/errors/brainyError.js +12 -0
  125. package/dist/examples/basicUsage.js +3 -3
  126. package/dist/graph/graphAdjacencyIndex.d.ts +96 -0
  127. package/dist/graph/graphAdjacencyIndex.js +288 -0
  128. package/dist/graph/pathfinding.js +4 -2
  129. package/dist/hnsw/scaledHNSWSystem.js +11 -2
  130. package/dist/importManager.js +6 -3
  131. package/dist/index.d.ts +12 -21
  132. package/dist/index.js +14 -22
  133. package/dist/mcp/brainyMCPAdapter.d.ts +4 -4
  134. package/dist/mcp/brainyMCPAdapter.js +5 -5
  135. package/dist/mcp/brainyMCPService.d.ts +3 -3
  136. package/dist/mcp/brainyMCPService.js +3 -11
  137. package/dist/mcp/mcpAugmentationToolset.js +20 -30
  138. package/dist/neural/embeddedPatterns.d.ts +1 -1
  139. package/dist/neural/embeddedPatterns.js +2 -2
  140. package/dist/neural/entityExtractor.d.ts +65 -0
  141. package/dist/neural/entityExtractor.js +316 -0
  142. package/dist/neural/improvedNeuralAPI.js +90 -79
  143. package/dist/neural/naturalLanguageProcessor.d.ts +155 -10
  144. package/dist/neural/naturalLanguageProcessor.js +941 -66
  145. package/dist/neural/naturalLanguageProcessorStatic.d.ts +2 -2
  146. package/dist/neural/naturalLanguageProcessorStatic.js +3 -3
  147. package/dist/neural/neuralAPI.js +8 -2
  148. package/dist/neural/patternLibrary.d.ts +57 -3
  149. package/dist/neural/patternLibrary.js +348 -13
  150. package/dist/neural/staticPatternMatcher.d.ts +2 -2
  151. package/dist/neural/staticPatternMatcher.js +2 -2
  152. package/dist/shared/default-augmentations.d.ts +3 -3
  153. package/dist/shared/default-augmentations.js +5 -5
  154. package/dist/storage/adapters/fileSystemStorage.d.ts +4 -0
  155. package/dist/storage/adapters/fileSystemStorage.js +54 -1
  156. package/dist/storage/adapters/memoryStorage.js +13 -8
  157. package/dist/storage/backwardCompatibility.d.ts +10 -78
  158. package/dist/storage/backwardCompatibility.js +17 -132
  159. package/dist/storage/baseStorage.d.ts +6 -0
  160. package/dist/storage/baseStorage.js +17 -0
  161. package/dist/storage/cacheManager.js +2 -2
  162. package/dist/storage/readOnlyOptimizations.js +8 -3
  163. package/dist/streaming/pipeline.d.ts +154 -0
  164. package/dist/streaming/pipeline.js +551 -0
  165. package/dist/triple/TripleIntelligence.d.ts +25 -110
  166. package/dist/triple/TripleIntelligence.js +4 -574
  167. package/dist/triple/TripleIntelligenceSystem.d.ts +159 -0
  168. package/dist/triple/TripleIntelligenceSystem.js +519 -0
  169. package/dist/types/apiTypes.d.ts +278 -0
  170. package/dist/types/apiTypes.js +33 -0
  171. package/dist/types/brainy.types.d.ts +308 -0
  172. package/dist/types/brainy.types.js +8 -0
  173. package/dist/types/brainyDataInterface.d.ts +3 -3
  174. package/dist/types/brainyDataInterface.js +2 -2
  175. package/dist/types/graphTypes.js +2 -2
  176. package/dist/utils/cacheAutoConfig.d.ts +3 -3
  177. package/dist/utils/embedding.js +8 -14
  178. package/dist/utils/enhancedLogger.d.ts +104 -0
  179. package/dist/utils/enhancedLogger.js +232 -0
  180. package/dist/utils/index.d.ts +1 -1
  181. package/dist/utils/index.js +1 -1
  182. package/dist/utils/intelligentTypeMapper.d.ts +60 -0
  183. package/dist/utils/intelligentTypeMapper.js +349 -0
  184. package/dist/utils/metadataIndex.d.ts +118 -1
  185. package/dist/utils/metadataIndex.js +539 -16
  186. package/dist/utils/paramValidation.d.ts +39 -0
  187. package/dist/utils/paramValidation.js +192 -0
  188. package/dist/utils/rateLimiter.d.ts +160 -0
  189. package/dist/utils/rateLimiter.js +271 -0
  190. package/dist/utils/statistics.d.ts +4 -4
  191. package/dist/utils/statistics.js +3 -3
  192. package/dist/utils/structuredLogger.d.ts +146 -0
  193. package/dist/utils/structuredLogger.js +394 -0
  194. package/dist/utils/textEncoding.js +2 -1
  195. package/dist/utils/typeValidation.d.ts +34 -0
  196. package/dist/utils/typeValidation.js +247 -0
  197. package/package.json +14 -6
  198. package/scripts/download-models.cjs +6 -15
  199. package/dist/augmentations/walAugmentation.d.ts +0 -111
  200. package/dist/augmentations/walAugmentation.js +0 -519
  201. package/dist/chat/BrainyChat.d.ts +0 -121
  202. package/dist/chat/BrainyChat.js +0 -396
  203. package/dist/chat/ChatCLI.d.ts +0 -61
  204. package/dist/chat/ChatCLI.js +0 -351
package/dist/brainy.js ADDED
@@ -0,0 +1,1181 @@
1
+ /**
2
+ * 🧠 Brainy 3.0 - The Future of Neural Databases
3
+ *
4
+ * Beautiful, Professional, Planet-Scale, Fun to Use
5
+ * NO STUBS, NO MOCKS, REAL IMPLEMENTATION
6
+ */
7
+ import { v4 as uuidv4 } from './universal/uuid.js';
8
+ import { HNSWIndex } from './hnsw/hnswIndex.js';
9
+ import { HNSWIndexOptimized } from './hnsw/hnswIndexOptimized.js';
10
+ import { createStorage } from './storage/storageFactory.js';
11
+ import { defaultEmbeddingFunction, cosineDistance } from './utils/index.js';
12
+ import { AugmentationRegistry } from './augmentations/brainyAugmentation.js';
13
+ import { createDefaultAugmentations } from './augmentations/defaultAugmentations.js';
14
+ import { ImprovedNeuralAPI } from './neural/improvedNeuralAPI.js';
15
+ import { NaturalLanguageProcessor } from './neural/naturalLanguageProcessor.js';
16
+ import { TripleIntelligenceSystem } from './triple/TripleIntelligenceSystem.js';
17
+ import { MetadataIndexManager } from './utils/metadataIndex.js';
18
+ import { GraphAdjacencyIndex } from './graph/graphAdjacencyIndex.js';
19
+ import { NounType } from './types/graphTypes.js';
20
+ /**
21
+ * The main Brainy class - Clean, Beautiful, Powerful
22
+ * REAL IMPLEMENTATION - No stubs, no mocks
23
+ */
24
+ export class Brainy {
25
+ constructor(config) {
26
+ // State
27
+ this.initialized = false;
28
+ // Normalize configuration with defaults
29
+ this.config = this.normalizeConfig(config);
30
+ // Setup core components
31
+ this.distance = cosineDistance;
32
+ this.embedder = this.setupEmbedder();
33
+ this.augmentationRegistry = this.setupAugmentations();
34
+ // Index and storage are initialized in init() because they may need each other
35
+ }
36
+ /**
37
+ * Initialize Brainy - MUST be called before use
38
+ * @param overrides Optional configuration overrides for init
39
+ */
40
+ async init(overrides) {
41
+ if (this.initialized) {
42
+ return;
43
+ }
44
+ // Apply any init-time configuration overrides
45
+ if (overrides) {
46
+ const { dimensions, ...configOverrides } = overrides;
47
+ this.config = {
48
+ ...this.config,
49
+ ...configOverrides,
50
+ storage: { ...this.config.storage, ...configOverrides.storage },
51
+ model: { ...this.config.model, ...configOverrides.model },
52
+ index: { ...this.config.index, ...configOverrides.index },
53
+ augmentations: { ...this.config.augmentations, ...configOverrides.augmentations }
54
+ };
55
+ // Set dimensions if provided
56
+ if (dimensions) {
57
+ this.dimensions = dimensions;
58
+ }
59
+ }
60
+ try {
61
+ // Setup and initialize storage
62
+ this.storage = await this.setupStorage();
63
+ await this.storage.init();
64
+ // Setup index now that we have storage
65
+ this.index = this.setupIndex();
66
+ // Initialize core metadata index
67
+ this.metadataIndex = new MetadataIndexManager(this.storage);
68
+ // Initialize core graph index
69
+ this.graphIndex = new GraphAdjacencyIndex(this.storage);
70
+ // Rebuild indexes if needed for existing data
71
+ await this.rebuildIndexesIfNeeded();
72
+ // Initialize augmentations
73
+ await this.augmentationRegistry.initializeAll({
74
+ brain: this,
75
+ storage: this.storage,
76
+ config: this.config,
77
+ log: (message, level = 'info') => {
78
+ // Simple logging for now
79
+ if (level === 'error') {
80
+ console.error(message);
81
+ }
82
+ else if (level === 'warn') {
83
+ console.warn(message);
84
+ }
85
+ else {
86
+ console.log(message);
87
+ }
88
+ }
89
+ });
90
+ // Warm up if configured
91
+ if (this.config.warmup) {
92
+ await this.warmup();
93
+ }
94
+ this.initialized = true;
95
+ }
96
+ catch (error) {
97
+ throw new Error(`Failed to initialize Brainy: ${error}`);
98
+ }
99
+ }
100
+ /**
101
+ * Ensure Brainy is initialized
102
+ */
103
+ async ensureInitialized() {
104
+ if (!this.initialized) {
105
+ throw new Error('Brainy not initialized. Call init() first.');
106
+ }
107
+ }
108
+ // ============= CORE CRUD OPERATIONS =============
109
+ /**
110
+ * Add an entity to the database
111
+ */
112
+ async add(params) {
113
+ await this.ensureInitialized();
114
+ // Zero-config validation
115
+ const { validateAddParams } = await import('./utils/paramValidation.js');
116
+ validateAddParams(params);
117
+ // Generate ID if not provided
118
+ const id = params.id || uuidv4();
119
+ // Get or compute vector
120
+ const vector = params.vector || (await this.embed(params.data));
121
+ // Ensure dimensions are set
122
+ if (!this.dimensions) {
123
+ this.dimensions = vector.length;
124
+ }
125
+ else if (vector.length !== this.dimensions) {
126
+ throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${vector.length}`);
127
+ }
128
+ // Execute through augmentation pipeline
129
+ return this.augmentationRegistry.execute('add', params, async () => {
130
+ // Add to index
131
+ await this.index.addItem({ id, vector });
132
+ // Prepare metadata object with data field included
133
+ const metadata = {
134
+ ...(typeof params.data === 'object' && params.data !== null && !Array.isArray(params.data) ? params.data : {}),
135
+ ...params.metadata,
136
+ _data: params.data, // Store the raw data in metadata
137
+ noun: params.type,
138
+ service: params.service,
139
+ createdAt: Date.now()
140
+ };
141
+ // Save to storage
142
+ await this.storage.saveNoun({
143
+ id,
144
+ vector,
145
+ connections: new Map(),
146
+ level: 0,
147
+ metadata
148
+ });
149
+ // Add to metadata index for fast filtering
150
+ await this.metadataIndex.addToIndex(id, metadata);
151
+ return id;
152
+ });
153
+ }
154
+ /**
155
+ * Get an entity by ID
156
+ */
157
+ async get(id) {
158
+ await this.ensureInitialized();
159
+ return this.augmentationRegistry.execute('get', { id }, async () => {
160
+ // Get from storage
161
+ const noun = await this.storage.getNoun(id);
162
+ if (!noun) {
163
+ return null;
164
+ }
165
+ // Use the common conversion method
166
+ return this.convertNounToEntity(noun);
167
+ });
168
+ }
169
+ /**
170
+ * Convert a noun from storage to an entity
171
+ */
172
+ async convertNounToEntity(noun) {
173
+ // Extract metadata - separate user metadata from system metadata
174
+ const { noun: nounType, service, createdAt, updatedAt, _data, ...userMetadata } = noun.metadata || {};
175
+ const entity = {
176
+ id: noun.id,
177
+ vector: noun.vector,
178
+ type: nounType || NounType.Thing,
179
+ metadata: userMetadata,
180
+ service: service,
181
+ createdAt: createdAt || Date.now(),
182
+ updatedAt: updatedAt
183
+ };
184
+ // Only add data field if it exists
185
+ if (_data !== undefined) {
186
+ entity.data = _data;
187
+ }
188
+ return entity;
189
+ }
190
+ /**
191
+ * Update an entity
192
+ */
193
+ async update(params) {
194
+ await this.ensureInitialized();
195
+ // Zero-config validation
196
+ const { validateUpdateParams } = await import('./utils/paramValidation.js');
197
+ validateUpdateParams(params);
198
+ return this.augmentationRegistry.execute('update', params, async () => {
199
+ // Get existing entity
200
+ const existing = await this.get(params.id);
201
+ if (!existing) {
202
+ throw new Error(`Entity ${params.id} not found`);
203
+ }
204
+ // Update vector if data changed
205
+ let vector = existing.vector;
206
+ if (params.data) {
207
+ vector = params.vector || (await this.embed(params.data));
208
+ // Update in index (remove and re-add since no update method)
209
+ await this.index.removeItem(params.id);
210
+ await this.index.addItem({ id: params.id, vector });
211
+ }
212
+ // Always update the noun with new metadata
213
+ const newMetadata = params.merge !== false
214
+ ? { ...existing.metadata, ...params.metadata }
215
+ : params.metadata || existing.metadata;
216
+ // Merge data objects if both old and new are objects
217
+ const dataFields = typeof params.data === 'object' && params.data !== null && !Array.isArray(params.data)
218
+ ? params.data
219
+ : {};
220
+ // Prepare updated metadata object with data field
221
+ const updatedMetadata = {
222
+ ...newMetadata,
223
+ ...dataFields,
224
+ _data: params.data !== undefined ? params.data : existing.data, // Update the data field
225
+ noun: params.type || existing.type,
226
+ service: existing.service,
227
+ createdAt: existing.createdAt,
228
+ updatedAt: Date.now()
229
+ };
230
+ await this.storage.saveNoun({
231
+ id: params.id,
232
+ vector,
233
+ connections: new Map(),
234
+ level: 0,
235
+ metadata: updatedMetadata
236
+ });
237
+ // Update metadata index - remove old entry and add new one
238
+ await this.metadataIndex.removeFromIndex(params.id, existing.metadata);
239
+ await this.metadataIndex.addToIndex(params.id, updatedMetadata);
240
+ });
241
+ }
242
+ /**
243
+ * Delete an entity
244
+ */
245
+ async delete(id) {
246
+ await this.ensureInitialized();
247
+ return this.augmentationRegistry.execute('delete', { id }, async () => {
248
+ // Remove from vector index
249
+ await this.index.removeItem(id);
250
+ // Remove from metadata index
251
+ await this.metadataIndex.removeFromIndex(id);
252
+ // Delete from storage
253
+ await this.storage.deleteNoun(id);
254
+ // Delete metadata (if it exists as separate)
255
+ try {
256
+ await this.storage.saveMetadata(id, null); // Clear metadata
257
+ }
258
+ catch {
259
+ // Ignore if not supported
260
+ }
261
+ // Delete related verbs
262
+ const verbs = await this.storage.getVerbsBySource(id);
263
+ const targetVerbs = await this.storage.getVerbsByTarget(id);
264
+ const allVerbs = [...verbs, ...targetVerbs];
265
+ for (const verb of allVerbs) {
266
+ await this.storage.deleteVerb(verb.id);
267
+ }
268
+ });
269
+ }
270
+ // ============= RELATIONSHIP OPERATIONS =============
271
+ /**
272
+ * Create a relationship between entities
273
+ */
274
+ async relate(params) {
275
+ await this.ensureInitialized();
276
+ // Zero-config validation
277
+ const { validateRelateParams } = await import('./utils/paramValidation.js');
278
+ validateRelateParams(params);
279
+ // Verify entities exist
280
+ const fromEntity = await this.get(params.from);
281
+ const toEntity = await this.get(params.to);
282
+ if (!fromEntity) {
283
+ throw new Error(`Source entity ${params.from} not found`);
284
+ }
285
+ if (!toEntity) {
286
+ throw new Error(`Target entity ${params.to} not found`);
287
+ }
288
+ // Generate ID
289
+ const id = uuidv4();
290
+ // Compute relationship vector (average of entities)
291
+ const relationVector = fromEntity.vector.map((v, i) => (v + toEntity.vector[i]) / 2);
292
+ return this.augmentationRegistry.execute('relate', params, async () => {
293
+ // Save to storage
294
+ const verb = {
295
+ id,
296
+ vector: relationVector,
297
+ sourceId: params.from,
298
+ targetId: params.to,
299
+ source: fromEntity.type,
300
+ target: toEntity.type,
301
+ verb: params.type,
302
+ type: params.type,
303
+ weight: params.weight ?? 1.0,
304
+ metadata: params.metadata,
305
+ createdAt: Date.now()
306
+ };
307
+ await this.storage.saveVerb(verb);
308
+ // Add to graph index for O(1) lookups
309
+ await this.graphIndex.addVerb(verb);
310
+ // Create bidirectional if requested
311
+ if (params.bidirectional) {
312
+ const reverseId = uuidv4();
313
+ const reverseVerb = {
314
+ ...verb,
315
+ id: reverseId,
316
+ sourceId: params.to,
317
+ targetId: params.from,
318
+ source: toEntity.type,
319
+ target: fromEntity.type
320
+ };
321
+ await this.storage.saveVerb(reverseVerb);
322
+ // Add reverse relationship to graph index too
323
+ await this.graphIndex.addVerb(reverseVerb);
324
+ }
325
+ return id;
326
+ });
327
+ }
328
+ /**
329
+ * Delete a relationship
330
+ */
331
+ async unrelate(id) {
332
+ await this.ensureInitialized();
333
+ return this.augmentationRegistry.execute('unrelate', { id }, async () => {
334
+ // Remove from graph index
335
+ await this.graphIndex.removeVerb(id);
336
+ // Remove from storage
337
+ await this.storage.deleteVerb(id);
338
+ });
339
+ }
340
+ /**
341
+ * Get relationships
342
+ */
343
+ async getRelations(params = {}) {
344
+ await this.ensureInitialized();
345
+ const relations = [];
346
+ if (params.from) {
347
+ const verbs = await this.storage.getVerbsBySource(params.from);
348
+ relations.push(...this.verbsToRelations(verbs));
349
+ }
350
+ if (params.to) {
351
+ const verbs = await this.storage.getVerbsByTarget(params.to);
352
+ relations.push(...this.verbsToRelations(verbs));
353
+ }
354
+ // Filter by type
355
+ let filtered = relations;
356
+ if (params.type) {
357
+ const types = Array.isArray(params.type) ? params.type : [params.type];
358
+ filtered = relations.filter((r) => types.includes(r.type));
359
+ }
360
+ // Filter by service
361
+ if (params.service) {
362
+ filtered = filtered.filter((r) => r.service === params.service);
363
+ }
364
+ // Apply pagination
365
+ const limit = params.limit || 100;
366
+ const offset = params.offset || 0;
367
+ return filtered.slice(offset, offset + limit);
368
+ }
369
+ // ============= SEARCH & DISCOVERY =============
370
+ /**
371
+ * Unified find method - supports natural language and structured queries
372
+ * Implements Triple Intelligence with parallel search optimization
373
+ */
374
+ async find(query) {
375
+ await this.ensureInitialized();
376
+ // Parse natural language queries
377
+ const params = typeof query === 'string' ? await this.parseNaturalQuery(query) : query;
378
+ // Zero-config validation - only enforces universal truths
379
+ const { validateFindParams, recordQueryPerformance } = await import('./utils/paramValidation.js');
380
+ validateFindParams(params);
381
+ const startTime = Date.now();
382
+ const result = await this.augmentationRegistry.execute('find', params, async () => {
383
+ let results = [];
384
+ // Handle empty query - return paginated results from storage
385
+ const hasSearchCriteria = params.query || params.vector || params.where ||
386
+ params.type || params.service || params.near || params.connected;
387
+ if (!hasSearchCriteria) {
388
+ const limit = params.limit || 20;
389
+ const offset = params.offset || 0;
390
+ const storageResults = await this.storage.getNouns({
391
+ pagination: { limit: limit + offset, offset: 0 }
392
+ });
393
+ for (let i = offset; i < Math.min(offset + limit, storageResults.items.length); i++) {
394
+ const noun = storageResults.items[i];
395
+ if (noun) {
396
+ const entity = await this.convertNounToEntity(noun);
397
+ results.push({
398
+ id: noun.id,
399
+ score: 1.0, // All results equally relevant for empty query
400
+ entity
401
+ });
402
+ }
403
+ }
404
+ return results;
405
+ }
406
+ // Execute parallel searches for optimal performance
407
+ const searchPromises = [];
408
+ // Vector search component
409
+ if (params.query || params.vector) {
410
+ searchPromises.push(this.executeVectorSearch(params));
411
+ }
412
+ // Proximity search component
413
+ if (params.near) {
414
+ searchPromises.push(this.executeProximitySearch(params));
415
+ }
416
+ // Execute searches in parallel
417
+ if (searchPromises.length > 0) {
418
+ const searchResults = await Promise.all(searchPromises);
419
+ for (const batch of searchResults) {
420
+ results.push(...batch);
421
+ }
422
+ }
423
+ // Remove duplicate results from parallel searches
424
+ if (results.length > 0) {
425
+ const uniqueResults = new Map();
426
+ for (const result of results) {
427
+ const existing = uniqueResults.get(result.id);
428
+ if (!existing || result.score > existing.score) {
429
+ uniqueResults.set(result.id, result);
430
+ }
431
+ }
432
+ results = Array.from(uniqueResults.values());
433
+ }
434
+ // Apply O(log n) metadata filtering using core MetadataIndexManager
435
+ if (params.where || params.type || params.service) {
436
+ // Build filter object for metadata index
437
+ let filter = {};
438
+ // Base filter from where and service
439
+ if (params.where)
440
+ Object.assign(filter, params.where);
441
+ if (params.service)
442
+ filter.service = params.service;
443
+ if (params.type) {
444
+ const types = Array.isArray(params.type) ? params.type : [params.type];
445
+ if (types.length === 1) {
446
+ filter.noun = types[0];
447
+ }
448
+ else {
449
+ // For multiple types, create separate filter for each type with all conditions
450
+ filter = {
451
+ anyOf: types.map(type => ({
452
+ noun: type,
453
+ ...filter
454
+ }))
455
+ };
456
+ }
457
+ }
458
+ const filteredIds = await this.metadataIndex.getIdsForFilter(filter);
459
+ // CRITICAL FIX: Handle both cases properly
460
+ if (results.length > 0) {
461
+ // Filter existing results (from vector search)
462
+ const filteredIdSet = new Set(filteredIds);
463
+ results = results.filter((r) => filteredIdSet.has(r.id));
464
+ }
465
+ else {
466
+ // Create results from metadata matches (metadata-only query)
467
+ for (const id of filteredIds) {
468
+ const entity = await this.get(id);
469
+ if (entity) {
470
+ results.push({
471
+ id,
472
+ score: 1.0, // All metadata matches are equally relevant
473
+ entity
474
+ });
475
+ }
476
+ }
477
+ }
478
+ }
479
+ // Graph search component with O(1) traversal
480
+ if (params.connected) {
481
+ results = await this.executeGraphSearch(params, results);
482
+ }
483
+ // Apply fusion scoring if requested
484
+ if (params.fusion && results.length > 0) {
485
+ results = this.applyFusionScoring(results, params.fusion);
486
+ }
487
+ // Sort by score and apply pagination
488
+ results.sort((a, b) => b.score - a.score);
489
+ const limit = params.limit || 10;
490
+ const offset = params.offset || 0;
491
+ return results.slice(offset, offset + limit);
492
+ });
493
+ // Record performance for auto-tuning
494
+ const duration = Date.now() - startTime;
495
+ recordQueryPerformance(duration, result.length);
496
+ return result;
497
+ }
498
+ /**
499
+ * Find similar entities
500
+ */
501
+ async similar(params) {
502
+ await this.ensureInitialized();
503
+ // Get target vector
504
+ let targetVector;
505
+ if (typeof params.to === 'string') {
506
+ const entity = await this.get(params.to);
507
+ if (!entity) {
508
+ throw new Error(`Entity ${params.to} not found`);
509
+ }
510
+ targetVector = entity.vector;
511
+ }
512
+ else if (Array.isArray(params.to)) {
513
+ targetVector = params.to;
514
+ }
515
+ else {
516
+ targetVector = params.to.vector;
517
+ }
518
+ // Use find with vector
519
+ return this.find({
520
+ vector: targetVector,
521
+ limit: params.limit,
522
+ type: params.type,
523
+ where: params.where,
524
+ service: params.service
525
+ });
526
+ }
527
+ // ============= BATCH OPERATIONS =============
528
+ /**
529
+ * Add multiple entities
530
+ */
531
+ async addMany(params) {
532
+ await this.ensureInitialized();
533
+ const result = {
534
+ successful: [],
535
+ failed: [],
536
+ total: params.items.length,
537
+ duration: 0
538
+ };
539
+ const startTime = Date.now();
540
+ const chunkSize = params.chunkSize || 100;
541
+ // Process in chunks
542
+ for (let i = 0; i < params.items.length; i += chunkSize) {
543
+ const chunk = params.items.slice(i, i + chunkSize);
544
+ const promises = chunk.map(async (item) => {
545
+ try {
546
+ const id = await this.add(item);
547
+ result.successful.push(id);
548
+ }
549
+ catch (error) {
550
+ result.failed.push({
551
+ item,
552
+ error: error.message
553
+ });
554
+ if (!params.continueOnError) {
555
+ throw error;
556
+ }
557
+ }
558
+ });
559
+ if (params.parallel !== false) {
560
+ await Promise.allSettled(promises);
561
+ }
562
+ else {
563
+ for (const promise of promises) {
564
+ await promise;
565
+ }
566
+ }
567
+ // Report progress
568
+ if (params.onProgress) {
569
+ params.onProgress(result.successful.length + result.failed.length, result.total);
570
+ }
571
+ }
572
+ result.duration = Date.now() - startTime;
573
+ return result;
574
+ }
575
+ /**
576
+ * Delete multiple entities
577
+ */
578
+ async deleteMany(params) {
579
+ await this.ensureInitialized();
580
+ // Determine what to delete
581
+ let idsToDelete = [];
582
+ if (params.ids) {
583
+ idsToDelete = params.ids;
584
+ }
585
+ else if (params.type || params.where) {
586
+ // Find entities to delete
587
+ const entities = await this.find({
588
+ type: params.type,
589
+ where: params.where,
590
+ limit: params.limit || 1000
591
+ });
592
+ idsToDelete = entities.map((e) => e.id);
593
+ }
594
+ const result = {
595
+ successful: [],
596
+ failed: [],
597
+ total: idsToDelete.length,
598
+ duration: 0
599
+ };
600
+ const startTime = Date.now();
601
+ for (const id of idsToDelete) {
602
+ try {
603
+ await this.delete(id);
604
+ result.successful.push(id);
605
+ }
606
+ catch (error) {
607
+ result.failed.push({
608
+ item: id,
609
+ error: error.message
610
+ });
611
+ }
612
+ if (params.onProgress) {
613
+ params.onProgress(result.successful.length + result.failed.length, result.total);
614
+ }
615
+ }
616
+ result.duration = Date.now() - startTime;
617
+ return result;
618
+ }
619
+ /**
620
+ * Update multiple entities with batch processing
621
+ */
622
+ async updateMany(params) {
623
+ await this.ensureInitialized();
624
+ const result = {
625
+ successful: [],
626
+ failed: [],
627
+ total: params.items.length,
628
+ duration: 0
629
+ };
630
+ const startTime = Date.now();
631
+ const chunkSize = params.chunkSize || 100;
632
+ // Process in chunks
633
+ for (let i = 0; i < params.items.length; i += chunkSize) {
634
+ const chunk = params.items.slice(i, i + chunkSize);
635
+ const promises = chunk.map(async (item, chunkIndex) => {
636
+ try {
637
+ await this.update(item);
638
+ result.successful.push(item.id);
639
+ }
640
+ catch (error) {
641
+ result.failed.push({
642
+ item,
643
+ error: error.message
644
+ });
645
+ if (!params.continueOnError) {
646
+ throw error;
647
+ }
648
+ }
649
+ });
650
+ if (params.parallel !== false) {
651
+ await Promise.allSettled(promises);
652
+ }
653
+ else {
654
+ for (const promise of promises) {
655
+ await promise;
656
+ }
657
+ }
658
+ // Report progress
659
+ if (params.onProgress) {
660
+ params.onProgress(result.successful.length + result.failed.length, result.total);
661
+ }
662
+ }
663
+ result.duration = Date.now() - startTime;
664
+ return result;
665
+ }
666
+ /**
667
+ * Clear all data from the database
668
+ */
669
+ async clear() {
670
+ await this.ensureInitialized();
671
+ return this.augmentationRegistry.execute('clear', {}, async () => {
672
+ // Clear storage
673
+ await this.storage.clear();
674
+ // Reset index
675
+ if ('clear' in this.index && typeof this.index.clear === 'function') {
676
+ await this.index.clear();
677
+ }
678
+ else {
679
+ // Recreate index if no clear method
680
+ this.index = this.setupIndex();
681
+ }
682
+ // Reset dimensions
683
+ this.dimensions = undefined;
684
+ // Clear any cached sub-APIs
685
+ this._neural = undefined;
686
+ this._nlp = undefined;
687
+ this._tripleIntelligence = undefined;
688
+ });
689
+ }
690
+ // ============= SUB-APIS =============
691
+ /**
692
+ * Neural API - Advanced AI operations
693
+ */
694
+ neural() {
695
+ if (!this._neural) {
696
+ this._neural = new ImprovedNeuralAPI(this);
697
+ }
698
+ return this._neural;
699
+ }
700
+ /**
701
+ * Natural Language Processing API
702
+ */
703
+ nlp() {
704
+ if (!this._nlp) {
705
+ this._nlp = new NaturalLanguageProcessor(this);
706
+ }
707
+ return this._nlp;
708
+ }
709
+ /**
710
+ * Data Management API - backup, restore, import, export
711
+ */
712
+ async data() {
713
+ const { DataAPI } = await import('./api/DataAPI.js');
714
+ return new DataAPI(this.storage, (id) => this.get(id), undefined, // No getRelation method yet
715
+ this);
716
+ }
717
+ /**
718
+ * Get Triple Intelligence System
719
+ * Advanced pattern recognition and relationship analysis
720
+ */
721
+ getTripleIntelligence() {
722
+ if (!this._tripleIntelligence) {
723
+ // Use core components directly - no lazy loading needed
724
+ this._tripleIntelligence = new TripleIntelligenceSystem(this.metadataIndex, this.index, this.graphIndex, async (text) => this.embedder(text), this.storage);
725
+ }
726
+ return this._tripleIntelligence;
727
+ }
728
+ // ============= METADATA INTELLIGENCE API =============
729
+ /**
730
+ * Get all indexed field names currently in the metadata index
731
+ * Essential for dynamic query building and NLP field discovery
732
+ */
733
+ async getAvailableFields() {
734
+ await this.ensureInitialized();
735
+ return this.metadataIndex.getFilterFields();
736
+ }
737
+ /**
738
+ * Get field statistics including cardinality and query patterns
739
+ * Used for query optimization and understanding data distribution
740
+ */
741
+ async getFieldStatistics() {
742
+ await this.ensureInitialized();
743
+ return this.metadataIndex.getFieldStatistics();
744
+ }
745
+ /**
746
+ * Get fields sorted by cardinality for optimal filtering
747
+ * Lower cardinality fields are better for initial filtering
748
+ */
749
+ async getFieldsWithCardinality() {
750
+ await this.ensureInitialized();
751
+ return this.metadataIndex.getFieldsWithCardinality();
752
+ }
753
+ /**
754
+ * Get optimal query plan for a given set of filters
755
+ * Returns field processing order and estimated cost
756
+ */
757
+ async getOptimalQueryPlan(filters) {
758
+ await this.ensureInitialized();
759
+ return this.metadataIndex.getOptimalQueryPlan(filters);
760
+ }
761
+ /**
762
+ * Get filter values for a specific field (for UI dropdowns, etc)
763
+ */
764
+ async getFieldValues(field) {
765
+ await this.ensureInitialized();
766
+ return this.metadataIndex.getFilterValues(field);
767
+ }
768
+ /**
769
+ * Get fields that commonly appear with a specific entity type
770
+ * Essential for type-aware NLP parsing
771
+ */
772
+ async getFieldsForType(nounType) {
773
+ await this.ensureInitialized();
774
+ return this.metadataIndex.getFieldsForType(nounType);
775
+ }
776
+ /**
777
+ * Get comprehensive type-field affinity statistics
778
+ * Useful for understanding data patterns and NLP optimization
779
+ */
780
+ async getTypeFieldAffinityStats() {
781
+ await this.ensureInitialized();
782
+ return this.metadataIndex.getTypeFieldAffinityStats();
783
+ }
784
+ /**
785
+ * Create a streaming pipeline
786
+ */
787
+ stream() {
788
+ const { Pipeline } = require('./streaming/pipeline.js');
789
+ return new Pipeline(this);
790
+ }
791
+ /**
792
+ * Get insights about the data
793
+ */
794
+ async insights() {
795
+ await this.ensureInitialized();
796
+ // Get all entities count - use getNouns with high limit
797
+ const entitiesResult = await this.storage.getNouns({
798
+ pagination: { limit: 10000 }
799
+ });
800
+ const entities = entitiesResult.totalCount || entitiesResult.items.length;
801
+ // Get relationships count - use getVerbs with high limit
802
+ const verbsResult = await this.storage.getVerbs({
803
+ pagination: { limit: 10000 }
804
+ });
805
+ const relationships = verbsResult.totalCount || verbsResult.items.length;
806
+ // Count by type
807
+ const types = {};
808
+ for (const entity of entitiesResult.items) {
809
+ const type = entity.metadata?.noun || 'unknown';
810
+ types[type] = (types[type] || 0) + 1;
811
+ }
812
+ // Get unique services
813
+ const services = [...new Set(entitiesResult.items.map((e) => e.metadata?.service).filter(Boolean))];
814
+ // Calculate density (relationships per entity)
815
+ const density = entities > 0 ? relationships / entities : 0;
816
+ return {
817
+ entities,
818
+ relationships,
819
+ types,
820
+ services,
821
+ density
822
+ };
823
+ }
824
+ /**
825
+ * Augmentations API - Clean and simple
826
+ */
827
+ get augmentations() {
828
+ return {
829
+ list: () => this.augmentationRegistry.getAll().map(a => a.name),
830
+ get: (name) => this.augmentationRegistry.getAll().find(a => a.name === name),
831
+ has: (name) => this.augmentationRegistry.getAll().some(a => a.name === name)
832
+ };
833
+ }
834
+ // ============= HELPER METHODS =============
835
+ /**
836
+ * Parse natural language query using advanced NLP with 220+ patterns
837
+ * The embedding model is always available as it's core to Brainy's functionality
838
+ */
839
+ async parseNaturalQuery(query) {
840
+ // Initialize NLP processor if needed (lazy loading)
841
+ if (!this._nlp) {
842
+ this._nlp = new NaturalLanguageProcessor(this);
843
+ await this._nlp.init(); // Ensure pattern library is loaded
844
+ }
845
+ // Process with our advanced pattern library (220+ patterns with embeddings)
846
+ const tripleQuery = await this._nlp.processNaturalQuery(query);
847
+ // Convert TripleQuery to FindParams
848
+ const params = {};
849
+ // Handle vector search
850
+ if (tripleQuery.like || tripleQuery.similar) {
851
+ params.query = typeof tripleQuery.like === 'string' ? tripleQuery.like :
852
+ typeof tripleQuery.similar === 'string' ? tripleQuery.similar : query;
853
+ }
854
+ else if (!tripleQuery.where && !tripleQuery.connected) {
855
+ // Default to vector search if no other criteria specified
856
+ params.query = query;
857
+ }
858
+ // Handle metadata filtering
859
+ if (tripleQuery.where) {
860
+ params.where = tripleQuery.where;
861
+ }
862
+ // Handle graph relationships
863
+ if (tripleQuery.connected) {
864
+ params.connected = {
865
+ to: Array.isArray(tripleQuery.connected.to) ? tripleQuery.connected.to[0] : tripleQuery.connected.to,
866
+ from: Array.isArray(tripleQuery.connected.from) ? tripleQuery.connected.from[0] : tripleQuery.connected.from,
867
+ via: tripleQuery.connected.type,
868
+ depth: tripleQuery.connected.depth,
869
+ direction: tripleQuery.connected.direction
870
+ };
871
+ }
872
+ // Handle other options
873
+ if (tripleQuery.limit)
874
+ params.limit = tripleQuery.limit;
875
+ if (tripleQuery.offset)
876
+ params.offset = tripleQuery.offset;
877
+ return this.enhanceNLPResult(params, query);
878
+ }
879
+ /**
880
+ * Enhance NLP results with fusion scoring
881
+ */
882
+ enhanceNLPResult(params, _originalQuery) {
883
+ // Add fusion scoring for complex queries
884
+ if (params.query && params.where && Object.keys(params.where).length > 0) {
885
+ params.fusion = params.fusion || {
886
+ strategy: 'adaptive',
887
+ weights: {
888
+ vector: 0.6,
889
+ field: 0.3,
890
+ graph: 0.1
891
+ }
892
+ };
893
+ }
894
+ return params;
895
+ }
896
+ /**
897
+ * Execute vector search component
898
+ */
899
+ async executeVectorSearch(params) {
900
+ const vector = params.vector || (await this.embed(params.query));
901
+ const limit = params.limit || 10;
902
+ const searchResults = await this.index.search(vector, limit * 2);
903
+ const results = [];
904
+ for (const [id, distance] of searchResults) {
905
+ const entity = await this.get(id);
906
+ if (entity) {
907
+ const score = Math.max(0, Math.min(1, 1 / (1 + distance)));
908
+ results.push({ id, score, entity });
909
+ }
910
+ }
911
+ return results;
912
+ }
913
+ /**
914
+ * Execute proximity search component
915
+ */
916
+ async executeProximitySearch(params) {
917
+ if (!params.near)
918
+ return [];
919
+ const nearEntity = await this.get(params.near.id);
920
+ if (!nearEntity)
921
+ return [];
922
+ const nearResults = await this.index.search(nearEntity.vector, params.limit || 10);
923
+ const results = [];
924
+ for (const [id, distance] of nearResults) {
925
+ const score = Math.max(0, Math.min(1, 1 / (1 + distance)));
926
+ if (score >= (params.near.threshold || 0.7)) {
927
+ const entity = await this.get(id);
928
+ if (entity) {
929
+ results.push({ id, score, entity });
930
+ }
931
+ }
932
+ }
933
+ return results;
934
+ }
935
+ /**
936
+ * Execute graph search component with O(1) traversal
937
+ */
938
+ async executeGraphSearch(params, existingResults) {
939
+ if (!params.connected)
940
+ return existingResults;
941
+ const { from, to, direction = 'both' } = params.connected;
942
+ const connectedIds = [];
943
+ if (from) {
944
+ const neighbors = await this.graphIndex.getNeighbors(from, direction);
945
+ connectedIds.push(...neighbors);
946
+ }
947
+ if (to) {
948
+ const reverseDirection = direction === 'in' ? 'out' : direction === 'out' ? 'in' : 'both';
949
+ const neighbors = await this.graphIndex.getNeighbors(to, reverseDirection);
950
+ connectedIds.push(...neighbors);
951
+ }
952
+ // Filter existing results to only connected entities
953
+ if (existingResults.length > 0) {
954
+ const connectedIdSet = new Set(connectedIds);
955
+ return existingResults.filter(r => connectedIdSet.has(r.id));
956
+ }
957
+ // Create results from connected entities
958
+ const results = [];
959
+ for (const id of connectedIds) {
960
+ const entity = await this.get(id);
961
+ if (entity) {
962
+ results.push({
963
+ id,
964
+ score: 1.0,
965
+ entity
966
+ });
967
+ }
968
+ }
969
+ return results;
970
+ }
971
+ /**
972
+ * Apply fusion scoring for multi-source results
973
+ */
974
+ applyFusionScoring(results, fusionType) {
975
+ // Implement different fusion strategies
976
+ const strategy = typeof fusionType === 'string' ? fusionType : fusionType.strategy || 'weighted';
977
+ switch (strategy) {
978
+ case 'max':
979
+ // Use maximum score from any source
980
+ return results;
981
+ case 'average':
982
+ // Average scores from multiple sources
983
+ const scoreMap = new Map();
984
+ for (const result of results) {
985
+ const scores = scoreMap.get(result.id) || [];
986
+ scores.push(result.score);
987
+ scoreMap.set(result.id, scores);
988
+ }
989
+ return results.map(r => ({
990
+ ...r,
991
+ score: scoreMap.get(r.id).reduce((a, b) => a + b, 0) / scoreMap.get(r.id).length
992
+ }));
993
+ case 'weighted':
994
+ default:
995
+ // Weighted combination based on source importance
996
+ const weights = fusionType.weights || { vector: 0.7, metadata: 0.2, graph: 0.1 };
997
+ return results.map(r => ({
998
+ ...r,
999
+ score: r.score * (weights.vector || 1.0)
1000
+ }));
1001
+ }
1002
+ }
1003
+ /**
1004
+ * Apply graph constraints using O(1) GraphAdjacencyIndex - TRUE Triple Intelligence!
1005
+ */
1006
+ async applyGraphConstraints(results, constraints) {
1007
+ // Filter by graph connections using fast graph index
1008
+ if (constraints.to || constraints.from) {
1009
+ const filtered = [];
1010
+ for (const result of results) {
1011
+ let hasConnection = false;
1012
+ if (constraints.to) {
1013
+ // Check if this entity connects TO the target (O(1) lookup)
1014
+ const outgoingNeighbors = await this.graphIndex.getNeighbors(result.id, 'out');
1015
+ hasConnection = outgoingNeighbors.includes(constraints.to);
1016
+ }
1017
+ if (constraints.from && !hasConnection) {
1018
+ // Check if this entity connects FROM the source (O(1) lookup)
1019
+ const incomingNeighbors = await this.graphIndex.getNeighbors(result.id, 'in');
1020
+ hasConnection = incomingNeighbors.includes(constraints.from);
1021
+ }
1022
+ if (hasConnection) {
1023
+ filtered.push(result);
1024
+ }
1025
+ }
1026
+ return filtered;
1027
+ }
1028
+ return results;
1029
+ }
1030
+ /**
1031
+ * Convert verbs to relations
1032
+ */
1033
+ verbsToRelations(verbs) {
1034
+ return verbs.map((v) => ({
1035
+ id: v.id,
1036
+ from: v.sourceId,
1037
+ to: v.targetId,
1038
+ type: (v.verb || v.type),
1039
+ weight: v.weight,
1040
+ metadata: v.metadata,
1041
+ service: v.metadata?.service,
1042
+ createdAt: typeof v.createdAt === 'number' ? v.createdAt : Date.now()
1043
+ }));
1044
+ }
1045
+ /**
1046
+ * Embed data into vector
1047
+ */
1048
+ async embed(data) {
1049
+ return this.embedder(data);
1050
+ }
1051
+ /**
1052
+ * Warm up the system
1053
+ */
1054
+ async warmup() {
1055
+ // Warm up embedder
1056
+ await this.embed('warmup');
1057
+ }
1058
+ /**
1059
+ * Setup embedder
1060
+ */
1061
+ setupEmbedder() {
1062
+ // Custom model loading removed - not implemented
1063
+ // Only 'fast' and 'accurate' model types are supported
1064
+ return defaultEmbeddingFunction;
1065
+ }
1066
+ /**
1067
+ * Setup storage
1068
+ */
1069
+ async setupStorage() {
1070
+ const storage = await createStorage({
1071
+ type: this.config.storage?.type || 'memory',
1072
+ ...this.config.storage?.options
1073
+ });
1074
+ return storage;
1075
+ }
1076
+ /**
1077
+ * Setup index
1078
+ */
1079
+ setupIndex() {
1080
+ const indexConfig = {
1081
+ ...this.config.index,
1082
+ distanceFunction: this.distance
1083
+ };
1084
+ // Use optimized index for larger datasets
1085
+ if (this.config.storage?.type !== 'memory') {
1086
+ return new HNSWIndexOptimized(indexConfig, this.distance, this.storage);
1087
+ }
1088
+ return new HNSWIndex(indexConfig);
1089
+ }
1090
+ /**
1091
+ * Setup augmentations
1092
+ */
1093
+ setupAugmentations() {
1094
+ const registry = new AugmentationRegistry();
1095
+ // Register default augmentations
1096
+ const defaults = createDefaultAugmentations(this.config.augmentations);
1097
+ for (const aug of defaults) {
1098
+ registry.register(aug);
1099
+ }
1100
+ return registry;
1101
+ }
1102
+ /**
1103
+ * Normalize and validate configuration
1104
+ */
1105
+ normalizeConfig(config) {
1106
+ // Validate storage configuration
1107
+ if (config?.storage?.type && !['memory', 'filesystem', 'opfs', 'remote'].includes(config.storage.type)) {
1108
+ throw new Error(`Invalid storage type: ${config.storage.type}. Must be one of: memory, filesystem, opfs, remote`);
1109
+ }
1110
+ // Validate model configuration
1111
+ if (config?.model?.type && !['fast', 'accurate', 'custom'].includes(config.model.type)) {
1112
+ throw new Error(`Invalid model type: ${config.model.type}. Must be one of: fast, accurate, custom`);
1113
+ }
1114
+ // Validate numeric configurations
1115
+ if (config?.index?.m && (config.index.m < 1 || config.index.m > 128)) {
1116
+ throw new Error(`Invalid index m parameter: ${config.index.m}. Must be between 1 and 128`);
1117
+ }
1118
+ if (config?.index?.efConstruction && (config.index.efConstruction < 1 || config.index.efConstruction > 1000)) {
1119
+ throw new Error(`Invalid index efConstruction: ${config.index.efConstruction}. Must be between 1 and 1000`);
1120
+ }
1121
+ if (config?.index?.efSearch && (config.index.efSearch < 1 || config.index.efSearch > 1000)) {
1122
+ throw new Error(`Invalid index efSearch: ${config.index.efSearch}. Must be between 1 and 1000`);
1123
+ }
1124
+ return {
1125
+ storage: config?.storage || { type: 'memory' },
1126
+ model: config?.model || { type: 'fast' },
1127
+ index: config?.index || {},
1128
+ cache: config?.cache ?? true,
1129
+ augmentations: config?.augmentations || {},
1130
+ warmup: config?.warmup ?? false,
1131
+ realtime: config?.realtime ?? false,
1132
+ multiTenancy: config?.multiTenancy ?? false,
1133
+ telemetry: config?.telemetry ?? false
1134
+ };
1135
+ }
1136
+ /**
1137
+ * Rebuild indexes if there's existing data but empty indexes
1138
+ */
1139
+ async rebuildIndexesIfNeeded() {
1140
+ try {
1141
+ // Check if storage has data
1142
+ const entities = await this.storage.getNouns({ pagination: { limit: 1 } });
1143
+ if (entities.totalCount === 0 || entities.items.length === 0) {
1144
+ // No data in storage, no rebuild needed
1145
+ return;
1146
+ }
1147
+ // Check if metadata index is empty
1148
+ const metadataStats = await this.metadataIndex.getStats();
1149
+ if (metadataStats.totalEntries === 0) {
1150
+ console.log('🔄 Rebuilding metadata index for existing data...');
1151
+ await this.metadataIndex.rebuild();
1152
+ const newStats = await this.metadataIndex.getStats();
1153
+ console.log(`✅ Metadata index rebuilt: ${newStats.totalEntries} entries`);
1154
+ }
1155
+ // Note: GraphAdjacencyIndex will rebuild itself as relationships are added
1156
+ // Vector index should already be populated if storage has data
1157
+ }
1158
+ catch (error) {
1159
+ console.warn('Warning: Could not check or rebuild indexes:', error);
1160
+ }
1161
+ }
1162
+ /**
1163
+ * Close and cleanup
1164
+ */
1165
+ async close() {
1166
+ // Shutdown augmentations
1167
+ const augs = this.augmentationRegistry.getAll();
1168
+ for (const aug of augs) {
1169
+ if ('shutdown' in aug && typeof aug.shutdown === 'function') {
1170
+ await aug.shutdown();
1171
+ }
1172
+ }
1173
+ // Storage doesn't have close in current interface
1174
+ // We'll just mark as not initialized
1175
+ this.initialized = false;
1176
+ }
1177
+ }
1178
+ // Re-export types for convenience
1179
+ export * from './types/brainy.types.js';
1180
+ export { NounType, VerbType } from './types/graphTypes.js';
1181
+ //# sourceMappingURL=brainy.js.map