@soulcraft/brainy 3.0.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 (260) hide show
  1. package/CHANGELOG.md +53 -3
  2. package/README.md +353 -110
  3. package/bin/brainy.js +340 -62
  4. package/dist/api/ConfigAPI.d.ts +67 -0
  5. package/dist/api/ConfigAPI.js +166 -0
  6. package/dist/api/DataAPI.d.ts +123 -0
  7. package/dist/api/DataAPI.js +391 -0
  8. package/dist/api/SecurityAPI.d.ts +50 -0
  9. package/dist/api/SecurityAPI.js +139 -0
  10. package/dist/api/UniversalImportAPI.d.ts +134 -0
  11. package/dist/api/UniversalImportAPI.js +615 -0
  12. package/dist/augmentationManager.js +12 -7
  13. package/dist/augmentationPipeline.d.ts +0 -61
  14. package/dist/augmentationPipeline.js +0 -87
  15. package/dist/augmentationRegistry.d.ts +1 -1
  16. package/dist/augmentationRegistry.js +1 -1
  17. package/dist/augmentations/apiServerAugmentation.d.ts +27 -1
  18. package/dist/augmentations/apiServerAugmentation.js +290 -9
  19. package/dist/augmentations/auditLogAugmentation.d.ts +109 -0
  20. package/dist/augmentations/auditLogAugmentation.js +358 -0
  21. package/dist/augmentations/batchProcessingAugmentation.d.ts +3 -2
  22. package/dist/augmentations/batchProcessingAugmentation.js +123 -22
  23. package/dist/augmentations/brainyAugmentation.d.ts +142 -8
  24. package/dist/augmentations/brainyAugmentation.js +179 -2
  25. package/dist/augmentations/cacheAugmentation.d.ts +8 -5
  26. package/dist/augmentations/cacheAugmentation.js +116 -17
  27. package/dist/augmentations/conduitAugmentations.d.ts +2 -2
  28. package/dist/augmentations/conduitAugmentations.js +2 -2
  29. package/dist/augmentations/configResolver.d.ts +122 -0
  30. package/dist/augmentations/configResolver.js +440 -0
  31. package/dist/augmentations/connectionPoolAugmentation.d.ts +3 -1
  32. package/dist/augmentations/connectionPoolAugmentation.js +37 -12
  33. package/dist/augmentations/defaultAugmentations.d.ts +14 -10
  34. package/dist/augmentations/defaultAugmentations.js +16 -11
  35. package/dist/augmentations/discovery/catalogDiscovery.d.ts +142 -0
  36. package/dist/augmentations/discovery/catalogDiscovery.js +249 -0
  37. package/dist/augmentations/discovery/localDiscovery.d.ts +84 -0
  38. package/dist/augmentations/discovery/localDiscovery.js +246 -0
  39. package/dist/augmentations/discovery/runtimeLoader.d.ts +97 -0
  40. package/dist/augmentations/discovery/runtimeLoader.js +337 -0
  41. package/dist/augmentations/discovery.d.ts +152 -0
  42. package/dist/augmentations/discovery.js +441 -0
  43. package/dist/augmentations/display/cache.d.ts +130 -0
  44. package/dist/augmentations/display/cache.js +319 -0
  45. package/dist/augmentations/display/fieldPatterns.d.ts +52 -0
  46. package/dist/augmentations/display/fieldPatterns.js +393 -0
  47. package/dist/augmentations/display/iconMappings.d.ts +57 -0
  48. package/dist/augmentations/display/iconMappings.js +68 -0
  49. package/dist/augmentations/display/intelligentComputation.d.ts +109 -0
  50. package/dist/augmentations/display/intelligentComputation.js +462 -0
  51. package/dist/augmentations/display/types.d.ts +203 -0
  52. package/dist/augmentations/display/types.js +7 -0
  53. package/dist/augmentations/entityRegistryAugmentation.d.ts +3 -1
  54. package/dist/augmentations/entityRegistryAugmentation.js +5 -1
  55. package/dist/augmentations/indexAugmentation.d.ts +5 -3
  56. package/dist/augmentations/indexAugmentation.js +5 -2
  57. package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +24 -7
  58. package/dist/augmentations/intelligentVerbScoringAugmentation.js +111 -27
  59. package/dist/augmentations/manifest.d.ts +176 -0
  60. package/dist/augmentations/manifest.js +8 -0
  61. package/dist/augmentations/marketplace/AugmentationMarketplace.d.ts +168 -0
  62. package/dist/augmentations/marketplace/AugmentationMarketplace.js +329 -0
  63. package/dist/augmentations/marketplace/cli.d.ts +47 -0
  64. package/dist/augmentations/marketplace/cli.js +265 -0
  65. package/dist/augmentations/metricsAugmentation.d.ts +3 -3
  66. package/dist/augmentations/metricsAugmentation.js +2 -2
  67. package/dist/augmentations/monitoringAugmentation.d.ts +3 -3
  68. package/dist/augmentations/monitoringAugmentation.js +2 -2
  69. package/dist/augmentations/neuralImport.d.ts +1 -1
  70. package/dist/augmentations/neuralImport.js +4 -4
  71. package/dist/augmentations/rateLimitAugmentation.d.ts +82 -0
  72. package/dist/augmentations/rateLimitAugmentation.js +321 -0
  73. package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +2 -2
  74. package/dist/augmentations/requestDeduplicatorAugmentation.js +1 -1
  75. package/dist/augmentations/storageAugmentation.d.ts +1 -1
  76. package/dist/augmentations/storageAugmentation.js +2 -2
  77. package/dist/augmentations/storageAugmentations.d.ts +37 -8
  78. package/dist/augmentations/storageAugmentations.js +204 -15
  79. package/dist/augmentations/synapseAugmentation.d.ts +1 -1
  80. package/dist/augmentations/synapseAugmentation.js +35 -16
  81. package/dist/augmentations/typeMatching/brainyTypes.d.ts +83 -0
  82. package/dist/augmentations/typeMatching/brainyTypes.js +425 -0
  83. package/dist/augmentations/typeMatching/intelligentTypeMatcher.d.ts +39 -59
  84. package/dist/augmentations/typeMatching/intelligentTypeMatcher.js +103 -389
  85. package/dist/augmentations/universalDisplayAugmentation.d.ts +191 -0
  86. package/dist/augmentations/universalDisplayAugmentation.js +371 -0
  87. package/dist/brainy-unified.d.ts +106 -0
  88. package/dist/brainy-unified.js +327 -0
  89. package/dist/brainy.d.ts +273 -0
  90. package/dist/brainy.js +1181 -0
  91. package/dist/brainyData.d.ts +56 -111
  92. package/dist/brainyData.js +912 -756
  93. package/dist/brainyDataV3.d.ts +186 -0
  94. package/dist/brainyDataV3.js +337 -0
  95. package/dist/browserFramework.d.ts +6 -6
  96. package/dist/browserFramework.js +11 -8
  97. package/dist/browserFramework.minimal.d.ts +5 -5
  98. package/dist/browserFramework.minimal.js +11 -8
  99. package/dist/config/distributedPresets-new.d.ts +118 -0
  100. package/dist/config/distributedPresets-new.js +318 -0
  101. package/dist/config/distributedPresets.d.ts +118 -0
  102. package/dist/config/distributedPresets.js +318 -0
  103. package/dist/config/extensibleConfig.d.ts +99 -0
  104. package/dist/config/extensibleConfig.js +268 -0
  105. package/dist/config/index.d.ts +17 -0
  106. package/dist/config/index.js +35 -0
  107. package/dist/config/modelAutoConfig.d.ts +32 -0
  108. package/dist/config/modelAutoConfig.js +139 -0
  109. package/dist/config/modelPrecisionManager.d.ts +42 -0
  110. package/dist/config/modelPrecisionManager.js +98 -0
  111. package/dist/config/sharedConfigManager.d.ts +67 -0
  112. package/dist/config/sharedConfigManager.js +215 -0
  113. package/dist/config/storageAutoConfig.d.ts +41 -0
  114. package/dist/config/storageAutoConfig.js +328 -0
  115. package/dist/config/zeroConfig.d.ts +68 -0
  116. package/dist/config/zeroConfig.js +301 -0
  117. package/dist/cortex/backupRestore.d.ts +2 -2
  118. package/dist/cortex/backupRestore.js +85 -27
  119. package/dist/cortex/healthCheck.d.ts +2 -2
  120. package/dist/cortex/neuralImport.d.ts +2 -2
  121. package/dist/cortex/neuralImport.js +18 -13
  122. package/dist/cortex/performanceMonitor.d.ts +2 -2
  123. package/dist/critical/model-guardian.d.ts +4 -0
  124. package/dist/critical/model-guardian.js +31 -11
  125. package/dist/demo.d.ts +4 -4
  126. package/dist/demo.js +7 -7
  127. package/dist/distributed/cacheSync.d.ts +112 -0
  128. package/dist/distributed/cacheSync.js +265 -0
  129. package/dist/distributed/coordinator.d.ts +193 -0
  130. package/dist/distributed/coordinator.js +548 -0
  131. package/dist/distributed/httpTransport.d.ts +120 -0
  132. package/dist/distributed/httpTransport.js +446 -0
  133. package/dist/distributed/index.d.ts +8 -0
  134. package/dist/distributed/index.js +5 -0
  135. package/dist/distributed/networkTransport.d.ts +132 -0
  136. package/dist/distributed/networkTransport.js +633 -0
  137. package/dist/distributed/queryPlanner.d.ts +104 -0
  138. package/dist/distributed/queryPlanner.js +327 -0
  139. package/dist/distributed/readWriteSeparation.d.ts +134 -0
  140. package/dist/distributed/readWriteSeparation.js +350 -0
  141. package/dist/distributed/shardManager.d.ts +114 -0
  142. package/dist/distributed/shardManager.js +357 -0
  143. package/dist/distributed/shardMigration.d.ts +110 -0
  144. package/dist/distributed/shardMigration.js +289 -0
  145. package/dist/distributed/storageDiscovery.d.ts +160 -0
  146. package/dist/distributed/storageDiscovery.js +551 -0
  147. package/dist/embeddings/CachedEmbeddings.d.ts +40 -0
  148. package/dist/embeddings/CachedEmbeddings.js +146 -0
  149. package/dist/embeddings/EmbeddingManager.d.ts +102 -0
  150. package/dist/embeddings/EmbeddingManager.js +291 -0
  151. package/dist/embeddings/SingletonModelManager.d.ts +95 -0
  152. package/dist/embeddings/SingletonModelManager.js +220 -0
  153. package/dist/embeddings/index.d.ts +12 -0
  154. package/dist/embeddings/index.js +16 -0
  155. package/dist/embeddings/lightweight-embedder.d.ts +0 -1
  156. package/dist/embeddings/lightweight-embedder.js +4 -12
  157. package/dist/embeddings/model-manager.d.ts +11 -0
  158. package/dist/embeddings/model-manager.js +43 -7
  159. package/dist/embeddings/universal-memory-manager.d.ts +1 -1
  160. package/dist/embeddings/universal-memory-manager.js +27 -67
  161. package/dist/embeddings/worker-embedding.js +4 -8
  162. package/dist/errors/brainyError.d.ts +5 -1
  163. package/dist/errors/brainyError.js +12 -0
  164. package/dist/examples/basicUsage.js +7 -4
  165. package/dist/graph/graphAdjacencyIndex.d.ts +96 -0
  166. package/dist/graph/graphAdjacencyIndex.js +288 -0
  167. package/dist/graph/pathfinding.js +4 -2
  168. package/dist/hnsw/scaledHNSWSystem.js +11 -2
  169. package/dist/importManager.js +8 -5
  170. package/dist/index.d.ts +17 -22
  171. package/dist/index.js +37 -23
  172. package/dist/mcp/brainyMCPAdapter.d.ts +4 -4
  173. package/dist/mcp/brainyMCPAdapter.js +5 -5
  174. package/dist/mcp/brainyMCPService.d.ts +3 -3
  175. package/dist/mcp/brainyMCPService.js +3 -11
  176. package/dist/mcp/mcpAugmentationToolset.js +20 -30
  177. package/dist/neural/embeddedPatterns.d.ts +1 -1
  178. package/dist/neural/embeddedPatterns.js +2 -2
  179. package/dist/neural/entityExtractor.d.ts +65 -0
  180. package/dist/neural/entityExtractor.js +316 -0
  181. package/dist/neural/improvedNeuralAPI.d.ts +357 -0
  182. package/dist/neural/improvedNeuralAPI.js +2628 -0
  183. package/dist/neural/naturalLanguageProcessor.d.ts +155 -10
  184. package/dist/neural/naturalLanguageProcessor.js +941 -66
  185. package/dist/neural/naturalLanguageProcessorStatic.d.ts +2 -2
  186. package/dist/neural/naturalLanguageProcessorStatic.js +3 -3
  187. package/dist/neural/neuralAPI.js +8 -2
  188. package/dist/neural/patternLibrary.d.ts +57 -3
  189. package/dist/neural/patternLibrary.js +348 -13
  190. package/dist/neural/staticPatternMatcher.d.ts +2 -2
  191. package/dist/neural/staticPatternMatcher.js +2 -2
  192. package/dist/neural/types.d.ts +287 -0
  193. package/dist/neural/types.js +24 -0
  194. package/dist/shared/default-augmentations.d.ts +3 -3
  195. package/dist/shared/default-augmentations.js +5 -5
  196. package/dist/storage/adapters/baseStorageAdapter.d.ts +42 -0
  197. package/dist/storage/adapters/fileSystemStorage.d.ts +26 -2
  198. package/dist/storage/adapters/fileSystemStorage.js +218 -15
  199. package/dist/storage/adapters/memoryStorage.d.ts +4 -4
  200. package/dist/storage/adapters/memoryStorage.js +17 -12
  201. package/dist/storage/adapters/opfsStorage.d.ts +2 -2
  202. package/dist/storage/adapters/opfsStorage.js +2 -2
  203. package/dist/storage/adapters/s3CompatibleStorage.d.ts +2 -2
  204. package/dist/storage/adapters/s3CompatibleStorage.js +2 -2
  205. package/dist/storage/backwardCompatibility.d.ts +10 -78
  206. package/dist/storage/backwardCompatibility.js +17 -132
  207. package/dist/storage/baseStorage.d.ts +18 -2
  208. package/dist/storage/baseStorage.js +74 -3
  209. package/dist/storage/cacheManager.js +2 -2
  210. package/dist/storage/readOnlyOptimizations.js +8 -3
  211. package/dist/streaming/pipeline.d.ts +154 -0
  212. package/dist/streaming/pipeline.js +551 -0
  213. package/dist/triple/TripleIntelligence.d.ts +25 -110
  214. package/dist/triple/TripleIntelligence.js +4 -574
  215. package/dist/triple/TripleIntelligenceSystem.d.ts +159 -0
  216. package/dist/triple/TripleIntelligenceSystem.js +519 -0
  217. package/dist/types/apiTypes.d.ts +278 -0
  218. package/dist/types/apiTypes.js +33 -0
  219. package/dist/types/brainy.types.d.ts +308 -0
  220. package/dist/types/brainy.types.js +8 -0
  221. package/dist/types/brainyDataInterface.d.ts +5 -8
  222. package/dist/types/brainyDataInterface.js +2 -2
  223. package/dist/types/graphTypes.js +2 -2
  224. package/dist/utils/brainyTypes.d.ts +217 -0
  225. package/dist/utils/brainyTypes.js +261 -0
  226. package/dist/utils/cacheAutoConfig.d.ts +3 -3
  227. package/dist/utils/embedding.d.ts +9 -4
  228. package/dist/utils/embedding.js +89 -26
  229. package/dist/utils/enhancedLogger.d.ts +104 -0
  230. package/dist/utils/enhancedLogger.js +232 -0
  231. package/dist/utils/hybridModelManager.d.ts +19 -28
  232. package/dist/utils/hybridModelManager.js +36 -200
  233. package/dist/utils/index.d.ts +1 -1
  234. package/dist/utils/index.js +1 -1
  235. package/dist/utils/intelligentTypeMapper.d.ts +60 -0
  236. package/dist/utils/intelligentTypeMapper.js +349 -0
  237. package/dist/utils/metadataIndex.d.ts +118 -1
  238. package/dist/utils/metadataIndex.js +539 -16
  239. package/dist/utils/nodeVersionCheck.d.ts +24 -0
  240. package/dist/utils/nodeVersionCheck.js +65 -0
  241. package/dist/utils/paramValidation.d.ts +39 -0
  242. package/dist/utils/paramValidation.js +192 -0
  243. package/dist/utils/rateLimiter.d.ts +160 -0
  244. package/dist/utils/rateLimiter.js +271 -0
  245. package/dist/utils/statistics.d.ts +4 -4
  246. package/dist/utils/statistics.js +3 -3
  247. package/dist/utils/structuredLogger.d.ts +146 -0
  248. package/dist/utils/structuredLogger.js +394 -0
  249. package/dist/utils/textEncoding.js +2 -1
  250. package/dist/utils/typeValidation.d.ts +59 -0
  251. package/dist/utils/typeValidation.js +374 -0
  252. package/dist/utils/version.js +19 -3
  253. package/package.json +15 -4
  254. package/scripts/download-models.cjs +94 -20
  255. package/dist/augmentations/walAugmentation.d.ts +0 -109
  256. package/dist/augmentations/walAugmentation.js +0 -516
  257. package/dist/chat/BrainyChat.d.ts +0 -121
  258. package/dist/chat/BrainyChat.js +0 -396
  259. package/dist/chat/ChatCLI.d.ts +0 -61
  260. package/dist/chat/ChatCLI.js +0 -351
