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