@soulcraft/brainy 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -3
- package/README.md +427 -111
- package/bin/brainy.js +340 -62
- package/dist/api/ConfigAPI.d.ts +67 -0
- package/dist/api/ConfigAPI.js +166 -0
- package/dist/api/DataAPI.d.ts +123 -0
- package/dist/api/DataAPI.js +391 -0
- package/dist/api/SecurityAPI.d.ts +50 -0
- package/dist/api/SecurityAPI.js +139 -0
- package/dist/api/UniversalImportAPI.d.ts +134 -0
- package/dist/api/UniversalImportAPI.js +615 -0
- package/dist/augmentationManager.js +12 -7
- package/dist/augmentationPipeline.d.ts +0 -61
- package/dist/augmentationPipeline.js +0 -87
- package/dist/augmentationRegistry.d.ts +1 -1
- package/dist/augmentationRegistry.js +1 -1
- package/dist/augmentations/apiServerAugmentation.d.ts +27 -1
- package/dist/augmentations/apiServerAugmentation.js +290 -9
- package/dist/augmentations/auditLogAugmentation.d.ts +109 -0
- package/dist/augmentations/auditLogAugmentation.js +358 -0
- package/dist/augmentations/batchProcessingAugmentation.d.ts +3 -2
- package/dist/augmentations/batchProcessingAugmentation.js +123 -22
- package/dist/augmentations/brainyAugmentation.d.ts +142 -8
- package/dist/augmentations/brainyAugmentation.js +179 -2
- package/dist/augmentations/cacheAugmentation.d.ts +8 -5
- package/dist/augmentations/cacheAugmentation.js +116 -17
- package/dist/augmentations/conduitAugmentations.d.ts +2 -2
- package/dist/augmentations/conduitAugmentations.js +2 -2
- package/dist/augmentations/configResolver.d.ts +122 -0
- package/dist/augmentations/configResolver.js +440 -0
- package/dist/augmentations/connectionPoolAugmentation.d.ts +3 -1
- package/dist/augmentations/connectionPoolAugmentation.js +37 -12
- package/dist/augmentations/defaultAugmentations.d.ts +14 -10
- package/dist/augmentations/defaultAugmentations.js +16 -11
- package/dist/augmentations/discovery/catalogDiscovery.d.ts +142 -0
- package/dist/augmentations/discovery/catalogDiscovery.js +249 -0
- package/dist/augmentations/discovery/localDiscovery.d.ts +84 -0
- package/dist/augmentations/discovery/localDiscovery.js +246 -0
- package/dist/augmentations/discovery/runtimeLoader.d.ts +97 -0
- package/dist/augmentations/discovery/runtimeLoader.js +337 -0
- package/dist/augmentations/discovery.d.ts +152 -0
- package/dist/augmentations/discovery.js +441 -0
- package/dist/augmentations/display/cache.d.ts +130 -0
- package/dist/augmentations/display/cache.js +319 -0
- package/dist/augmentations/display/fieldPatterns.d.ts +52 -0
- package/dist/augmentations/display/fieldPatterns.js +393 -0
- package/dist/augmentations/display/iconMappings.d.ts +57 -0
- package/dist/augmentations/display/iconMappings.js +68 -0
- package/dist/augmentations/display/intelligentComputation.d.ts +109 -0
- package/dist/augmentations/display/intelligentComputation.js +462 -0
- package/dist/augmentations/display/types.d.ts +203 -0
- package/dist/augmentations/display/types.js +7 -0
- package/dist/augmentations/entityRegistryAugmentation.d.ts +3 -1
- package/dist/augmentations/entityRegistryAugmentation.js +5 -1
- package/dist/augmentations/indexAugmentation.d.ts +5 -3
- package/dist/augmentations/indexAugmentation.js +5 -2
- package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +24 -7
- package/dist/augmentations/intelligentVerbScoringAugmentation.js +111 -27
- package/dist/augmentations/manifest.d.ts +176 -0
- package/dist/augmentations/manifest.js +8 -0
- package/dist/augmentations/marketplace/AugmentationMarketplace.d.ts +168 -0
- package/dist/augmentations/marketplace/AugmentationMarketplace.js +329 -0
- package/dist/augmentations/marketplace/cli.d.ts +47 -0
- package/dist/augmentations/marketplace/cli.js +265 -0
- package/dist/augmentations/metricsAugmentation.d.ts +3 -3
- package/dist/augmentations/metricsAugmentation.js +2 -2
- package/dist/augmentations/monitoringAugmentation.d.ts +3 -3
- package/dist/augmentations/monitoringAugmentation.js +2 -2
- package/dist/augmentations/neuralImport.d.ts +1 -1
- package/dist/augmentations/neuralImport.js +4 -4
- package/dist/augmentations/rateLimitAugmentation.d.ts +82 -0
- package/dist/augmentations/rateLimitAugmentation.js +321 -0
- package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +2 -2
- package/dist/augmentations/requestDeduplicatorAugmentation.js +1 -1
- package/dist/augmentations/storageAugmentation.d.ts +1 -1
- package/dist/augmentations/storageAugmentation.js +2 -2
- package/dist/augmentations/storageAugmentations.d.ts +37 -8
- package/dist/augmentations/storageAugmentations.js +204 -15
- package/dist/augmentations/synapseAugmentation.d.ts +1 -1
- package/dist/augmentations/synapseAugmentation.js +35 -16
- package/dist/augmentations/typeMatching/brainyTypes.d.ts +83 -0
- package/dist/augmentations/typeMatching/brainyTypes.js +425 -0
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.d.ts +39 -59
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.js +103 -389
- package/dist/augmentations/universalDisplayAugmentation.d.ts +191 -0
- package/dist/augmentations/universalDisplayAugmentation.js +371 -0
- package/dist/brainy-unified.d.ts +106 -0
- package/dist/brainy-unified.js +327 -0
- package/dist/brainy.d.ts +277 -0
- package/dist/brainy.js +1241 -0
- package/dist/brainyData.d.ts +56 -111
- package/dist/brainyData.js +912 -756
- package/dist/brainyDataV3.d.ts +186 -0
- package/dist/brainyDataV3.js +337 -0
- package/dist/config/distributedPresets-new.d.ts +118 -0
- package/dist/config/distributedPresets-new.js +318 -0
- package/dist/config/distributedPresets.d.ts +118 -0
- package/dist/config/distributedPresets.js +318 -0
- package/dist/config/extensibleConfig.d.ts +99 -0
- package/dist/config/extensibleConfig.js +268 -0
- package/dist/config/index.d.ts +17 -0
- package/dist/config/index.js +35 -0
- package/dist/config/modelAutoConfig.d.ts +32 -0
- package/dist/config/modelAutoConfig.js +139 -0
- package/dist/config/modelPrecisionManager.d.ts +42 -0
- package/dist/config/modelPrecisionManager.js +98 -0
- package/dist/config/sharedConfigManager.d.ts +67 -0
- package/dist/config/sharedConfigManager.js +215 -0
- package/dist/config/storageAutoConfig.d.ts +41 -0
- package/dist/config/storageAutoConfig.js +328 -0
- package/dist/config/zeroConfig.d.ts +68 -0
- package/dist/config/zeroConfig.js +301 -0
- package/dist/cortex/backupRestore.d.ts +2 -2
- package/dist/cortex/backupRestore.js +85 -27
- package/dist/cortex/healthCheck.d.ts +2 -2
- package/dist/cortex/neuralImport.d.ts +2 -2
- package/dist/cortex/neuralImport.js +18 -13
- package/dist/cortex/performanceMonitor.d.ts +2 -2
- package/dist/critical/model-guardian.d.ts +4 -0
- package/dist/critical/model-guardian.js +31 -11
- package/dist/demo.d.ts +4 -4
- package/dist/demo.js +7 -7
- package/dist/distributed/cacheSync.d.ts +112 -0
- package/dist/distributed/cacheSync.js +265 -0
- package/dist/distributed/coordinator.d.ts +193 -0
- package/dist/distributed/coordinator.js +548 -0
- package/dist/distributed/httpTransport.d.ts +120 -0
- package/dist/distributed/httpTransport.js +446 -0
- package/dist/distributed/index.d.ts +8 -0
- package/dist/distributed/index.js +5 -0
- package/dist/distributed/networkTransport.d.ts +132 -0
- package/dist/distributed/networkTransport.js +633 -0
- package/dist/distributed/queryPlanner.d.ts +104 -0
- package/dist/distributed/queryPlanner.js +327 -0
- package/dist/distributed/readWriteSeparation.d.ts +134 -0
- package/dist/distributed/readWriteSeparation.js +350 -0
- package/dist/distributed/shardManager.d.ts +114 -0
- package/dist/distributed/shardManager.js +357 -0
- package/dist/distributed/shardMigration.d.ts +110 -0
- package/dist/distributed/shardMigration.js +289 -0
- package/dist/distributed/storageDiscovery.d.ts +160 -0
- package/dist/distributed/storageDiscovery.js +551 -0
- package/dist/embeddings/CachedEmbeddings.d.ts +40 -0
- package/dist/embeddings/CachedEmbeddings.js +146 -0
- package/dist/embeddings/EmbeddingManager.d.ts +102 -0
- package/dist/embeddings/EmbeddingManager.js +291 -0
- package/dist/embeddings/SingletonModelManager.d.ts +95 -0
- package/dist/embeddings/SingletonModelManager.js +220 -0
- package/dist/embeddings/index.d.ts +12 -0
- package/dist/embeddings/index.js +16 -0
- package/dist/embeddings/lightweight-embedder.d.ts +0 -1
- package/dist/embeddings/lightweight-embedder.js +4 -12
- package/dist/embeddings/model-manager.d.ts +11 -0
- package/dist/embeddings/model-manager.js +43 -7
- package/dist/embeddings/universal-memory-manager.d.ts +1 -1
- package/dist/embeddings/universal-memory-manager.js +27 -67
- package/dist/embeddings/worker-embedding.js +4 -8
- package/dist/errors/brainyError.d.ts +5 -1
- package/dist/errors/brainyError.js +12 -0
- package/dist/examples/basicUsage.js +7 -4
- package/dist/graph/graphAdjacencyIndex.d.ts +96 -0
- package/dist/graph/graphAdjacencyIndex.js +288 -0
- package/dist/graph/pathfinding.js +4 -2
- package/dist/hnsw/scaledHNSWSystem.js +11 -2
- package/dist/importManager.js +8 -5
- package/dist/index.d.ts +17 -22
- package/dist/index.js +37 -23
- package/dist/mcp/brainyMCPAdapter.d.ts +4 -4
- package/dist/mcp/brainyMCPAdapter.js +5 -5
- package/dist/mcp/brainyMCPService.d.ts +3 -3
- package/dist/mcp/brainyMCPService.js +3 -11
- package/dist/mcp/mcpAugmentationToolset.js +20 -30
- package/dist/neural/embeddedPatterns.d.ts +1 -1
- package/dist/neural/embeddedPatterns.js +2 -2
- package/dist/neural/entityExtractor.d.ts +65 -0
- package/dist/neural/entityExtractor.js +316 -0
- package/dist/neural/improvedNeuralAPI.d.ts +357 -0
- package/dist/neural/improvedNeuralAPI.js +2628 -0
- package/dist/neural/naturalLanguageProcessor.d.ts +155 -10
- package/dist/neural/naturalLanguageProcessor.js +941 -66
- package/dist/neural/naturalLanguageProcessorStatic.d.ts +2 -2
- package/dist/neural/naturalLanguageProcessorStatic.js +3 -3
- package/dist/neural/neuralAPI.js +8 -2
- package/dist/neural/patternLibrary.d.ts +57 -3
- package/dist/neural/patternLibrary.js +348 -13
- package/dist/neural/staticPatternMatcher.d.ts +2 -2
- package/dist/neural/staticPatternMatcher.js +2 -2
- package/dist/neural/types.d.ts +287 -0
- package/dist/neural/types.js +24 -0
- package/dist/shared/default-augmentations.d.ts +3 -3
- package/dist/shared/default-augmentations.js +5 -5
- package/dist/storage/adapters/baseStorageAdapter.d.ts +42 -0
- package/dist/storage/adapters/fileSystemStorage.d.ts +26 -2
- package/dist/storage/adapters/fileSystemStorage.js +218 -15
- package/dist/storage/adapters/memoryStorage.d.ts +4 -4
- package/dist/storage/adapters/memoryStorage.js +17 -12
- package/dist/storage/adapters/opfsStorage.d.ts +2 -2
- package/dist/storage/adapters/opfsStorage.js +2 -2
- package/dist/storage/adapters/s3CompatibleStorage.d.ts +2 -2
- package/dist/storage/adapters/s3CompatibleStorage.js +2 -2
- package/dist/storage/backwardCompatibility.d.ts +10 -78
- package/dist/storage/backwardCompatibility.js +17 -132
- package/dist/storage/baseStorage.d.ts +18 -2
- package/dist/storage/baseStorage.js +74 -3
- package/dist/storage/cacheManager.js +2 -2
- package/dist/storage/readOnlyOptimizations.js +8 -3
- package/dist/streaming/pipeline.d.ts +154 -0
- package/dist/streaming/pipeline.js +551 -0
- package/dist/triple/TripleIntelligence.d.ts +25 -110
- package/dist/triple/TripleIntelligence.js +4 -574
- package/dist/triple/TripleIntelligenceSystem.d.ts +159 -0
- package/dist/triple/TripleIntelligenceSystem.js +519 -0
- package/dist/types/apiTypes.d.ts +278 -0
- package/dist/types/apiTypes.js +33 -0
- package/dist/types/brainy.types.d.ts +308 -0
- package/dist/types/brainy.types.js +8 -0
- package/dist/types/brainyDataInterface.d.ts +5 -8
- package/dist/types/brainyDataInterface.js +2 -2
- package/dist/types/graphTypes.js +2 -2
- package/dist/universal/crypto.d.ts +11 -1
- package/dist/universal/crypto.js +24 -93
- package/dist/universal/events.d.ts +3 -2
- package/dist/universal/events.js +6 -75
- package/dist/universal/fs.d.ts +2 -3
- package/dist/universal/fs.js +5 -211
- package/dist/universal/path.d.ts +3 -2
- package/dist/universal/path.js +22 -78
- package/dist/universal/uuid.d.ts +1 -1
- package/dist/universal/uuid.js +1 -1
- package/dist/utils/brainyTypes.d.ts +217 -0
- package/dist/utils/brainyTypes.js +261 -0
- package/dist/utils/cacheAutoConfig.d.ts +3 -3
- package/dist/utils/embedding.d.ts +9 -4
- package/dist/utils/embedding.js +89 -26
- package/dist/utils/enhancedLogger.d.ts +104 -0
- package/dist/utils/enhancedLogger.js +232 -0
- package/dist/utils/hybridModelManager.d.ts +19 -28
- package/dist/utils/hybridModelManager.js +36 -200
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/intelligentTypeMapper.d.ts +60 -0
- package/dist/utils/intelligentTypeMapper.js +349 -0
- package/dist/utils/metadataIndex.d.ts +118 -1
- package/dist/utils/metadataIndex.js +539 -16
- package/dist/utils/nodeVersionCheck.d.ts +24 -0
- package/dist/utils/nodeVersionCheck.js +65 -0
- package/dist/utils/paramValidation.d.ts +39 -0
- package/dist/utils/paramValidation.js +192 -0
- package/dist/utils/rateLimiter.d.ts +160 -0
- package/dist/utils/rateLimiter.js +271 -0
- package/dist/utils/statistics.d.ts +4 -4
- package/dist/utils/statistics.js +3 -3
- package/dist/utils/structuredLogger.d.ts +146 -0
- package/dist/utils/structuredLogger.js +394 -0
- package/dist/utils/textEncoding.js +2 -1
- package/dist/utils/typeValidation.d.ts +59 -0
- package/dist/utils/typeValidation.js +374 -0
- package/dist/utils/version.js +19 -3
- package/package.json +15 -17
- package/scripts/download-models.cjs +94 -20
- package/dist/augmentations/walAugmentation.d.ts +0 -109
- package/dist/augmentations/walAugmentation.js +0 -516
- package/dist/browserFramework.d.ts +0 -15
- package/dist/browserFramework.js +0 -31
- package/dist/browserFramework.minimal.d.ts +0 -14
- package/dist/browserFramework.minimal.js +0 -31
- package/dist/chat/BrainyChat.d.ts +0 -121
- package/dist/chat/BrainyChat.js +0 -396
- package/dist/chat/ChatCLI.d.ts +0 -61
- package/dist/chat/ChatCLI.js +0 -351
package/dist/brainyData.js
CHANGED
|
@@ -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 {
|
|
15
|
-
import {
|
|
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 {
|
|
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
|
-
//
|
|
127
|
-
|
|
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:
|
|
300
|
-
const intelligentVerbAugmentation = new IntelligentVerbScoringAugmentation(this.config.intelligentVerbScoring || { enabled:
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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
|
|
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
|
|
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
|
|
836
|
-
//
|
|
837
|
-
for (const
|
|
838
|
-
|
|
839
|
-
|
|
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
|
-
//
|
|
882
|
-
|
|
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 {
|
|
886
|
-
|
|
887
|
-
|
|
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.
|
|
891
|
-
|
|
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
|
-
|
|
897
|
-
|
|
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
|
-
*
|
|
1166
|
-
*
|
|
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
|
-
|
|
1169
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
//
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
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
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
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
|
-
*
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
*
|
|
1212
|
-
|
|
1213
|
-
|
|
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
|
|
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
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
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
|
-
//
|
|
1444
|
+
// Validate the type is valid
|
|
1240
1445
|
try {
|
|
1241
|
-
|
|
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 (
|
|
1279
|
-
|
|
1448
|
+
catch (error) {
|
|
1449
|
+
invalidItems.push(index);
|
|
1280
1450
|
}
|
|
1281
1451
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
//
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
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
|
-
//
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
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
|
-
|
|
1313
|
-
//
|
|
1314
|
-
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
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
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
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
|
-
//
|
|
1954
|
-
const
|
|
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 (
|
|
1957
|
-
metadataFilter.nounType = { in:
|
|
1844
|
+
if (validatedOptions.nounTypes && validatedOptions.nounTypes.length > 0) {
|
|
1845
|
+
metadataFilter.nounType = { in: validatedOptions.nounTypes };
|
|
1958
1846
|
}
|
|
1959
1847
|
// Add item ID filtering
|
|
1960
|
-
if (
|
|
1961
|
-
metadataFilter.id = { in:
|
|
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:
|
|
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:
|
|
1974
|
-
offset:
|
|
1975
|
-
cursor:
|
|
1976
|
-
excludeDeleted:
|
|
1977
|
-
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 (
|
|
1983
|
-
results = results.filter(r => (r.fusionScore || r.score || 0) >=
|
|
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
|
-
|
|
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
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
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
|
-
|
|
3265
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
5329
|
+
throw BrainyError.notFound(`Source noun with ID ${sourceId}`);
|
|
5155
5330
|
}
|
|
5156
5331
|
if (!targetNoun) {
|
|
5157
|
-
throw
|
|
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
|
-
|
|
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
|
-
|
|
5690
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
5891
|
-
const
|
|
5892
|
-
|
|
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
|
-
|
|
5928
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|