@@ -8,14 +8,15 @@ import { HNSWIndexOptimized } from './hnsw/hnswIndexOptimized.js';
8
8
  import { cosineDistance, defaultEmbeddingFunction, cleanupWorkerPools, batchEmbed } from './utils/index.js';
9
9
  import { getAugmentationVersion } from './utils/version.js';
10
10
  import { matchesMetadataFilter } from './utils/metadataFilter.js';
11
+ import { enforceNodeVersion } from './utils/nodeVersionCheck.js';
11
12
  import { createNamespacedMetadata, updateNamespacedMetadata, markDeleted, markRestored, isDeleted, getUserMetadata } from './utils/metadataNamespace.js';
12
13
  import { PeriodicCleanup } from './utils/periodicCleanup.js';
13
14
  import { NounType, VerbType } from './types/graphTypes.js';
14
- import { createServerSearchAugmentations } from './augmentations/serverSearchAugmentations.js';
15
- import { augmentationPipeline } from './augmentationPipeline.js';
15
+ import { validateNounType, validateSearchQuery, validateSearchOptions, validateDataInput } from './utils/typeValidation.js';
16
+ import { BrainyError } from './errors/brainyError.js';
16
17
  import { prodLog } from './utils/logger.js';
17
18
  import { prepareJsonForVectorization, extractFieldFromJson } from './utils/jsonProcessing.js';
18
- import { DistributedConfigManager, HashPartitioner, OperationalModeFactory, DomainDetector } from './distributed/index.js';
19
+ import { DistributedConfigManager, HashPartitioner, OperationalModeFactory, DomainDetector, DistributedCoordinator, ShardManager, CacheSync, ReadWriteSeparation } from './distributed/index.js';
19
20
  import { CacheAutoConfigurator } from './utils/cacheAutoConfig.js';
20
21
  import { RequestDeduplicator } from './utils/requestDeduplicator.js';
21
22
  import { AugmentationRegistry } from './augmentations/brainyAugmentation.js';
@@ -27,10 +28,8 @@ import { EntityRegistryAugmentation, AutoRegisterEntitiesAugmentation } from './
27
28
  import { createDefaultAugmentations } from './augmentations/defaultAugmentations.js';
28
29
  // import { RealtimeStreamingAugmentation } from './augmentations/realtimeStreamingAugmentation.js'
29
30
  import { IntelligentVerbScoringAugmentation } from './augmentations/intelligentVerbScoringAugmentation.js';
30
- import { NeuralAPI } from './neural/neuralAPI.js';
31
- import { TripleIntelligenceEngine } from './triple/TripleIntelligence.js';
31
+ import { ImprovedNeuralAPI } from './neural/improvedNeuralAPI.js';
32
32
  export class BrainyData {
33
- // REMOVED: HealthMonitor is now handled by MonitoringAugmentation
34
33
  // Statistics collector
35
34
  // REMOVED: StatisticsCollector is now handled by MetricsAugmentation
36
35
  // Clean augmentation accessors for internal use
@@ -52,6 +51,11 @@ export class BrainyData {
52
51
  get monitoring() {
53
52
  return this.augmentations.get('monitoring');
54
53
  }
54
+ // ================================================================
55
+ // SECTION 1: CONFIGURATION & PROPERTIES
56
+ // ================================================================
57
+ // Configuration getters, dimensions, and system properties
58
+ // These provide access to core system configuration and status
55
59
  /**
56
60
  * Get the vector dimensions
57
61
  */
@@ -78,8 +82,15 @@ export class BrainyData {
78
82
  get initialized() {
79
83
  return this.isInitialized;
80
84
  }
85
+ // ================================================================
86
+ // SECTION 2: CONSTRUCTOR & INITIALIZATION
87
+ // ================================================================
88
+ // Constructor, initialization logic, and system setup
89
+ // Handles zero-config setup and system bootstrapping
81
90
  /**
82
91
  * Create a new vector database
92
+ * @param config - Zero-config string ('production', 'development', 'minimal'),
93
+ * simplified config object, or legacy full config
83
94
  */
84
95
  constructor(config = {}) {
85
96
  this.storage = null;
@@ -123,72 +134,96 @@ export class BrainyData {
123
134
  this.partitioner = null;
124
135
  this.operationalMode = null;
125
136
  this.domainDetector = null;
126
- // Store config
127
- this.config = config;
137
+ // REMOVED: HealthMonitor is now handled by MonitoringAugmentation
138
+ // New distributed components for 3.0
139
+ this.networkTransport = null;
140
+ this.coordinator = null;
141
+ this.shardManager = null;
142
+ this.cacheSync = null;
143
+ this.readWriteSeparation = null;
144
+ this.httpTransport = null; // HTTPTransport from dynamic import
145
+ this.storageDiscovery = null; // StorageDiscovery from dynamic import
146
+ this.queryPlanner = null; // DistributedQueryPlanner from dynamic import
147
+ this.shardMigrationManager = null; // ShardMigrationManager from dynamic import
148
+ // Enforce Node.js version requirement for ONNX stability
149
+ if (typeof process !== 'undefined' && process.version && !process.env.BRAINY_SKIP_VERSION_CHECK) {
150
+ enforceNodeVersion();
151
+ }
152
+ // Store raw config for processing in init()
153
+ this.rawConfig = config;
154
+ // For now, process as legacy config if it's an object
155
+ // The actual zero-config processing will happen in init() since it's async
156
+ if (typeof config === 'object') {
157
+ this.config = config;
158
+ }
159
+ else {
160
+ // String preset or simplified config - use minimal defaults for now
161
+ this.config = {};
162
+ }
128
163
  // Set dimensions to fixed value of 384 (all-MiniLM-L6-v2 dimension)
129
164
  this._dimensions = 384;
130
165
  // Set distance function
131
- this.distanceFunction = config.distanceFunction || cosineDistance;
166
+ this.distanceFunction = this.config.distanceFunction || cosineDistance;
132
167
  // Always use the optimized HNSW index implementation
133
168
  // Configure HNSW with disk-based storage when a storage adapter is provided
134
- const hnswConfig = config.hnsw || {};
135
- if (config.storageAdapter) {
169
+ const hnswConfig = this.config.hnsw || {};
170
+ if (this.config.storageAdapter) {
136
171
  hnswConfig.useDiskBasedIndex = true;
137
172
  }
138
173
  // Temporarily use base HNSW index for metadata filtering
139
174
  this.hnswIndex = new HNSWIndex(hnswConfig, this.distanceFunction);
140
175
  this.useOptimizedIndex = false;
141
176
  // Set storage if provided, otherwise it will be initialized in init()
142
- this.storage = config.storageAdapter || null;
177
+ this.storage = this.config.storageAdapter || null;
143
178
  // Store logging configuration
144
- if (config.logging !== undefined) {
179
+ if (this.config.logging !== undefined) {
145
180
  this.loggingConfig = {
146
181
  ...this.loggingConfig,
147
- ...config.logging
182
+ ...this.config.logging
148
183
  };
149
184
  }
150
185
  // Set embedding function if provided, otherwise create one with the appropriate verbose setting
151
- if (config.embeddingFunction) {
152
- this.embeddingFunction = config.embeddingFunction;
186
+ if (this.config.embeddingFunction) {
187
+ this.embeddingFunction = this.config.embeddingFunction;
153
188
  }
154
189
  else {
155
190
  this.embeddingFunction = defaultEmbeddingFunction;
156
191
  }
157
192
  // Set persistent storage request flag
158
193
  this.requestPersistentStorage =
159
- config.storage?.requestPersistentStorage || false;
194
+ this.config.storage?.requestPersistentStorage || false;
160
195
  // Set read-only flag
161
- this.readOnly = config.readOnly || false;
196
+ this.readOnly = this.config.readOnly || false;
162
197
  // Set frozen flag (defaults to false to allow optimizations in readOnly mode)
163
- this.frozen = config.frozen || false;
198
+ this.frozen = this.config.frozen || false;
164
199
  // Set lazy loading in read-only mode flag
165
- this.lazyLoadInReadOnlyMode = config.lazyLoadInReadOnlyMode || false;
200
+ this.lazyLoadInReadOnlyMode = this.config.lazyLoadInReadOnlyMode || false;
166
201
  // Set write-only flag
167
- this.writeOnly = config.writeOnly || false;
202
+ this.writeOnly = this.config.writeOnly || false;
168
203
  // Set allowDirectReads flag
169
- this.allowDirectReads = config.allowDirectReads || false;
204
+ this.allowDirectReads = this.config.allowDirectReads || false;
170
205
  // Validate that readOnly and writeOnly are not both true
171
206
  if (this.readOnly && this.writeOnly) {
172
207
  throw new Error('Database cannot be both read-only and write-only');
173
208
  }
174
209
  // Set default service name if provided
175
- if (config.defaultService) {
176
- this.defaultService = config.defaultService;
210
+ if (this.config.defaultService) {
211
+ this.defaultService = this.config.defaultService;
177
212
  }
178
213
  // Store storage configuration for later use in init()
179
- this.storageConfig = config.storage || {};
214
+ this.storageConfig = this.config.storage || {};
180
215
  // Store timeout and retry configuration
181
- this.timeoutConfig = config.timeouts || {};
182
- this.retryConfig = config.retryPolicy || {};
216
+ this.timeoutConfig = this.config.timeouts || {};
217
+ this.retryConfig = this.config.retryPolicy || {};
183
218
  // Store remote server configuration if provided
184
- if (config.remoteServer) {
185
- this.remoteServerConfig = config.remoteServer;
219
+ if (this.config.remoteServer) {
220
+ this.remoteServerConfig = this.config.remoteServer;
186
221
  }
187
222
  // Initialize real-time update configuration if provided
188
- if (config.realtimeUpdates) {
223
+ if (this.config.realtimeUpdates) {
189
224
  this.realtimeUpdateConfig = {
190
225
  ...this.realtimeUpdateConfig,
191
- ...config.realtimeUpdates
226
+ ...this.config.realtimeUpdates
192
227
  };
193
228
  }
194
229
  // Initialize cache configuration with intelligent defaults
@@ -206,15 +241,15 @@ export class BrainyData {
206
241
  }
207
242
  };
208
243
  // Override defaults with user-provided configuration if available
209
- if (config.cache) {
244
+ if (this.config.cache) {
210
245
  this.cacheConfig = {
211
246
  ...this.cacheConfig,
212
- ...config.cache
247
+ ...this.config.cache
213
248
  };
214
249
  }
215
250
  // Store distributed configuration
216
- if (config.distributed) {
217
- if (typeof config.distributed === 'boolean') {
251
+ if (this.config.distributed) {
252
+ if (typeof this.config.distributed === 'boolean') {
218
253
  // Auto-mode enabled
219
254
  this.distributedConfig = {
220
255
  enabled: true
@@ -222,7 +257,7 @@ export class BrainyData {
222
257
  }
223
258
  else {
224
259
  // Explicit configuration
225
- this.distributedConfig = config.distributed;
260
+ this.distributedConfig = this.config.distributed;
226
261
  }
227
262
  }
228
263
  // Initialize cache auto-configurator first
@@ -296,11 +331,11 @@ export class BrainyData {
296
331
  ttl: 5000,
297
332
  maxSize: 1000
298
333
  }));
299
- // Priority 10: Enhancement features
300
- const intelligentVerbAugmentation = new IntelligentVerbScoringAugmentation(this.config.intelligentVerbScoring || { enabled: false });
334
+ // Priority 10: Core relationship quality features
335
+ const intelligentVerbAugmentation = new IntelligentVerbScoringAugmentation(this.config.intelligentVerbScoring || { enabled: true });
301
336
  this.augmentations.register(intelligentVerbAugmentation);
302
- // Store reference if intelligent verb scoring is enabled
303
- if (this.config.intelligentVerbScoring?.enabled) {
337
+ // Store reference if intelligent verb scoring is enabled (enabled by default)
338
+ if (this.config.intelligentVerbScoring?.enabled !== false) {
304
339
  this.intelligentVerbScoring = intelligentVerbAugmentation.getScoring();
305
340
  }
306
341
  }
@@ -350,16 +385,28 @@ export class BrainyData {
350
385
  console.warn('Ignoring s3Storage configuration due to missing required fields');
351
386
  }
352
387
  }
353
- // Check if specific storage is configured
388
+ // Check if specific storage is configured (legacy and new formats)
354
389
  if (storageOptions.s3Storage || storageOptions.r2Storage ||
355
390
  storageOptions.gcsStorage || storageOptions.forceMemoryStorage ||
356
- storageOptions.forceFileSystemStorage) {
357
- // Create storage from config
358
- const { createStorage } = await import('./storage/storageFactory.js');
359
- this.storage = await createStorage(storageOptions);
360
- // Wrap in augmentation for consistency
361
- const wrapper = new DynamicStorageAugmentation(this.storage);
362
- this.augmentations.register(wrapper);
391
+ storageOptions.forceFileSystemStorage ||
392
+ typeof storageOptions === 'string') {
393
+ // Handle string storage types (new zero-config)
394
+ if (typeof storageOptions === 'string') {
395
+ const { createAutoStorageAugmentation } = await import('./augmentations/storageAugmentations.js');
396
+ // For now, use auto-detection - TODO: extend to support preferred types
397
+ const autoAug = await createAutoStorageAugmentation({
398
+ rootDirectory: './brainy-data'
399
+ });
400
+ this.augmentations.register(autoAug);
401
+ }
402
+ else {
403
+ // Legacy object config
404
+ const { createStorage } = await import('./storage/storageFactory.js');
405
+ this.storage = await createStorage(storageOptions);
406
+ // Wrap in augmentation for consistency
407
+ const wrapper = new DynamicStorageAugmentation(this.storage);
408
+ this.augmentations.register(wrapper);
409
+ }
363
410
  }
364
411
  else {
365
412
  // Zero-config: auto-select based on environment
@@ -376,7 +423,7 @@ export class BrainyData {
376
423
  await this.storage.init();
377
424
  }
378
425
  else {
379
- throw new Error('Failed to resolve storage');
426
+ throw BrainyError.storage('Failed to resolve storage');
380
427
  }
381
428
  }
382
429
  /**
@@ -410,7 +457,7 @@ export class BrainyData {
410
457
  */
411
458
  async initializePeriodicCleanup() {
412
459
  if (!this.storage) {
413
- throw new Error('Cannot initialize periodic cleanup: storage not available');
460
+ throw BrainyError.storage('Cannot initialize periodic cleanup: storage not available');
414
461
  }
415
462
  // Skip cleanup if in read-only or frozen mode
416
463
  if (this.readOnly || this.frozen) {
@@ -831,16 +878,12 @@ export class BrainyData {
831
878
  */
832
879
  getCurrentAugmentation() {
833
880
  try {
834
- // Get all registered augmentations
835
- const augmentationTypes = augmentationPipeline.getAvailableAugmentationTypes();
836
- // Check each type of augmentation
837
- for (const type of augmentationTypes) {
838
- const augmentations = augmentationPipeline.getAugmentationsByType(type);
839
- // Find the first augmentation (all registered augmentations are considered enabled)
840
- for (const augmentation of augmentations) {
841
- if (augmentation) {
842
- return augmentation.name;
843
- }
881
+ // Get all registered augmentations from the new API
882
+ const allAugmentations = this.augmentations.getAll();
883
+ // Find the first enabled augmentation
884
+ for (const augmentation of allAugmentations) {
885
+ if (augmentation && augmentation.config?.enabled !== false) {
886
+ return augmentation.name;
844
887
  }
845
888
  }
846
889
  return 'default';
@@ -878,23 +921,38 @@ export class BrainyData {
878
921
  return;
879
922
  }
880
923
  this.isInitializing = true;
881
- // CRITICAL: Initialize universal memory manager ONLY for default embedding function
882
- // This preserves custom embedding functions (like test mocks)
883
- if (typeof this.embeddingFunction === 'function' && this.embeddingFunction === defaultEmbeddingFunction) {
924
+ // Process zero-config if needed
925
+ if (this.rawConfig !== undefined) {
884
926
  try {
885
- const { universalMemoryManager } = await import('./embeddings/universal-memory-manager.js');
886
- this.embeddingFunction = await universalMemoryManager.getEmbeddingFunction();
887
- console.log('✅ UNIVERSAL: Memory-safe embedding system initialized');
927
+ const { applyZeroConfig } = await import('./config/index.js');
928
+ const processedConfig = await applyZeroConfig(this.rawConfig);
929
+ // Apply processed config if it's different from raw
930
+ if (processedConfig !== this.rawConfig) {
931
+ // Log if verbose
932
+ if (processedConfig.logging?.verbose) {
933
+ console.log('🤖 Zero-config applied successfully');
934
+ }
935
+ // Update config with processed values
936
+ this.config = processedConfig;
937
+ // Update relevant properties from processed config
938
+ this.storageConfig = processedConfig.storage || {};
939
+ this.loggingConfig = processedConfig.logging || { verbose: false };
940
+ // Update embedding function if precision was specified
941
+ if (processedConfig.embeddingOptions?.precision) {
942
+ const { createEmbeddingFunctionWithPrecision } = await import('./config/index.js');
943
+ this.embeddingFunction = await createEmbeddingFunctionWithPrecision(processedConfig.embeddingOptions.precision);
944
+ }
945
+ }
888
946
  }
889
947
  catch (error) {
890
- console.error('🚨 CRITICAL: Universal memory manager initialization failed!');
891
- console.error('Falling back to standard embedding with potential memory issues.');
892
- console.warn('Consider reducing usage or restarting process periodically.');
893
- // Continue with default function - better than crashing
948
+ console.warn('Zero-config processing failed, using defaults:', error);
949
+ // Continue with existing config
894
950
  }
895
951
  }
896
- else if (this.embeddingFunction !== defaultEmbeddingFunction) {
897
- console.log('✅ CUSTOM: Using custom embedding function (test or production override)');
952
+ // The embedding function is already set (either custom or default)
953
+ // EmbeddingManager handles all initialization internally
954
+ if (this.embeddingFunction !== defaultEmbeddingFunction) {
955
+ console.log('✅ Using custom embedding function');
898
956
  }
899
957
  try {
900
958
  // Pre-load the embedding model early to ensure it's always available
@@ -984,16 +1042,6 @@ export class BrainyData {
984
1042
  offset += limit;
985
1043
  }
986
1044
  }
987
- // Connect to remote server if configured with autoConnect
988
- if (this.remoteServerConfig && this.remoteServerConfig.autoConnect) {
989
- try {
990
- await this.connectToRemoteServer(this.remoteServerConfig.url, this.remoteServerConfig.protocols);
991
- }
992
- catch (remoteError) {
993
- console.warn('Failed to auto-connect to remote server:', remoteError);
994
- // Continue initialization even if remote connection fails
995
- }
996
- }
997
1045
  // Initialize statistics collector with existing data
998
1046
  try {
999
1047
  const existingStats = await this.storage.getStatistics();
@@ -1102,6 +1150,8 @@ export class BrainyData {
1102
1150
  // Create operational mode based on role
1103
1151
  const role = this.configManager.getRole();
1104
1152
  this.operationalMode = OperationalModeFactory.createMode(role);
1153
+ // Initialize NEW distributed components for 3.0
1154
+ await this.initializeDistributedComponents(sharedConfig);
1105
1155
  // Validate that role matches the configured mode
1106
1156
  // Don't override explicitly set readOnly/writeOnly
1107
1157
  if (role === 'reader' && !this.readOnly) {
@@ -1162,473 +1212,316 @@ export class BrainyData {
1162
1212
  }
1163
1213
  }
1164
1214
  /**
1165
- * Get distributed health status
1166
- * @returns Health status if distributed mode is enabled
1215
+ * Initialize NEW distributed components for Brainy 3.0
1216
+ * This enables true multi-node operation with consensus and sharding
1217
+ */
1218
+ async initializeDistributedComponents(sharedConfig) {
1219
+ // Extract distributed configuration with type safety
1220
+ const distConfig = typeof this.distributedConfig === 'object' && this.distributedConfig !== null
1221
+ ? this.distributedConfig
1222
+ : {};
1223
+ // Generate or use node ID
1224
+ const nodeId = distConfig.instanceId || sharedConfig.nodeId ||
1225
+ `node-${Math.random().toString(36).substring(2, 11)}`;
1226
+ // Use zero-config discovery if storage is available
1227
+ if (this.storage && distConfig.useStorageDiscovery !== false) {
1228
+ // Use storage-based discovery for true zero-config
1229
+ const { StorageDiscovery } = await import('./distributed/storageDiscovery.js');
1230
+ this.storageDiscovery = new StorageDiscovery(this.storage, nodeId);
1231
+ // Start discovery and join cluster
1232
+ const port = distConfig.port || 0; // 0 = auto-detect
1233
+ const cluster = await this.storageDiscovery.start(port);
1234
+ // Use discovered nodes as seeds
1235
+ distConfig.peers = cluster.nodes.map((n) => `${n.address}:${n.port}`);
1236
+ }
1237
+ // Initialize HTTP transport (replaces NetworkTransport)
1238
+ const { HTTPTransport } = await import('./distributed/httpTransport.js');
1239
+ this.httpTransport = new HTTPTransport(nodeId);
1240
+ // Start HTTP transport
1241
+ const actualPort = await this.httpTransport.start();
1242
+ console.log(`[${nodeId}] HTTP transport listening on port ${actualPort}`);
1243
+ // Initialize coordinator for consensus
1244
+ this.coordinator = new DistributedCoordinator({
1245
+ nodeId,
1246
+ heartbeatInterval: distConfig.heartbeatInterval || 1000,
1247
+ electionTimeout: distConfig.electionTimeout || 5000,
1248
+ nodes: distConfig.peers || []
1249
+ });
1250
+ // Start coordinator with HTTP transport adapter
1251
+ const transportAdapter = {
1252
+ send: (nodeId, message) => this.httpTransport.call(nodeId, 'coordinator', message),
1253
+ broadcast: (message) => this.httpTransport.broadcast('coordinator', message),
1254
+ on: (event, handler) => {
1255
+ // Register handler for coordinator messages
1256
+ if (event === 'message') {
1257
+ this.httpTransport.registerHandler('coordinator', handler);
1258
+ }
1259
+ }
1260
+ };
1261
+ await this.coordinator.start(transportAdapter);
1262
+ // Initialize shard manager
1263
+ this.shardManager = new ShardManager({
1264
+ shardCount: distConfig.shardCount || 8,
1265
+ replicationFactor: distConfig.replicationFactor || 3,
1266
+ virtualNodes: distConfig.virtualNodes || 100,
1267
+ autoRebalance: distConfig.autoRebalance !== false
1268
+ });
1269
+ // Initialize cache synchronization
1270
+ this.cacheSync = new CacheSync({
1271
+ nodeId,
1272
+ syncInterval: distConfig.syncInterval || 5000
1273
+ });
1274
+ // Initialize read/write separation
1275
+ // Note: This requires all components to be initialized
1276
+ this.readWriteSeparation = new ReadWriteSeparation({
1277
+ nodeId,
1278
+ role: this.readOnly ? 'replica' : this.writeOnly ? 'primary' : 'auto',
1279
+ primaryUrl: distConfig.primaryUrl || '',
1280
+ replicaUrls: distConfig.replicaUrls || [],
1281
+ syncInterval: distConfig.syncInterval || 5000,
1282
+ readPreference: distConfig.readPreference || 'nearest',
1283
+ consistencyLevel: distConfig.consistencyLevel || 'eventual'
1284
+ }, this.coordinator, this.shardManager, this.cacheSync);
1285
+ // Initialize query planner for distributed queries
1286
+ const { DistributedQueryPlanner } = await import('./distributed/queryPlanner.js');
1287
+ this.queryPlanner = new DistributedQueryPlanner(nodeId, this.coordinator, this.shardManager, this.httpTransport, this.storage, this._tripleEngine);
1288
+ // Set up coordinator event handlers
1289
+ this.coordinator.on('leaderElected', (leaderId) => {
1290
+ if (leaderId === nodeId) {
1291
+ console.log(`[${nodeId}] Became the leader`);
1292
+ // Update read/write separation if needed
1293
+ if (this.readWriteSeparation) {
1294
+ this.readWriteSeparation.setPrimary(true);
1295
+ }
1296
+ }
1297
+ else {
1298
+ console.log(`[${nodeId}] Following leader: ${leaderId}`);
1299
+ if (this.readWriteSeparation) {
1300
+ this.readWriteSeparation.setPrimary(false);
1301
+ }
1302
+ }
1303
+ });
1304
+ // Set up distributed operation handlers
1305
+ this.setupDistributedOperations();
1306
+ if (this.loggingConfig?.verbose) {
1307
+ console.log(`[${nodeId}] Distributed components initialized`);
1308
+ console.log(`- Network: ${this.networkTransport ? 'Ready' : 'Not initialized'}`);
1309
+ console.log(`- Coordinator: ${this.coordinator.getState().state}`);
1310
+ console.log(`- Shards: ${this.shardManager.getTotalShards()} total`);
1311
+ }
1312
+ }
1313
+ /**
1314
+ * Execute a query on local shards
1167
1315
  */
1168
- getHealthStatus() {
1169
- return this.monitoring?.getHealthStatus() || null;
1316
+ async executeLocalQuery(query, shards) {
1317
+ // For now, just do a regular find
1318
+ // In production, this would filter by shard assignments
1319
+ const results = await this.find(query.text || query.query, query.k || 10);
1320
+ return results;
1170
1321
  }
1171
1322
  /**
1172
- * Connect to a remote Brainy server for search operations
1173
- * @param serverUrl WebSocket URL of the remote Brainy server
1174
- * @param protocols Optional WebSocket protocols to use
1175
- * @returns The connection object
1323
+ * Set up distributed operation handlers
1176
1324
  */
1177
- async connectToRemoteServer(serverUrl, protocols) {
1178
- await this.ensureInitialized();
1179
- try {
1180
- // Create server search augmentations
1181
- const { conduit, connection } = await createServerSearchAugmentations(serverUrl, {
1182
- protocols,
1183
- localDb: this
1325
+ setupDistributedOperations() {
1326
+ // Set up handlers for HTTP transport if available
1327
+ if (this.httpTransport) {
1328
+ // Handle distributed query requests
1329
+ this.httpTransport.registerHandler('query', async (data) => {
1330
+ const { query, shards } = data;
1331
+ try {
1332
+ // Execute query on specified shards
1333
+ const results = await this.executeLocalQuery(query, shards);
1334
+ return { success: true, results, count: results.length };
1335
+ }
1336
+ catch (error) {
1337
+ return { success: false, error: error.message };
1338
+ }
1339
+ });
1340
+ // Handle migration batch receives
1341
+ this.httpTransport.registerHandler('receiveMigrationBatch', async (data) => {
1342
+ if (this.shardMigrationManager) {
1343
+ await this.shardMigrationManager.receiveMigrationBatch(data);
1344
+ }
1345
+ return { success: true };
1346
+ });
1347
+ // Handle migration validation
1348
+ this.httpTransport.registerHandler('validateMigration', async (data) => {
1349
+ if (this.shardMigrationManager) {
1350
+ return await this.shardMigrationManager.validateMigration(data);
1351
+ }
1352
+ return { valid: false, error: 'No migration manager' };
1184
1353
  });
1185
- // TODO: Store conduit and connection (post-2.0.0 feature)
1186
- // this.serverSearchConduit = conduit
1187
- // this.serverConnection = connection
1188
- return connection;
1189
1354
  }
1190
- catch (error) {
1191
- console.error('Failed to connect to remote server:', error);
1192
- throw new Error(`Failed to connect to remote server: ${error}`);
1355
+ // Set up legacy NetworkTransport handlers if still used
1356
+ if (this.networkTransport) {
1357
+ const handlers = this.networkTransport.messageHandlers;
1358
+ // Handle distributed add requests
1359
+ handlers.set('DISTRIBUTED_ADD', async (msg) => {
1360
+ const { data, type, metadata } = msg.data;
1361
+ try {
1362
+ const id = await this.localAdd(data, type, metadata);
1363
+ return { success: true, id };
1364
+ }
1365
+ catch (error) {
1366
+ return { success: false, error: error.message };
1367
+ }
1368
+ });
1369
+ // Handle distributed find requests
1370
+ handlers.set('DISTRIBUTED_FIND', async (msg) => {
1371
+ const { query, shardId } = msg.data;
1372
+ try {
1373
+ const results = await this.localFind(query, shardId);
1374
+ return { success: true, results };
1375
+ }
1376
+ catch (error) {
1377
+ return { success: false, error: error.message };
1378
+ }
1379
+ });
1380
+ // Handle cache sync messages
1381
+ handlers.set('CACHE_SYNC', async (msg) => {
1382
+ if (this.cacheSync) {
1383
+ await this.cacheSync.handleSyncMessage(msg.data);
1384
+ }
1385
+ return { success: true };
1386
+ });
1193
1387
  }
1194
1388
  }
1195
1389
  /**
1196
- * Add data to the database with intelligent processing
1197
- *
1198
- * @param vectorOrData Vector or data to add
1199
- * @param metadata Optional metadata to associate with the data
1200
- * @param options Additional options for processing
1201
- * @returns The ID of the added data
1202
- *
1203
- * @example
1204
- * // Auto mode - intelligently decides processing
1205
- * await brainy.add("Customer feedback: Great product!")
1206
- *
1207
- * @example
1208
- * // Explicit literal mode for sensitive data
1209
- * await brainy.add("API_KEY=secret123", null, { process: 'literal' })
1210
- *
1211
- * @example
1212
- * // Force neural processing
1213
- * await brainy.add("John works at Acme Corp", null, { process: 'neural' })
1390
+ * Local add operation (without distribution)
1391
+ */
1392
+ async localAdd(data, type, metadata) {
1393
+ // Use the existing addNoun method but bypass distribution checks
1394
+ const tempDistributed = this.shardManager;
1395
+ this.shardManager = null; // Temporarily disable to prevent recursion
1396
+ try {
1397
+ const id = await this.addNoun(data, type, metadata);
1398
+ return id;
1399
+ }
1400
+ finally {
1401
+ this.shardManager = tempDistributed; // Restore
1402
+ }
1403
+ }
1404
+ /**
1405
+ * Local find operation (potentially for a specific shard)
1406
+ */
1407
+ async localFind(query, shardId) {
1408
+ // TODO: Implement shard-aware find
1409
+ // For now, just use regular find
1410
+ return this.find(query);
1411
+ }
1412
+ /**
1413
+ * Get distributed health status
1414
+ * @returns Health status if distributed mode is enabled
1415
+ */
1416
+ getHealthStatus() {
1417
+ return this.monitoring?.getHealthStatus() || null;
1418
+ }
1419
+ // REMOVED: addItem() - Use addNoun() instead (cleaner 2.0 API)
1420
+ // REMOVED: addToBoth() - Remote server functionality moved to post-2.0.0
1421
+ /**
1422
+ * Add multiple vectors or data items to the database
1423
+ * @param items Array of items to add
1424
+ * @param options Additional options
1425
+ * @returns Array of IDs for the added items
1426
+ */
1427
+ /**
1428
+ * Add multiple nouns in batch with required types
1429
+ * @param items Array of nouns to add (all must have types)
1430
+ * @param options Batch processing options
1431
+ * @returns Array of generated IDs
1214
1432
  */
1215
- async add(vectorOrData, metadata, options = {}) {
1433
+ async addNouns(items, options = {}) {
1216
1434
  await this.ensureInitialized();
1217
1435
  // Check if database is in read-only mode
1218
1436
  this.checkReadOnly();
1219
- // Validate input is not null or undefined
1220
- if (vectorOrData === null || vectorOrData === undefined) {
1221
- throw new Error('Input cannot be null or undefined');
1222
- }
1223
- try {
1224
- let vector;
1225
- // First validate if input is an array but contains non-numeric values
1226
- if (Array.isArray(vectorOrData)) {
1227
- for (let i = 0; i < vectorOrData.length; i++) {
1228
- if (typeof vectorOrData[i] !== 'number') {
1229
- throw new Error('Vector contains non-numeric values');
1230
- }
1231
- }
1232
- }
1233
- // Check if input is already a vector
1234
- if (Array.isArray(vectorOrData) && !options.forceEmbed) {
1235
- // Input is already a vector (and we've validated it contains only numbers)
1236
- vector = vectorOrData;
1437
+ // Validate all types upfront for better error handling
1438
+ const invalidItems = [];
1439
+ items.forEach((item, index) => {
1440
+ if (!item.nounType || typeof item.nounType !== 'string') {
1441
+ invalidItems.push(index);
1237
1442
  }
1238
1443
  else {
1239
- // Input needs to be vectorized
1444
+ // Validate the type is valid
1240
1445
  try {
1241
- // Check if input is a JSON object and process it specially
1242
- if (typeof vectorOrData === 'object' &&
1243
- vectorOrData !== null &&
1244
- !Array.isArray(vectorOrData)) {
1245
- // Process JSON object for better vectorization
1246
- const preparedText = prepareJsonForVectorization(vectorOrData, {
1247
- // Prioritize common name/title fields if they exist
1248
- priorityFields: [
1249
- 'name',
1250
- 'title',
1251
- 'company',
1252
- 'organization',
1253
- 'description',
1254
- 'summary'
1255
- ]
1256
- });
1257
- vector = await this.embeddingFunction(preparedText);
1258
- // IMPORTANT: When an object is passed as data and no metadata is provided,
1259
- // use the object AS the metadata too. This is expected behavior for the API.
1260
- // Users can pass either:
1261
- // 1. addNoun(string, metadata) - vectorize string, store metadata
1262
- // 2. addNoun(object) - vectorize object text, store object as metadata
1263
- // 3. addNoun(object, metadata) - vectorize object text, store provided metadata
1264
- if (!metadata) {
1265
- metadata = vectorOrData;
1266
- }
1267
- // Track field names for this JSON document
1268
- const service = this.getServiceName(options);
1269
- if (this.storage) {
1270
- await this.storage.trackFieldNames(vectorOrData, service);
1271
- }
1272
- }
1273
- else {
1274
- // Use standard embedding for non-JSON data
1275
- vector = await this.embeddingFunction(vectorOrData);
1276
- }
1446
+ validateNounType(item.nounType);
1277
1447
  }
1278
- catch (embedError) {
1279
- throw new Error(`Failed to vectorize data: ${embedError}`);
1448
+ catch (error) {
1449
+ invalidItems.push(index);
1280
1450
  }
1281
1451
  }
1282
- // Check if vector is defined
1283
- if (!vector) {
1284
- throw new Error('Vector is undefined or null');
1285
- }
1286
- // Validate vector dimensions
1287
- if (vector.length !== this._dimensions) {
1288
- throw new Error(`Vector dimension mismatch: expected ${this._dimensions}, got ${vector.length}`);
1289
- }
1290
- // Use ID from options if it exists, otherwise from metadata, otherwise generate a new UUID
1291
- const id = options.id ||
1292
- (metadata && typeof metadata === 'object' && 'id' in metadata
1293
- ? metadata.id
1294
- : uuidv4());
1295
- // Check for existing noun (both write-only and normal modes)
1296
- let existingNoun;
1297
- if (options.id) {
1298
- try {
1299
- if (this.writeOnly) {
1300
- // In write-only mode, check storage directly
1301
- existingNoun =
1302
- (await this.storage.getNoun(options.id)) ?? undefined;
1452
+ });
1453
+ if (invalidItems.length > 0) {
1454
+ throw new Error(`Type validation failed for ${invalidItems.length} items at indices: ${invalidItems.slice(0, 5).join(', ')}${invalidItems.length > 5 ? '...' : ''}\n` +
1455
+ 'All items must have valid noun types.\n' +
1456
+ 'Example: { vectorOrData: "data", nounType: NounType.Content, metadata: {...} }');
1457
+ }
1458
+ // Default concurrency to 4 if not specified
1459
+ const concurrency = options.concurrency || 4;
1460
+ // Default batch size to 50 if not specified
1461
+ const batchSize = options.batchSize || 50;
1462
+ try {
1463
+ // Process items in batches to control concurrency and memory usage
1464
+ const ids = [];
1465
+ const itemsToProcess = [...items]; // Create a copy to avoid modifying the original array
1466
+ while (itemsToProcess.length > 0) {
1467
+ // Take up to 'batchSize' items to process in a batch
1468
+ const batch = itemsToProcess.splice(0, batchSize);
1469
+ // Separate items that are already vectors from those that need embedding
1470
+ const vectorItems = [];
1471
+ const textItems = [];
1472
+ // Categorize items
1473
+ batch.forEach((item, index) => {
1474
+ if (Array.isArray(item.vectorOrData) &&
1475
+ item.vectorOrData.every((val) => typeof val === 'number') &&
1476
+ !options.forceEmbed) {
1477
+ // Item is already a vector
1478
+ vectorItems.push({
1479
+ vectorOrData: item.vectorOrData,
1480
+ nounType: item.nounType,
1481
+ metadata: item.metadata,
1482
+ index
1483
+ });
1303
1484
  }
1304
- else {
1305
- // In normal mode, check index first, then storage
1306
- existingNoun = this.index.getNouns().get(options.id);
1307
- if (!existingNoun) {
1308
- existingNoun =
1309
- (await this.storage.getNoun(options.id)) ?? undefined;
1310
- }
1485
+ else if (typeof item.vectorOrData === 'string') {
1486
+ // Item is text that needs embedding
1487
+ textItems.push({
1488
+ text: item.vectorOrData,
1489
+ nounType: item.nounType,
1490
+ metadata: item.metadata,
1491
+ index
1492
+ });
1311
1493
  }
1312
- if (existingNoun) {
1313
- // Check if existing noun is a placeholder
1314
- const existingMetadata = await this.storage.getMetadata(options.id);
1315
- const isPlaceholder = existingMetadata &&
1316
- typeof existingMetadata === 'object' &&
1317
- existingMetadata.isPlaceholder;
1318
- if (isPlaceholder) {
1319
- // Replace placeholder with real data
1320
- if (this.loggingConfig?.verbose) {
1321
- console.log(`Replacing placeholder noun ${options.id} with real data`);
1322
- }
1323
- }
1324
- else {
1325
- // Real noun already exists, update it
1326
- if (this.loggingConfig?.verbose) {
1327
- console.log(`Updating existing noun ${options.id}`);
1328
- }
1329
- }
1494
+ else {
1495
+ // For now, treat other types as text
1496
+ // In a more complete implementation, we might handle other types differently
1497
+ const textRepresentation = String(item.vectorOrData);
1498
+ textItems.push({
1499
+ text: textRepresentation,
1500
+ nounType: item.nounType,
1501
+ metadata: item.metadata,
1502
+ index
1503
+ });
1330
1504
  }
1505
+ });
1506
+ // Process vector items (already embedded)
1507
+ const vectorPromises = vectorItems.map((item) => this.addNoun(item.vectorOrData, item.nounType, item.metadata));
1508
+ // Process text items in a single batch embedding operation
1509
+ let textPromises = [];
1510
+ if (textItems.length > 0) {
1511
+ // Extract just the text for batch embedding
1512
+ const texts = textItems.map((item) => item.text);
1513
+ // Perform batch embedding
1514
+ const embeddings = await batchEmbed(texts);
1515
+ // Add each item with its embedding
1516
+ textPromises = textItems.map((item, i) => this.addNoun(embeddings[i], item.nounType, item.metadata));
1331
1517
  }
1332
- catch (storageError) {
1333
- // Item doesn't exist, continue with add operation
1334
- }
1335
- }
1336
- let noun;
1337
- // In write-only mode, skip index operations since index is not loaded
1338
- if (this.writeOnly) {
1339
- // Create noun object directly without adding to index
1340
- noun = {
1341
- id,
1342
- vector,
1343
- connections: new Map(),
1344
- level: 0, // Default level for new nodes
1345
- metadata: undefined // Will be set separately
1346
- };
1347
- }
1348
- else {
1349
- // Normal mode: Add to HNSW index first
1350
- await this.hnswIndex.addItem({ id, vector, metadata });
1351
- // Get the noun from the HNSW index
1352
- const indexNoun = this.hnswIndex.getNouns().get(id);
1353
- if (!indexNoun) {
1354
- throw new Error(`Failed to retrieve newly created noun with ID ${id}`);
1355
- }
1356
- noun = indexNoun;
1357
- }
1358
- // Save noun to storage using augmentation system
1359
- await this.augmentations.execute('saveNoun', { noun, options }, async () => {
1360
- await this.storage.saveNoun(noun);
1361
- const service = this.getServiceName(options);
1362
- await this.storage.incrementStatistic('noun', service);
1363
- });
1364
- // Save metadata if provided and not empty
1365
- if (metadata !== undefined) {
1366
- // Skip saving if metadata is an empty object
1367
- if (metadata &&
1368
- typeof metadata === 'object' &&
1369
- Object.keys(metadata).length === 0) {
1370
- // Don't save empty metadata
1371
- // Explicitly save null to ensure no metadata is stored
1372
- await this.storage.saveMetadata(id, null);
1373
- }
1374
- else {
1375
- // Validate noun type if metadata is for a GraphNoun
1376
- if (metadata && typeof metadata === 'object' && 'noun' in metadata) {
1377
- const nounType = metadata.noun;
1378
- // Check if the noun type is valid
1379
- const isValidNounType = Object.values(NounType).includes(nounType);
1380
- if (!isValidNounType) {
1381
- console.warn(`Invalid noun type: ${nounType}. Falling back to GraphNoun.`);
1382
- metadata.noun = NounType.Concept;
1383
- }
1384
- // Ensure createdBy field is populated for GraphNoun
1385
- const service = options.service || this.getCurrentAugmentation();
1386
- const graphNoun = metadata;
1387
- // Only set createdBy if it doesn't exist or is being explicitly updated
1388
- if (!graphNoun.createdBy || options.service) {
1389
- graphNoun.createdBy = getAugmentationVersion(service);
1390
- }
1391
- // Update timestamps
1392
- const now = new Date();
1393
- const timestamp = {
1394
- seconds: Math.floor(now.getTime() / 1000),
1395
- nanoseconds: (now.getTime() % 1000) * 1000000
1396
- };
1397
- // Set createdAt if it doesn't exist
1398
- if (!graphNoun.createdAt) {
1399
- graphNoun.createdAt = timestamp;
1400
- }
1401
- // Always update updatedAt
1402
- graphNoun.updatedAt = timestamp;
1403
- }
1404
- // Create properly namespaced metadata for new items
1405
- let metadataToSave = createNamespacedMetadata(metadata);
1406
- // Add domain metadata if distributed mode is enabled
1407
- if (this.domainDetector) {
1408
- // First check if domain is already in metadata
1409
- if (metadataToSave.domain) {
1410
- // Domain already specified, keep it
1411
- const domainInfo = this.domainDetector.detectDomain(metadataToSave);
1412
- if (domainInfo.domainMetadata) {
1413
- ;
1414
- metadataToSave.domainMetadata =
1415
- domainInfo.domainMetadata;
1416
- }
1417
- }
1418
- else {
1419
- // Try to detect domain from the data
1420
- const dataToAnalyze = Array.isArray(vectorOrData)
1421
- ? metadata
1422
- : vectorOrData;
1423
- const domainInfo = this.domainDetector.detectDomain(dataToAnalyze);
1424
- if (domainInfo.domain) {
1425
- ;
1426
- metadataToSave.domain = domainInfo.domain;
1427
- if (domainInfo.domainMetadata) {
1428
- ;
1429
- metadataToSave.domainMetadata =
1430
- domainInfo.domainMetadata;
1431
- }
1432
- }
1433
- }
1434
- }
1435
- // Add partition information if distributed mode is enabled
1436
- if (this.partitioner) {
1437
- const partition = this.partitioner.getPartition(id);
1438
- metadataToSave.partition = partition;
1439
- }
1440
- await this.storage.saveMetadata(id, metadataToSave);
1441
- // Update metadata index (write-only mode should build indices!)
1442
- if (this.index && !this.frozen) {
1443
- await this.metadataIndex?.addToIndex?.(id, metadataToSave);
1444
- }
1445
- // Track metadata statistics
1446
- const metadataService = this.getServiceName(options);
1447
- await this.storage.incrementStatistic('metadata', metadataService);
1448
- // Track content type if it's a GraphNoun
1449
- if (metadataToSave &&
1450
- typeof metadataToSave === 'object' &&
1451
- 'noun' in metadataToSave) {
1452
- this.metrics.trackContentType(metadataToSave.noun);
1453
- }
1454
- // Track update timestamp (handled by metrics augmentation)
1455
- }
1456
- }
1457
- // Update HNSW index size with actual index size
1458
- const indexSize = this.index.size();
1459
- await this.storage.updateHnswIndexSize(indexSize);
1460
- // Update health metrics if in distributed mode
1461
- if (this.monitoring) {
1462
- const vectorCount = await this.getNounCount();
1463
- this.monitoring.updateVectorCount(vectorCount);
1464
- }
1465
- // If addToRemote is true and we're connected to a remote server, add to remote as well
1466
- if (options.addToRemote && this.isConnectedToRemoteServer()) {
1467
- try {
1468
- await this.addToRemote(id, vector, metadata);
1469
- }
1470
- catch (remoteError) {
1471
- console.warn(`Failed to add to remote server: ${remoteError}. Continuing with local add.`);
1472
- }
1473
- }
1474
- // Invalidate search cache since data has changed
1475
- this.cache?.invalidateOnDataChange('add');
1476
- // Determine processing mode
1477
- const processingMode = options.process || 'auto';
1478
- let shouldProcessNeurally = false;
1479
- if (processingMode === 'neural') {
1480
- shouldProcessNeurally = true;
1481
- }
1482
- else if (processingMode === 'auto') {
1483
- // Auto-detect whether to use neural processing
1484
- shouldProcessNeurally = this.shouldAutoProcessNeurally(vectorOrData, metadata);
1485
- }
1486
- // 'literal' mode means no neural processing
1487
- // 🧠 AI Processing (Neural Import) - Based on processing mode
1488
- if (shouldProcessNeurally) {
1489
- try {
1490
- // Execute augmentation pipeline for data processing
1491
- // Note: Augmentations will be called via this.augmentations.execute during the actual add operation
1492
- // This replaces the legacy SENSE pipeline
1493
- if (this.loggingConfig?.verbose) {
1494
- console.log(`🧠 AI processing completed for data: ${id}`);
1495
- }
1496
- }
1497
- catch (processingError) {
1498
- // Don't fail the add operation if processing fails
1499
- console.warn(`🧠 AI processing failed for ${id}:`, processingError);
1500
- }
1501
- }
1502
- return id;
1503
- }
1504
- catch (error) {
1505
- console.error('Failed to add vector:', error);
1506
- // Track error in health monitor
1507
- if (this.monitoring) {
1508
- this.monitoring.recordRequest(0, true);
1509
- }
1510
- throw new Error(`Failed to add vector: ${error}`);
1511
- }
1512
- }
1513
- // REMOVED: addItem() - Use addNoun() instead (cleaner 2.0 API)
1514
- // REMOVED: addToBoth() - Remote server functionality moved to post-2.0.0
1515
- /**
1516
- * Add a vector to the remote server
1517
- * @param id ID of the vector to add
1518
- * @param vector Vector to add
1519
- * @param metadata Optional metadata to associate with the vector
1520
- * @returns True if successful, false otherwise
1521
- * @private
1522
- */
1523
- async addToRemote(id, vector, metadata) {
1524
- if (!this.isConnectedToRemoteServer()) {
1525
- return false;
1526
- }
1527
- try {
1528
- // TODO: Remote server operations (post-2.0.0 feature)
1529
- // if (!this.serverSearchConduit || !this.serverConnection) {
1530
- // throw new Error(
1531
- // 'Server search conduit or connection is not initialized'
1532
- // )
1533
- // }
1534
- // TODO: Add to remote server
1535
- // const addResult = await this.serverSearchConduit.addToBoth(
1536
- // this.serverConnection.connectionId,
1537
- // vector,
1538
- // metadata
1539
- // )
1540
- throw new Error('Remote server functionality not yet implemented in Brainy 2.0.0');
1541
- // TODO: Handle remote add result (post-2.0.0 feature)
1542
- // if (!addResult.success) {
1543
- // throw new Error(`Remote add failed: ${addResult.error}`)
1544
- // }
1545
- return true;
1546
- }
1547
- catch (error) {
1548
- console.error('Failed to add to remote server:', error);
1549
- throw new Error(`Failed to add to remote server: ${error}`);
1550
- }
1551
- }
1552
- /**
1553
- * Add multiple vectors or data items to the database
1554
- * @param items Array of items to add
1555
- * @param options Additional options
1556
- * @returns Array of IDs for the added items
1557
- */
1558
- /**
1559
- * Add multiple nouns in batch
1560
- * @param items Array of nouns to add
1561
- * @param options Batch processing options
1562
- * @returns Array of generated IDs
1563
- */
1564
- async addNouns(items, options = {}) {
1565
- await this.ensureInitialized();
1566
- // Check if database is in read-only mode
1567
- this.checkReadOnly();
1568
- // Default concurrency to 4 if not specified
1569
- const concurrency = options.concurrency || 4;
1570
- // Default batch size to 50 if not specified
1571
- const batchSize = options.batchSize || 50;
1572
- try {
1573
- // Process items in batches to control concurrency and memory usage
1574
- const ids = [];
1575
- const itemsToProcess = [...items]; // Create a copy to avoid modifying the original array
1576
- while (itemsToProcess.length > 0) {
1577
- // Take up to 'batchSize' items to process in a batch
1578
- const batch = itemsToProcess.splice(0, batchSize);
1579
- // Separate items that are already vectors from those that need embedding
1580
- const vectorItems = [];
1581
- const textItems = [];
1582
- // Categorize items
1583
- batch.forEach((item, index) => {
1584
- if (Array.isArray(item.vectorOrData) &&
1585
- item.vectorOrData.every((val) => typeof val === 'number') &&
1586
- !options.forceEmbed) {
1587
- // Item is already a vector
1588
- vectorItems.push({
1589
- vectorOrData: item.vectorOrData,
1590
- metadata: item.metadata,
1591
- index
1592
- });
1593
- }
1594
- else if (typeof item.vectorOrData === 'string') {
1595
- // Item is text that needs embedding
1596
- textItems.push({
1597
- text: item.vectorOrData,
1598
- metadata: item.metadata,
1599
- index
1600
- });
1601
- }
1602
- else {
1603
- // For now, treat other types as text
1604
- // In a more complete implementation, we might handle other types differently
1605
- const textRepresentation = String(item.vectorOrData);
1606
- textItems.push({
1607
- text: textRepresentation,
1608
- metadata: item.metadata,
1609
- index
1610
- });
1611
- }
1612
- });
1613
- // Process vector items (already embedded)
1614
- const vectorPromises = vectorItems.map((item) => this.addNoun(item.vectorOrData, item.metadata));
1615
- // Process text items in a single batch embedding operation
1616
- let textPromises = [];
1617
- if (textItems.length > 0) {
1618
- // Extract just the text for batch embedding
1619
- const texts = textItems.map((item) => item.text);
1620
- // Perform batch embedding
1621
- const embeddings = await batchEmbed(texts);
1622
- // Add each item with its embedding
1623
- textPromises = textItems.map((item, i) => this.addNoun(embeddings[i], item.metadata));
1624
- }
1625
- // Combine all promises
1626
- const batchResults = await Promise.all([
1627
- ...vectorPromises,
1628
- ...textPromises
1629
- ]);
1630
- // Add the results to our ids array
1631
- ids.push(...batchResults);
1518
+ // Combine all promises
1519
+ const batchResults = await Promise.all([
1520
+ ...vectorPromises,
1521
+ ...textPromises
1522
+ ]);
1523
+ // Add the results to our ids array
1524
+ ids.push(...batchResults);
1632
1525
  }
1633
1526
  return ids;
1634
1527
  }
@@ -1637,20 +1530,6 @@ export class BrainyData {
1637
1530
  throw new Error(`Failed to add batch of items: ${error}`);
1638
1531
  }
1639
1532
  }
1640
- /**
1641
- * Add multiple vectors or data items to both local and remote databases
1642
- * @param items Array of items to add
1643
- * @param options Additional options
1644
- * @returns Array of IDs for the added items
1645
- */
1646
- async addBatchToBoth(items, options = {}) {
1647
- // Check if connected to a remote server
1648
- if (!this.isConnectedToRemoteServer()) {
1649
- throw new Error('Not connected to a remote server. Call connectToRemoteServer() first.');
1650
- }
1651
- // Add to local with addToRemote option
1652
- return this.addNouns(items, { ...options, addToRemote: true });
1653
- }
1654
1533
  /**
1655
1534
  * Filter search results by service
1656
1535
  * @param results Search results to filter
@@ -1929,6 +1808,12 @@ export class BrainyData {
1929
1808
  * @param options Simple search options (metadata filters only)
1930
1809
  * @returns Vector search results
1931
1810
  */
1811
+ // ================================================================
1812
+ // SECTION 3: SEARCH & DISCOVERY
1813
+ // ================================================================
1814
+ // Vector search, semantic search, and content discovery operations
1815
+ // Includes find(), search(), searchLocal(), findSimilar() and related methods
1816
+ // Powers the Triple Intelligence search combining vector + graph + field queries
1932
1817
  /**
1933
1818
  * 🔍 Simple Vector Similarity Search - Clean wrapper around find()
1934
1819
  *
@@ -1950,19 +1835,22 @@ export class BrainyData {
1950
1835
  * })
1951
1836
  */
1952
1837
  async search(queryVectorOrData, options = {}) {
1953
- // Build metadata filter from options
1954
- const metadataFilter = { ...options.metadata };
1838
+ // Comprehensive input validation
1839
+ const validatedQuery = validateSearchQuery(queryVectorOrData, 'queryVectorOrData');
1840
+ const validatedOptions = validateSearchOptions(options, 'options');
1841
+ // Build metadata filter from validated options
1842
+ const metadataFilter = { ...validatedOptions.metadata };
1955
1843
  // Add noun type filtering
1956
- if (options.nounTypes && options.nounTypes.length > 0) {
1957
- metadataFilter.nounType = { in: options.nounTypes };
1844
+ if (validatedOptions.nounTypes && validatedOptions.nounTypes.length > 0) {
1845
+ metadataFilter.nounType = { in: validatedOptions.nounTypes };
1958
1846
  }
1959
1847
  // Add item ID filtering
1960
- if (options.itemIds && options.itemIds.length > 0) {
1961
- metadataFilter.id = { in: options.itemIds };
1848
+ if (validatedOptions.itemIds && validatedOptions.itemIds.length > 0) {
1849
+ metadataFilter.id = { in: validatedOptions.itemIds };
1962
1850
  }
1963
1851
  // Build simple TripleQuery for vector similarity
1964
1852
  const tripleQuery = {
1965
- like: queryVectorOrData
1853
+ like: validatedQuery
1966
1854
  };
1967
1855
  // Add metadata filter if we have conditions
1968
1856
  if (Object.keys(metadataFilter).length > 0) {
@@ -1970,17 +1858,17 @@ export class BrainyData {
1970
1858
  }
1971
1859
  // Extract find() options
1972
1860
  const findOptions = {
1973
- limit: options.limit,
1974
- offset: options.offset,
1975
- cursor: options.cursor,
1976
- excludeDeleted: options.excludeDeleted,
1977
- timeout: options.timeout
1861
+ limit: validatedOptions.limit,
1862
+ offset: validatedOptions.offset,
1863
+ cursor: validatedOptions.cursor,
1864
+ excludeDeleted: validatedOptions.excludeDeleted,
1865
+ timeout: validatedOptions.timeout
1978
1866
  };
1979
1867
  // Call find() with structured query - this is the key simplification!
1980
1868
  let results = await this.find(tripleQuery, findOptions);
1981
1869
  // Apply threshold filtering if specified
1982
- if (options.threshold !== undefined) {
1983
- results = results.filter(r => (r.fusionScore || r.score || 0) >= options.threshold);
1870
+ if (validatedOptions.threshold !== undefined) {
1871
+ results = results.filter(r => (r.fusionScore || r.score || 0) >= validatedOptions.threshold);
1984
1872
  }
1985
1873
  // Convert to SearchResult format
1986
1874
  return results.map(r => ({
@@ -2093,11 +1981,9 @@ export class BrainyData {
2093
1981
  if (options.searchMode === 'local') {
2094
1982
  return this.searchLocal(queryVectorOrData, k, options);
2095
1983
  }
2096
- else if (options.searchMode === 'remote') {
2097
- return this.searchRemote(queryVectorOrData, k, options);
2098
- }
2099
- else if (options.searchMode === 'combined') {
2100
- return this.searchCombined(queryVectorOrData, k, options);
1984
+ else if (options.searchMode === 'remote' || options.searchMode === 'combined') {
1985
+ // Remote and combined search modes not supported - fall back to local
1986
+ return this.searchLocal(queryVectorOrData, k, options);
2101
1987
  }
2102
1988
  // Generate deduplication key for concurrent request handling
2103
1989
  const dedupeKey = RequestDeduplicator.getSearchKey(typeof queryVectorOrData === 'string' ? queryVectorOrData : JSON.stringify(queryVectorOrData), k, options);
@@ -3235,6 +3121,30 @@ export class BrainyData {
3235
3121
  throw new Error(`Failed to get verbs by type ${type}: ${error}`);
3236
3122
  }
3237
3123
  }
3124
+ /**
3125
+ * Get all verbs associated with a specific noun (both as source and target)
3126
+ * @param nounId The ID of the noun
3127
+ * @returns Array of verbs where the noun is either source or target
3128
+ */
3129
+ async getVerbsForNoun(nounId) {
3130
+ await this.ensureInitialized();
3131
+ try {
3132
+ // Get verbs where this noun is the source
3133
+ const sourceVerbs = await this.getVerbsBySource(nounId);
3134
+ // Get verbs where this noun is the target
3135
+ const targetVerbs = await this.getVerbsByTarget(nounId);
3136
+ // Combine and deduplicate (in case a verb somehow appears in both - shouldn't happen but safety first)
3137
+ const verbMap = new Map();
3138
+ for (const verb of [...sourceVerbs, ...targetVerbs]) {
3139
+ verbMap.set(verb.id, verb);
3140
+ }
3141
+ return Array.from(verbMap.values());
3142
+ }
3143
+ catch (error) {
3144
+ console.error(`Failed to get verbs for noun ${nounId}:`, error);
3145
+ throw error;
3146
+ }
3147
+ }
3238
3148
  /**
3239
3149
  * Delete a verb
3240
3150
  * @param id The ID of the verb to delete
@@ -3248,9 +3158,16 @@ export class BrainyData {
3248
3158
  */
3249
3159
  async addVerbs(verbs) {
3250
3160
  const ids = [];
3251
- for (const verb of verbs) {
3252
- const id = await this.addVerb(verb.source, verb.target, verb.type, verb.metadata);
3253
- ids.push(id);
3161
+ const chunkSize = 10; // Conservative chunk size for parallel processing
3162
+ // Process verbs in parallel chunks to improve performance
3163
+ for (let i = 0; i < verbs.length; i += chunkSize) {
3164
+ const chunk = verbs.slice(i, i + chunkSize);
3165
+ // Process chunk in parallel
3166
+ const chunkPromises = chunk.map(verb => this.addVerb(verb.source, verb.target, verb.type, verb.metadata));
3167
+ // Wait for all in chunk to complete
3168
+ const chunkIds = await Promise.all(chunkPromises);
3169
+ // Maintain order by adding chunk results
3170
+ ids.push(...chunkIds);
3254
3171
  }
3255
3172
  return ids;
3256
3173
  }
@@ -3261,8 +3178,16 @@ export class BrainyData {
3261
3178
  */
3262
3179
  async deleteVerbs(ids) {
3263
3180
  const results = [];
3264
- for (const id of ids) {
3265
- results.push(await this.deleteVerb(id));
3181
+ const chunkSize = 10; // Conservative chunk size for parallel processing
3182
+ // Process deletions in parallel chunks to improve performance
3183
+ for (let i = 0; i < ids.length; i += chunkSize) {
3184
+ const chunk = ids.slice(i, i + chunkSize);
3185
+ // Process chunk in parallel
3186
+ const chunkPromises = chunk.map(id => this.deleteVerb(id));
3187
+ // Wait for all in chunk to complete
3188
+ const chunkResults = await Promise.all(chunkPromises);
3189
+ // Maintain order by adding chunk results
3190
+ results.push(...chunkResults);
3266
3191
  }
3267
3192
  return results;
3268
3193
  }
@@ -3346,6 +3271,12 @@ export class BrainyData {
3346
3271
  searchMemoryUsage: this.cache?.getMemoryUsage() || 0
3347
3272
  };
3348
3273
  }
3274
+ // ================================================================
3275
+ // SECTION 8: CACHE & PERFORMANCE
3276
+ // ================================================================
3277
+ // Caching, performance optimization, and memory management
3278
+ // Includes clearCache(), performance tuning, and optimization utilities
3279
+ // Cache management for improved response times and resource efficiency
3349
3280
  /**
3350
3281
  * Clear search cache manually (useful for testing or memory management)
3351
3282
  */
@@ -3514,6 +3445,12 @@ export class BrainyData {
3514
3445
  // Ignore errors in size calculation
3515
3446
  }
3516
3447
  }
3448
+ // ================================================================
3449
+ // SECTION 7: STATISTICS & MONITORING
3450
+ // ================================================================
3451
+ // Analytics, monitoring, and metrics collection operations
3452
+ // Includes getStatistics(), getServiceStatistics(), performance monitoring
3453
+ // System health reporting and data analytics for optimization
3517
3454
  /**
3518
3455
  * Get statistics about the current state of the database
3519
3456
  * @param options Additional options for retrieving statistics
@@ -4276,102 +4213,6 @@ export class BrainyData {
4276
4213
  throw new Error(`Failed to search with text query: ${error}`);
4277
4214
  }
4278
4215
  }
4279
- /**
4280
- * Search a remote Brainy server for similar vectors
4281
- * @param queryVectorOrData Query vector or data to search for
4282
- * @param k Number of results to return
4283
- * @param options Additional options
4284
- * @returns Array of search results
4285
- */
4286
- async searchRemote(queryVectorOrData, k = 10, options = {}) {
4287
- // TODO: Remote server search will be implemented in post-2.0.0 release
4288
- await this.ensureInitialized();
4289
- this.checkWriteOnly();
4290
- throw new Error('Remote server search functionality not yet implemented in Brainy 2.0.0');
4291
- }
4292
- /**
4293
- * Search both local and remote Brainy instances, combining the results
4294
- * @param queryVectorOrData Query vector or data to search for
4295
- * @param k Number of results to return
4296
- * @param options Additional options
4297
- * @returns Array of search results
4298
- */
4299
- async searchCombined(queryVectorOrData, k = 10, options = {}) {
4300
- await this.ensureInitialized();
4301
- // Check if database is in write-only mode
4302
- this.checkWriteOnly();
4303
- // Check if connected to a remote server
4304
- if (!this.isConnectedToRemoteServer()) {
4305
- // If not connected to a remote server, just search locally
4306
- return this.searchLocal(queryVectorOrData, k, options);
4307
- }
4308
- try {
4309
- // Default to searching local first
4310
- const localFirst = options.localFirst !== false;
4311
- if (localFirst) {
4312
- // Search local first
4313
- const localResults = await this.searchLocal(queryVectorOrData, k, options);
4314
- // If we have enough local results, return them
4315
- if (localResults.length >= k) {
4316
- return localResults;
4317
- }
4318
- // Otherwise, search remote for additional results
4319
- const remoteResults = await this.searchRemote(queryVectorOrData, k - localResults.length, { ...options, storeResults: true });
4320
- // Combine results, removing duplicates
4321
- const combinedResults = [...localResults];
4322
- const localIds = new Set(localResults.map((r) => r.id));
4323
- for (const result of remoteResults) {
4324
- if (!localIds.has(result.id)) {
4325
- combinedResults.push(result);
4326
- }
4327
- }
4328
- return combinedResults;
4329
- }
4330
- else {
4331
- // Search remote first
4332
- const remoteResults = await this.searchRemote(queryVectorOrData, k, {
4333
- ...options,
4334
- storeResults: true
4335
- });
4336
- // If we have enough remote results, return them
4337
- if (remoteResults.length >= k) {
4338
- return remoteResults;
4339
- }
4340
- // Otherwise, search local for additional results
4341
- const localResults = await this.searchLocal(queryVectorOrData, k - remoteResults.length, options);
4342
- // Combine results, removing duplicates
4343
- const combinedResults = [...remoteResults];
4344
- const remoteIds = new Set(remoteResults.map((r) => r.id));
4345
- for (const result of localResults) {
4346
- if (!remoteIds.has(result.id)) {
4347
- combinedResults.push(result);
4348
- }
4349
- }
4350
- return combinedResults;
4351
- }
4352
- }
4353
- catch (error) {
4354
- console.error('Failed to perform combined search:', error);
4355
- throw new Error(`Failed to perform combined search: ${error}`);
4356
- }
4357
- }
4358
- /**
4359
- * Check if the instance is connected to a remote server
4360
- * @returns True if connected to a remote server, false otherwise
4361
- */
4362
- isConnectedToRemoteServer() {
4363
- // TODO: Remote server connections will be implemented in post-2.0.0 release
4364
- return false;
4365
- }
4366
- /**
4367
- * Disconnect from the remote server
4368
- * @returns True if successfully disconnected, false if not connected
4369
- */
4370
- async disconnectFromRemoteServer() {
4371
- // TODO: Remote server disconnection will be implemented in post-2.0.0 release
4372
- console.warn('disconnectFromRemoteServer: Remote server functionality not yet implemented in Brainy 2.0.0');
4373
- return false;
4374
- }
4375
4216
  /**
4376
4217
  * Ensure the database is initialized
4377
4218
  */
@@ -4500,10 +4341,6 @@ export class BrainyData {
4500
4341
  // Continue with shutdown even if statistics flush fails
4501
4342
  }
4502
4343
  }
4503
- // Disconnect from remote server if connected
4504
- if (this.isConnectedToRemoteServer()) {
4505
- await this.disconnectFromRemoteServer();
4506
- }
4507
4344
  // Clean up worker pools to release resources
4508
4345
  cleanupWorkerPools();
4509
4346
  // Additional cleanup could be added here in the future
@@ -4634,8 +4471,12 @@ export class BrainyData {
4634
4471
  noun.vector = await this.embeddingFunction(noun.metadata);
4635
4472
  }
4636
4473
  }
4474
+ // Extract type from metadata or default to Content
4475
+ const nounType = (noun.metadata && typeof noun.metadata === 'object' && 'noun' in noun.metadata)
4476
+ ? noun.metadata.noun
4477
+ : NounType.Content;
4637
4478
  // Add the noun with its vector and metadata (custom ID not supported)
4638
- await this.addNoun(noun.vector, noun.metadata);
4479
+ await this.addNoun(noun.vector, nounType, noun.metadata);
4639
4480
  nounsRestored++;
4640
4481
  }
4641
4482
  catch (error) {
@@ -4791,8 +4632,8 @@ export class BrainyData {
4791
4632
  tags: [`tag-${i % 5}`, `category-${i % 3}`]
4792
4633
  }
4793
4634
  };
4794
- // Add the noun
4795
- const id = await this.addNoun(metadata.description, metadata);
4635
+ // Add the noun with explicit type
4636
+ const id = await this.addNoun(metadata.description, nounType, metadata);
4796
4637
  nounIds.push(id);
4797
4638
  }
4798
4639
  // Generate random verbs between nouns
@@ -4982,8 +4823,7 @@ export class BrainyData {
4982
4823
  const configValue = options?.encrypt ? await this.encryptData(JSON.stringify(value)) : value;
4983
4824
  // Use simple text for vectorization
4984
4825
  const searchableText = `Configuration setting for ${key}`;
4985
- await this.addNoun(searchableText, {
4986
- nounType: NounType.State,
4826
+ await this.addNoun(searchableText, NounType.State, {
4987
4827
  configKey: key,
4988
4828
  configValue: configValue,
4989
4829
  encrypted: !!options?.encrypt,
@@ -5061,6 +4901,12 @@ export class BrainyData {
5061
4901
  // 6. update() - Update noun data/metadata with index sync
5062
4902
  // 7. delete() - Smart delete with soft delete default (enhanced original)
5063
4903
  // ========================================
4904
+ // ================================================================
4905
+ // SECTION 6: IMPORT & DATA INGESTION
4906
+ // ================================================================
4907
+ // Bulk data import and processing operations
4908
+ // Includes import(), importSparseData() with neural type detection
4909
+ // Smart parsing of CSV, JSON, YAML and automatic relationship extraction
5064
4910
  /**
5065
4911
  * Neural Import - Smart bulk data import with semantic type detection
5066
4912
  * Uses transformer embeddings to automatically detect and classify data types
@@ -5114,17 +4960,346 @@ export class BrainyData {
5114
4960
  * @param metadata Additional metadata
5115
4961
  * @returns Created noun ID
5116
4962
  */
4963
+ // ================================================================
4964
+ // SECTION 4: NOUN OPERATIONS (CRUD)
4965
+ // ================================================================
4966
+ // Create, Read, Update, Delete operations for noun entities
4967
+ // Includes addNoun(), addNouns(), getNoun(), getNouns(), updateNoun(), deleteNoun()
4968
+ // Core data storage and retrieval operations with metadata management
5117
4969
  /**
5118
- * Add a noun to the database
4970
+ * Add a noun to the database with required type
5119
4971
  * Clean 2.0 API - primary method for adding data
5120
4972
  *
5121
4973
  * @param vectorOrData Vector array or data to embed
5122
- * @param metadata Metadata to store with the noun
4974
+ * @param nounType Required noun type (one of 31 types)
4975
+ * @param metadata Optional metadata object
5123
4976
  * @returns The generated ID
5124
4977
  */
5125
- async addNoun(vectorOrData, metadata) {
5126
- return await this.add(vectorOrData, metadata);
4978
+ async addNoun(vectorOrData, nounType, metadata, options = {}) {
4979
+ // Validate noun type
4980
+ const validatedType = validateNounType(nounType);
4981
+ // Enrich metadata with validated type
4982
+ let enrichedMetadata = {
4983
+ ...metadata,
4984
+ noun: validatedType
4985
+ };
4986
+ await this.ensureInitialized();
4987
+ // Check if database is in read-only mode
4988
+ this.checkReadOnly();
4989
+ // Distributed routing for add operations
4990
+ if (this.shardManager && this.networkTransport && !options.id) {
4991
+ // Generate ID early for consistent shard routing
4992
+ const id = uuidv4();
4993
+ // Determine which shard this data belongs to
4994
+ const shardAssignment = this.shardManager.getShardForKey(id);
4995
+ // If this shard is owned by another node, forward the request
4996
+ if (shardAssignment && shardAssignment.nodeId &&
4997
+ shardAssignment.nodeId !== this.networkTransport.nodeId) {
4998
+ try {
4999
+ const response = await this.networkTransport.sendToNode(shardAssignment.nodeId, 'DISTRIBUTED_ADD', {
5000
+ data: vectorOrData,
5001
+ type: nounType,
5002
+ metadata: enrichedMetadata,
5003
+ id // Use the generated ID
5004
+ });
5005
+ if (response.success) {
5006
+ return response.id;
5007
+ }
5008
+ else {
5009
+ throw new Error(`Remote add failed: ${response.error}`);
5010
+ }
5011
+ }
5012
+ catch (error) {
5013
+ console.warn(`Failed to forward add to ${shardAssignment.nodeId}, falling back to local add:`, error);
5014
+ // Fall through to local add
5015
+ }
5016
+ }
5017
+ // If we're here, either we own the shard or forwarding failed
5018
+ options.id = id; // Use the generated ID for local add
5019
+ }
5020
+ // Comprehensive input validation
5021
+ const validatedData = validateDataInput(vectorOrData, 'vectorOrData');
5022
+ try {
5023
+ let vector;
5024
+ if (Array.isArray(validatedData)) {
5025
+ for (let i = 0; i < validatedData.length; i++) {
5026
+ if (typeof validatedData[i] !== 'number') {
5027
+ throw new Error('Vector contains non-numeric values');
5028
+ }
5029
+ }
5030
+ }
5031
+ // Check if input is already a vector
5032
+ if (Array.isArray(validatedData) && !options.forceEmbed) {
5033
+ // Input is already a vector (and we've validated it contains only numbers)
5034
+ vector = validatedData;
5035
+ }
5036
+ else {
5037
+ // Input needs to be vectorized
5038
+ try {
5039
+ // Check if input is a JSON object and process it specially
5040
+ if (typeof validatedData === 'object' &&
5041
+ validatedData !== null &&
5042
+ !Array.isArray(validatedData)) {
5043
+ // Process JSON object for better vectorization
5044
+ const preparedText = prepareJsonForVectorization(validatedData, {
5045
+ // Prioritize common name/title fields if they exist
5046
+ priorityFields: [
5047
+ 'name',
5048
+ 'title',
5049
+ 'company',
5050
+ 'organization',
5051
+ 'description',
5052
+ 'summary'
5053
+ ]
5054
+ });
5055
+ vector = await this.embeddingFunction(preparedText);
5056
+ // IMPORTANT: When an object is passed as data and no metadata is provided,
5057
+ // use the object AS the metadata too. This is expected behavior for the API.
5058
+ // Users can pass either:
5059
+ // 1. addNoun(string, metadata) - vectorize string, store metadata
5060
+ // 2. addNoun(object) - vectorize object text, store object as metadata
5061
+ // 3. addNoun(object, metadata) - vectorize object text, store provided metadata
5062
+ if (!enrichedMetadata || Object.keys(enrichedMetadata).length === 1) { // Only has 'noun' key
5063
+ enrichedMetadata = { ...validatedData, noun: validatedType };
5064
+ }
5065
+ // Track field names for this JSON document
5066
+ const service = this.getServiceName(options);
5067
+ if (this.storage) {
5068
+ await this.storage.trackFieldNames(validatedData, service);
5069
+ }
5070
+ }
5071
+ else {
5072
+ // Use standard embedding for non-JSON data
5073
+ vector = await this.embeddingFunction(validatedData);
5074
+ }
5075
+ }
5076
+ catch (embedError) {
5077
+ throw new Error(`Failed to vectorize data: ${embedError}`);
5078
+ }
5079
+ }
5080
+ // Check if vector is defined
5081
+ if (!vector) {
5082
+ throw new Error('Vector is undefined or null');
5083
+ }
5084
+ // Validate vector dimensions
5085
+ if (vector.length !== this._dimensions) {
5086
+ throw new Error(`Vector dimension mismatch: expected ${this._dimensions}, got ${vector.length}`);
5087
+ }
5088
+ // Use ID from options if it exists, otherwise from metadata, otherwise generate a new UUID
5089
+ const id = options.id ||
5090
+ (enrichedMetadata && typeof enrichedMetadata === 'object' && 'id' in enrichedMetadata
5091
+ ? enrichedMetadata.id
5092
+ : uuidv4());
5093
+ // Check for existing noun (both write-only and normal modes)
5094
+ let existingNoun;
5095
+ if (options.id) {
5096
+ try {
5097
+ if (this.writeOnly) {
5098
+ // In write-only mode, check storage directly
5099
+ existingNoun =
5100
+ (await this.storage.getNoun(options.id)) ?? undefined;
5101
+ }
5102
+ else {
5103
+ // In normal mode, check index first, then storage
5104
+ existingNoun = this.index.getNouns().get(options.id);
5105
+ if (!existingNoun) {
5106
+ existingNoun =
5107
+ (await this.storage.getNoun(options.id)) ?? undefined;
5108
+ }
5109
+ }
5110
+ if (existingNoun) {
5111
+ // Check if existing noun is a placeholder
5112
+ const existingMetadata = await this.storage.getMetadata(options.id);
5113
+ const isPlaceholder = existingMetadata &&
5114
+ typeof existingMetadata === 'object' &&
5115
+ existingMetadata.isPlaceholder;
5116
+ if (isPlaceholder) {
5117
+ // Replace placeholder with real data
5118
+ if (this.loggingConfig?.verbose) {
5119
+ console.log(`Replacing placeholder noun ${options.id} with real data`);
5120
+ }
5121
+ }
5122
+ else {
5123
+ // Real noun already exists, update it
5124
+ if (this.loggingConfig?.verbose) {
5125
+ console.log(`Updating existing noun ${options.id}`);
5126
+ }
5127
+ }
5128
+ }
5129
+ }
5130
+ catch (storageError) {
5131
+ // Item doesn't exist, continue with add operation
5132
+ }
5133
+ }
5134
+ let noun;
5135
+ // In write-only mode, skip index operations since index is not loaded
5136
+ if (this.writeOnly) {
5137
+ // Create noun object directly without adding to index
5138
+ noun = {
5139
+ id,
5140
+ vector,
5141
+ connections: new Map(),
5142
+ level: 0, // Default level for new nodes
5143
+ metadata: undefined // Will be set separately
5144
+ };
5145
+ }
5146
+ else {
5147
+ // Normal mode: Add to HNSW index first
5148
+ await this.hnswIndex.addItem({ id, vector, metadata: enrichedMetadata });
5149
+ // Get the noun from the HNSW index
5150
+ const indexNoun = this.hnswIndex.getNouns().get(id);
5151
+ if (!indexNoun) {
5152
+ throw new Error(`Failed to retrieve newly created noun with ID ${id}`);
5153
+ }
5154
+ noun = indexNoun;
5155
+ }
5156
+ // Save noun to storage using augmentation system
5157
+ await this.augmentations.execute('saveNoun', { noun, options }, async () => {
5158
+ await this.storage.saveNoun(noun);
5159
+ const service = this.getServiceName(options);
5160
+ await this.storage.incrementStatistic('noun', service);
5161
+ });
5162
+ // Save metadata if provided and not empty
5163
+ if (enrichedMetadata !== undefined) {
5164
+ // Skip saving if metadata is an empty object
5165
+ if (enrichedMetadata &&
5166
+ typeof enrichedMetadata === 'object' &&
5167
+ Object.keys(enrichedMetadata).length === 0) {
5168
+ // Don't save empty metadata
5169
+ // Explicitly save null to ensure no metadata is stored
5170
+ await this.storage.saveMetadata(id, null);
5171
+ }
5172
+ else {
5173
+ // Validate noun type if metadata is for a GraphNoun
5174
+ if (enrichedMetadata && typeof enrichedMetadata === 'object' && 'noun' in enrichedMetadata) {
5175
+ const nounType = enrichedMetadata.noun;
5176
+ // Check if the noun type is valid
5177
+ const isValidNounType = Object.values(NounType).includes(nounType);
5178
+ if (!isValidNounType) {
5179
+ console.warn(`Invalid noun type: ${nounType}. Falling back to GraphNoun.`);
5180
+ enrichedMetadata.noun = NounType.Concept;
5181
+ }
5182
+ // Ensure createdBy field is populated for GraphNoun
5183
+ const service = options.service || this.getCurrentAugmentation();
5184
+ const graphNoun = enrichedMetadata;
5185
+ // Only set createdBy if it doesn't exist or is being explicitly updated
5186
+ if (!graphNoun.createdBy || options.service) {
5187
+ graphNoun.createdBy = getAugmentationVersion(service);
5188
+ }
5189
+ // Update timestamps
5190
+ const now = new Date();
5191
+ const timestamp = {
5192
+ seconds: Math.floor(now.getTime() / 1000),
5193
+ nanoseconds: (now.getTime() % 1000) * 1000000
5194
+ };
5195
+ // Set createdAt if it doesn't exist
5196
+ if (!graphNoun.createdAt) {
5197
+ graphNoun.createdAt = timestamp;
5198
+ }
5199
+ // Always update updatedAt
5200
+ graphNoun.updatedAt = timestamp;
5201
+ }
5202
+ // Create properly namespaced metadata for new items
5203
+ let metadataToSave = createNamespacedMetadata(enrichedMetadata);
5204
+ // Add domain metadata if distributed mode is enabled
5205
+ if (this.domainDetector) {
5206
+ // First check if domain is already in metadata
5207
+ if (metadataToSave.domain) {
5208
+ // Domain already specified, keep it
5209
+ const domainInfo = this.domainDetector.detectDomain(metadataToSave);
5210
+ if (domainInfo.domainMetadata) {
5211
+ ;
5212
+ metadataToSave.domainMetadata =
5213
+ domainInfo.domainMetadata;
5214
+ }
5215
+ }
5216
+ else {
5217
+ // Try to detect domain from the data
5218
+ const dataToAnalyze = Array.isArray(vectorOrData)
5219
+ ? enrichedMetadata
5220
+ : vectorOrData;
5221
+ const domainInfo = this.domainDetector.detectDomain(dataToAnalyze);
5222
+ if (domainInfo.domain) {
5223
+ ;
5224
+ metadataToSave.domain = domainInfo.domain;
5225
+ if (domainInfo.domainMetadata) {
5226
+ ;
5227
+ metadataToSave.domainMetadata =
5228
+ domainInfo.domainMetadata;
5229
+ }
5230
+ }
5231
+ }
5232
+ }
5233
+ // Add partition information if distributed mode is enabled
5234
+ if (this.partitioner) {
5235
+ const partition = this.partitioner.getPartition(id);
5236
+ metadataToSave.partition = partition;
5237
+ }
5238
+ await this.storage.saveMetadata(id, metadataToSave);
5239
+ // Update metadata index (write-only mode should build indices!)
5240
+ if (this.index && !this.frozen) {
5241
+ await this.metadataIndex?.addToIndex?.(id, metadataToSave);
5242
+ }
5243
+ // Track metadata statistics
5244
+ const metadataService = this.getServiceName(options);
5245
+ await this.storage.incrementStatistic('metadata', metadataService);
5246
+ // Content type tracking removed - metrics system not initialized
5247
+ // Track update timestamp (handled by metrics augmentation)
5248
+ }
5249
+ }
5250
+ // Update HNSW index size with actual index size
5251
+ const indexSize = this.index.size();
5252
+ await this.storage.updateHnswIndexSize(indexSize);
5253
+ // Update health metrics if in distributed mode
5254
+ if (this.monitoring) {
5255
+ const vectorCount = await this.getNounCount();
5256
+ this.monitoring.updateVectorCount(vectorCount);
5257
+ }
5258
+ // Invalidate search cache since data has changed
5259
+ this.cache?.invalidateOnDataChange('add');
5260
+ // Determine processing mode
5261
+ const processingMode = options.process || 'auto';
5262
+ let shouldProcessNeurally = false;
5263
+ if (processingMode === 'neural') {
5264
+ shouldProcessNeurally = true;
5265
+ }
5266
+ else if (processingMode === 'auto') {
5267
+ // Auto-detect whether to use neural processing
5268
+ shouldProcessNeurally = this.shouldAutoProcessNeurally(vectorOrData, enrichedMetadata);
5269
+ }
5270
+ // 'literal' mode means no neural processing
5271
+ // 🧠 AI Processing (Neural Import) - Based on processing mode
5272
+ if (shouldProcessNeurally) {
5273
+ try {
5274
+ // Execute augmentation pipeline for data processing
5275
+ // Note: Augmentations will be called via this.augmentations.execute during the actual add operation
5276
+ // This replaces the legacy SENSE pipeline
5277
+ if (this.loggingConfig?.verbose) {
5278
+ console.log(`🧠 AI processing completed for data: ${id}`);
5279
+ }
5280
+ }
5281
+ catch (processingError) {
5282
+ // Don't fail the add operation if processing fails
5283
+ console.warn(`🧠 AI processing failed for ${id}:`, processingError);
5284
+ }
5285
+ }
5286
+ return id;
5287
+ }
5288
+ catch (error) {
5289
+ console.error('Failed to add vector:', error);
5290
+ // Track error in health monitor
5291
+ if (this.monitoring) {
5292
+ this.monitoring.recordRequest(0, true);
5293
+ }
5294
+ throw new Error(`Failed to add vector: ${error}`);
5295
+ }
5127
5296
  }
5297
+ // ================================================================
5298
+ // SECTION 5: GRAPH OPERATIONS (VERBS)
5299
+ // ================================================================
5300
+ // Relationship and graph operations for verb entities
5301
+ // Includes addVerb(), addVerbs(), getVerb(), getVerbs(), relationship queries
5302
+ // Manages typed connections between nouns with metadata and weights
5128
5303
  /**
5129
5304
  * Add Verb - Unified relationship creation between nouns
5130
5305
  * Creates typed relationships with proper vector embeddings from metadata
@@ -5151,10 +5326,10 @@ export class BrainyData {
5151
5326
  const sourceNoun = this.index.getNouns().get(sourceId);
5152
5327
  const targetNoun = this.index.getNouns().get(targetId);
5153
5328
  if (!sourceNoun) {
5154
- throw new Error(`Source noun with ID ${sourceId} does not exist`);
5329
+ throw BrainyError.notFound(`Source noun with ID ${sourceId}`);
5155
5330
  }
5156
5331
  if (!targetNoun) {
5157
- throw new Error(`Target noun with ID ${targetId} does not exist`);
5332
+ throw BrainyError.notFound(`Target noun with ID ${targetId}`);
5158
5333
  }
5159
5334
  // Create embeddable text from verb type and metadata for searchability
5160
5335
  let embeddingText = `${verbType} relationship`;
@@ -5458,10 +5633,10 @@ export class BrainyData {
5458
5633
  }
5459
5634
  };
5460
5635
  // Store coordination plan in _system directory
5461
- await this.addNoun({
5636
+ await this.addNoun('Cortex coordination plan', NounType.Process, {
5462
5637
  id: '_system/coordination',
5463
5638
  type: 'cortex_coordination',
5464
- metadata: coordinationPlan
5639
+ ...coordinationPlan
5465
5640
  });
5466
5641
  prodLog.info('📋 Storage migration coordination plan created');
5467
5642
  prodLog.info('All services will automatically detect and execute the migration');
@@ -5686,8 +5861,16 @@ export class BrainyData {
5686
5861
  */
5687
5862
  async deleteNouns(ids) {
5688
5863
  const results = [];
5689
- for (const id of ids) {
5690
- results.push(await this.deleteNoun(id));
5864
+ const chunkSize = 10; // Conservative chunk size for parallel processing
5865
+ // Process deletions in parallel chunks to improve performance
5866
+ for (let i = 0; i < ids.length; i += chunkSize) {
5867
+ const chunk = ids.slice(i, i + chunkSize);
5868
+ // Process chunk in parallel
5869
+ const chunkPromises = chunk.map(id => this.deleteNoun(id));
5870
+ // Wait for all in chunk to complete
5871
+ const chunkResults = await Promise.all(chunkPromises);
5872
+ // Maintain order by adding chunk results
5873
+ results.push(...chunkResults);
5691
5874
  }
5692
5875
  return results;
5693
5876
  }
@@ -5712,7 +5895,7 @@ export class BrainyData {
5712
5895
  // For data updates, we need to regenerate the vector
5713
5896
  const existingNoun = this.index.getNouns().get(id);
5714
5897
  if (!existingNoun) {
5715
- throw new Error(`Noun with ID ${id} does not exist`);
5898
+ throw BrainyError.notFound(`Noun with ID ${id}`);
5716
5899
  }
5717
5900
  // Get existing metadata from storage (not just from index)
5718
5901
  const existingMetadata = await this.storage.getMetadata(id) || {};
@@ -5801,7 +5984,7 @@ export class BrainyData {
5801
5984
  // Check if a vector exists
5802
5985
  const noun = this.index.getNouns().get(id);
5803
5986
  if (!noun) {
5804
- throw new Error(`Vector with ID ${id} does not exist`);
5987
+ throw BrainyError.notFound(`Vector with ID ${id}`);
5805
5988
  }
5806
5989
  // Get existing metadata to preserve namespaces
5807
5990
  const existing = await this.storage.getMetadata(id) || {};
@@ -5868,34 +6051,41 @@ export class BrainyData {
5868
6051
  get neural() {
5869
6052
  if (!this._neural) {
5870
6053
  // Create the unified Neural API instance
5871
- this._neural = new NeuralAPI(this);
6054
+ this._neural = new ImprovedNeuralAPI(this);
5872
6055
  }
5873
6056
  return this._neural;
5874
6057
  }
5875
6058
  /**
5876
6059
  * Simple similarity check (shorthand for neural.similar)
5877
6060
  */
5878
- async similar(a, b) {
5879
- return this.neural.similar(a, b);
6061
+ async similar(a, b, options) {
6062
+ const result = await this.neural.similar(a, b, options);
6063
+ // Always return simple number for main class shortcut
6064
+ return typeof result === 'object' ? result.score : result;
5880
6065
  }
5881
6066
  /**
5882
6067
  * Get semantic clusters (shorthand for neural.clusters)
5883
6068
  */
5884
- async clusters(options) {
5885
- return this.neural.clusters(options);
6069
+ async clusters(items, options) {
6070
+ // Support both (items, options) and (options) patterns
6071
+ if (typeof items === 'object' && !Array.isArray(items) && options === undefined) {
6072
+ // First argument is options object
6073
+ return this.neural.clusters(items);
6074
+ }
6075
+ // Standard (items, options) pattern
6076
+ if (options) {
6077
+ return this.neural.clusters({ ...options, items });
6078
+ }
6079
+ return this.neural.clusters(items);
5886
6080
  }
5887
6081
  /**
5888
6082
  * Get related items (shorthand for neural.neighbors)
5889
6083
  */
5890
- async related(id, limit) {
5891
- const result = await this.neural.neighbors(id, { limit });
5892
- return result.neighbors;
5893
- }
5894
- /**
5895
- * Get visualization data (shorthand for neural.visualize)
5896
- */
5897
- async visualize(options) {
5898
- return this.neural.visualize(options);
6084
+ async related(id, options) {
6085
+ const limit = typeof options === 'number' ? options : options?.limit;
6086
+ const fullOptions = typeof options === 'number' ? { limit } : options;
6087
+ const result = await this.neural.neighbors(id, fullOptions);
6088
+ return result.neighbors || [];
5899
6089
  }
5900
6090
  /**
5901
6091
  * 🚀 TRIPLE INTELLIGENCE SEARCH - Natural Language & Complex Queries
@@ -5924,60 +6114,9 @@ export class BrainyData {
5924
6114
  const { limit = 10, offset = 0, cursor, mode = 'auto', maxDepth = 2, parallel = true, timeout, excludeDeleted = true } = options || {};
5925
6115
  // Validate and cap limit for safety
5926
6116
  const safeLimit = Math.min(limit, 10000);
5927
- if (!this._tripleEngine) {
5928
- this._tripleEngine = new TripleIntelligenceEngine(this);
5929
- }
5930
- // 🎆 NATURAL LANGUAGE AUTO-BREAKDOWN
5931
- // If query is a string, auto-convert to structured Triple Intelligence query
5932
- let processedQuery;
5933
- if (typeof query === 'string') {
5934
- // Use Brainy's sophisticated natural language processing
5935
- processedQuery = await this.processNaturalLanguage(query);
5936
- }
5937
- else {
5938
- processedQuery = query;
5939
- }
5940
- // Apply pagination options
5941
- processedQuery.limit = safeLimit;
5942
- // Handle cursor-based pagination
5943
- if (cursor) {
5944
- const decodedCursor = this.decodeCursor(cursor);
5945
- processedQuery.offset = decodedCursor.offset;
5946
- }
5947
- else if (offset > 0) {
5948
- processedQuery.offset = offset;
5949
- }
5950
- // Add soft-delete filter using POSITIVE match (O(1) hash lookup)
5951
- // We use _brainy.deleted to avoid conflicts with user metadata
5952
- if (excludeDeleted) {
5953
- if (!processedQuery.where) {
5954
- processedQuery.where = {};
5955
- }
5956
- // Use namespaced field for O(1) hash lookup in metadata index
5957
- processedQuery.where['_brainy.deleted'] = false; // or { equals: false }
5958
- }
5959
- // Apply mode-specific optimizations
5960
- if (mode !== 'auto') {
5961
- processedQuery.mode = mode;
5962
- }
5963
- // Apply graph traversal depth limit
5964
- if (processedQuery.connected) {
5965
- processedQuery.connected.maxDepth = Math.min(processedQuery.connected.maxDepth || maxDepth, maxDepth);
5966
- }
5967
- // Execute with Triple Intelligence engine
5968
- const results = await this._tripleEngine.find(processedQuery);
5969
- // Generate next cursor if we hit the limit
5970
- if (results.length === safeLimit) {
5971
- const nextCursor = this.encodeCursor({
5972
- offset: (offset || 0) + safeLimit,
5973
- timestamp: Date.now()
5974
- });
5975
- // Attach cursor to last result for convenience
5976
- if (results.length > 0) {
5977
- results[results.length - 1].nextCursor = nextCursor;
5978
- }
5979
- }
5980
- return results;
6117
+ // Triple Intelligence now requires Brainy, not BrainyData
6118
+ // BrainyData is deprecated - use Brainy.find() instead
6119
+ throw new Error('Triple Intelligence search is not available in BrainyData. Please use Brainy.find() instead.');
5981
6120
  }
5982
6121
  /**
5983
6122
  * 🧠 NATURAL LANGUAGE PROCESSING - Auto-breakdown using all Brainy features
@@ -6127,7 +6266,7 @@ export class BrainyData {
6127
6266
  * @returns The BrainyData instance for chaining
6128
6267
  */
6129
6268
  unregister(name) {
6130
- augmentationPipeline.unregister(name);
6269
+ // Deprecated: use brain.augmentations instead
6131
6270
  return this;
6132
6271
  }
6133
6272
  /**
@@ -6138,7 +6277,8 @@ export class BrainyData {
6138
6277
  * @returns True if augmentation was found and enabled
6139
6278
  */
6140
6279
  enableAugmentation(name) {
6141
- return augmentationPipeline.enableAugmentation(name);
6280
+ // Deprecated: use brain.augmentations instead
6281
+ return false;
6142
6282
  }
6143
6283
  /**
6144
6284
  * Disable an augmentation by name
@@ -6148,7 +6288,8 @@ export class BrainyData {
6148
6288
  * @returns True if augmentation was found and disabled
6149
6289
  */
6150
6290
  disableAugmentation(name) {
6151
- return augmentationPipeline.disableAugmentation(name);
6291
+ // Deprecated: use brain.augmentations instead
6292
+ return false;
6152
6293
  }
6153
6294
  /**
6154
6295
  * Check if an augmentation is enabled
@@ -6157,7 +6298,8 @@ export class BrainyData {
6157
6298
  * @returns True if augmentation is found and enabled, false otherwise
6158
6299
  */
6159
6300
  isAugmentationEnabled(name) {
6160
- return augmentationPipeline.isAugmentationEnabled(name);
6301
+ // Deprecated: use brain.augmentations instead
6302
+ return false;
6161
6303
  }
6162
6304
  /**
6163
6305
  * Get all augmentations with their enabled status
@@ -6166,7 +6308,13 @@ export class BrainyData {
6166
6308
  * @returns Array of augmentations with name, type, and enabled status
6167
6309
  */
6168
6310
  listAugmentations() {
6169
- return augmentationPipeline.listAugmentationsWithStatus();
6311
+ // Use the real augmentation registry instead of deprecated pipeline
6312
+ return this.augmentations.getInfo().map(aug => ({
6313
+ name: aug.name,
6314
+ type: aug.category, // Map category to type for backward compatibility
6315
+ enabled: aug.enabled,
6316
+ description: aug.description
6317
+ }));
6170
6318
  }
6171
6319
  /**
6172
6320
  * Enable all augmentations of a specific type
@@ -6175,7 +6323,8 @@ export class BrainyData {
6175
6323
  * @returns Number of augmentations enabled
6176
6324
  */
6177
6325
  enableAugmentationType(type) {
6178
- return augmentationPipeline.enableAugmentationType(type);
6326
+ // Deprecated: use brain.augmentations instead
6327
+ return 0;
6179
6328
  }
6180
6329
  /**
6181
6330
  * Disable all augmentations of a specific type
@@ -6184,7 +6333,8 @@ export class BrainyData {
6184
6333
  * @returns Number of augmentations disabled
6185
6334
  */
6186
6335
  disableAugmentationType(type) {
6187
- return augmentationPipeline.disableAugmentationType(type);
6336
+ // Deprecated: use brain.augmentations instead
6337
+ return 0;
6188
6338
  }
6189
6339
  // ===== Enhanced Clear Methods (2.0.0 API) =====
6190
6340
  /**
@@ -6275,6 +6425,12 @@ export class BrainyData {
6275
6425
  throw new Error(`Failed to clear all data: ${error}`);
6276
6426
  }
6277
6427
  }
6428
+ // ================================================================
6429
+ // SECTION 9: UTILITIES & CLEANUP
6430
+ // ================================================================
6431
+ // System utilities, cleanup operations, and maintenance functions
6432
+ // Includes clearAll(), database maintenance, and system shutdown operations
6433
+ // Essential maintenance and administrative functionality
6278
6434
  /**
6279
6435
  * Clear all data from the database (alias for clear)
6280
6436
  * @param options Options including force flag to skip confirmation