2025-08-26 12:32:21 -07:00
/ * *
* Automatic Configuration System for Brainy Vector Database
* Detects environment , resources , and data patterns to provide optimal settings
* /
import { isBrowser , isNode , isThreadingAvailable } from './environment.js'
export interface AutoConfigResult {
// Environment details
environment : 'browser' | 'nodejs' | 'serverless' | 'unknown'
// Resource detection
availableMemory : number // bytes
cpuCores : number
threadingAvailable : boolean
// Storage capabilities
persistentStorageAvailable : boolean
s3StorageDetected : boolean
// Recommended configuration
recommendedConfig : {
expectedDatasetSize : number
maxMemoryUsage : number
targetSearchLatency : number
enablePartitioning : boolean
enableCompression : boolean
enableDistributedSearch : boolean
enablePredictiveCaching : boolean
partitionStrategy : 'semantic' | 'hash'
maxNodesPerPartition : number
semanticClusters : number
}
// Performance optimization flags
optimizationFlags : {
useMemoryMapping : boolean
aggressiveCaching : boolean
backgroundOptimization : boolean
compressionLevel : 'none' | 'light' | 'aggressive'
}
}
export interface DatasetAnalysis {
estimatedSize : number
vectorDimension? : number
growthRate? : number // vectors per second
accessPatterns ? : 'read-heavy' | 'write-heavy' | 'balanced'
}
/ * *
* Automatic configuration system that detects environment and optimizes settings
* /
export class AutoConfiguration {
private static instance : AutoConfiguration
private cachedConfig : AutoConfigResult | null = null
private datasetStats : DatasetAnalysis = { estimatedSize : 0 }
private constructor ( ) { }
public static getInstance ( ) : AutoConfiguration {
if ( ! AutoConfiguration . instance ) {
AutoConfiguration . instance = new AutoConfiguration ( )
}
return AutoConfiguration . instance
}
/ * *
* Detect environment and generate optimal configuration
* /
public async detectAndConfigure ( hints ? : {
expectedDataSize? : number
s3Available? : boolean
memoryBudget? : number
} ) : Promise < AutoConfigResult > {
if ( this . cachedConfig && ! hints ) {
return this . cachedConfig
}
const environment = this . detectEnvironment ( )
const resources = await this . detectResources ( )
const storage = await this . detectStorageCapabilities ( hints ? . s3Available )
const config : AutoConfigResult = {
environment ,
. . . resources ,
. . . storage ,
recommendedConfig : this.generateRecommendedConfig ( environment , resources , hints ) ,
optimizationFlags : this.generateOptimizationFlags ( environment , resources )
}
this . cachedConfig = config
return config
}
/ * *
* Update configuration based on runtime dataset analysis
* /
public async adaptToDataset ( analysis : DatasetAnalysis ) : Promise < AutoConfigResult > {
this . datasetStats = analysis
// Regenerate configuration with dataset insights
const currentConfig = await this . detectAndConfigure ( )
const adaptedConfig = this . adaptConfigurationToData ( currentConfig , analysis )
this . cachedConfig = adaptedConfig
return adaptedConfig
}
/ * *
* Learn from performance metrics and adjust configuration
* /
public async learnFromPerformance ( metrics : {
averageSearchTime : number
memoryUsage : number
cacheHitRate : number
errorRate : number
} ) : Promise < Partial < AutoConfigResult [ 'recommendedConfig' ] > > {
const adjustments : Partial < AutoConfigResult [ 'recommendedConfig' ] > = { }
// Learn from search performance
if ( metrics . averageSearchTime > 200 ) {
// Too slow - optimize for speed
adjustments . enableDistributedSearch = true
adjustments . maxNodesPerPartition = Math . max ( 10000 , ( this . cachedConfig ? . recommendedConfig . maxNodesPerPartition || 50000 ) * 0.8 )
} else if ( metrics . averageSearchTime < 50 ) {
// Very fast - can optimize for quality
adjustments . maxNodesPerPartition = Math . min ( 100000 , ( this . cachedConfig ? . recommendedConfig . maxNodesPerPartition || 50000 ) * 1.2 )
}
// Learn from memory usage
if ( metrics . memoryUsage > ( this . cachedConfig ? . recommendedConfig . maxMemoryUsage || 0 ) * 0.9 ) {
// High memory usage - enable compression
adjustments . enableCompression = true
}
// Learn from cache performance
if ( metrics . cacheHitRate < 0.7 ) {
// Poor cache performance - enable predictive caching
adjustments . enablePredictiveCaching = true
}
// Update cached config with learned adjustments
if ( this . cachedConfig ) {
this . cachedConfig . recommendedConfig = {
. . . this . cachedConfig . recommendedConfig ,
. . . adjustments
}
}
return adjustments
}
/ * *
* Get minimal configuration for quick setup
* /
public async getQuickSetupConfig ( scenario : 'small' | 'medium' | 'large' | 'enterprise' ) : Promise < {
expectedDatasetSize : number
maxMemoryUsage : number
targetSearchLatency : number
s3Required : boolean
} > {
const environment = this . detectEnvironment ( )
const resources = await this . detectResources ( )
switch ( scenario ) {
case 'small' :
return {
expectedDatasetSize : 10000 ,
maxMemoryUsage : Math.min ( resources . availableMemory * 0.3 , 1024 * 1024 * 1024 ) , // 1GB max
targetSearchLatency : 100 ,
s3Required : false
}
case 'medium' :
return {
expectedDatasetSize : 100000 ,
maxMemoryUsage : Math.min ( resources . availableMemory * 0.5 , 4 * 1024 * 1024 * 1024 ) , // 4GB max
targetSearchLatency : 150 ,
s3Required : environment === 'serverless'
}
case 'large' :
return {
expectedDatasetSize : 1000000 ,
maxMemoryUsage : Math.min ( resources . availableMemory * 0.7 , 8 * 1024 * 1024 * 1024 ) , // 8GB max
targetSearchLatency : 200 ,
s3Required : true
}
case 'enterprise' :
return {
expectedDatasetSize : 10000000 ,
maxMemoryUsage : Math.min ( resources . availableMemory * 0.8 , 32 * 1024 * 1024 * 1024 ) , // 32GB max
targetSearchLatency : 300 ,
s3Required : true
}
}
}
/ * *
* Detect the current runtime environment
* /
private detectEnvironment ( ) : 'browser' | 'nodejs' | 'serverless' | 'unknown' {
if ( isBrowser ( ) ) {
return 'browser'
}
if ( isNode ( ) ) {
// Check for serverless environment indicators
if ( process . env . AWS_LAMBDA_FUNCTION_NAME ||
process . env . VERCEL ||
process . env . NETLIFY ||
process . env . CLOUDFLARE_WORKERS ) {
return 'serverless'
}
return 'nodejs'
}
return 'unknown'
}
/ * *
* Detect available system resources
* /
private async detectResources ( ) : Promise < {
availableMemory : number
cpuCores : number
threadingAvailable : boolean
} > {
let availableMemory = 2 * 1024 * 1024 * 1024 // Default 2GB
let cpuCores = 4 // Default 4 cores
// Browser memory detection
if ( isBrowser ( ) ) {
// @ts-ignore - navigator.deviceMemory is experimental
if ( navigator . deviceMemory ) {
// @ts-ignore
availableMemory = navigator . deviceMemory * 1024 * 1024 * 1024 * 0.3 // Use 30% of device memory
} else {
availableMemory = 512 * 1024 * 1024 // Conservative 512MB for browsers
}
cpuCores = navigator . hardwareConcurrency || 4
}
// Node.js memory detection
if ( isNode ( ) ) {
try {
feat: add node: protocol to all Node.js built-in imports for bundler compatibility
- Updated all fs, path, crypto, os, url, util, events, http, https, net, child_process, stream, and zlib imports
- Changed both static imports and dynamic imports to use node: protocol
- This makes Brainy more bundler-friendly by explicitly marking Node.js built-ins
- Prevents bundlers from attempting to polyfill or bundle these modules
- Reduces bundle size for web applications using Brainy
- Improves tree-shaking and dead code elimination
Benefits for external bundlers:
- Clear distinction between Node.js built-ins and external dependencies
- No ambiguity about what needs polyfilling
- Smaller bundles for browser builds
- Better compatibility with modern bundlers (Webpack 5, Vite, Rollup, esbuild)
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 14:20:21 -07:00
const os = await import ( 'node:os' )
2025-08-26 12:32:21 -07:00
availableMemory = os . totalmem ( ) * 0.7 // Use 70% of total memory
cpuCores = os . cpus ( ) . length
} catch ( error ) {
// Fallback to defaults
}
}
return {
availableMemory ,
cpuCores ,
threadingAvailable : isThreadingAvailable ( )
}
}
/ * *
* Detect available storage capabilities
* /
private async detectStorageCapabilities ( s3Hint? : boolean ) : Promise < {
persistentStorageAvailable : boolean
s3StorageDetected : boolean
} > {
let persistentStorageAvailable = false
let s3StorageDetected = s3Hint || false
if ( isBrowser ( ) ) {
// Check for OPFS support
persistentStorageAvailable = 'navigator' in globalThis &&
'storage' in navigator &&
'getDirectory' in navigator . storage
}
if ( isNode ( ) ) {
persistentStorageAvailable = true // Always available in Node.js
// Check for AWS SDK or S3 environment variables
s3StorageDetected = s3Hint ||
! ! ( process . env . AWS_ACCESS_KEY_ID && process . env . AWS_SECRET_ACCESS_KEY ) ||
! ! ( process . env . S3_BUCKET_NAME )
}
return {
persistentStorageAvailable ,
s3StorageDetected
}
}
/ * *
* Generate recommended configuration based on detected environment and resources
* /
private generateRecommendedConfig (
environment : string ,
resources : { availableMemory : number ; cpuCores : number } ,
hints ? : { expectedDataSize? : number ; memoryBudget? : number }
) : AutoConfigResult [ 'recommendedConfig' ] {
const datasetSize = hints ? . expectedDataSize || this . estimateDatasetSize ( )
const memoryBudget = hints ? . memoryBudget || Math . floor ( resources . availableMemory * 0.6 )
// Base configuration
let config = {
expectedDatasetSize : datasetSize ,
maxMemoryUsage : memoryBudget ,
targetSearchLatency : 150 ,
enablePartitioning : datasetSize > 25000 ,
enableCompression : environment === 'browser' || memoryBudget < 2 * 1024 * 1024 * 1024 ,
enableDistributedSearch : resources.cpuCores > 2 && datasetSize > 50000 ,
enablePredictiveCaching : true ,
partitionStrategy : 'semantic' as const ,
maxNodesPerPartition : 50000 ,
semanticClusters : 8
}
// Environment-specific adjustments
switch ( environment ) {
case 'browser' :
config = {
. . . config ,
maxMemoryUsage : Math.min ( memoryBudget , 1024 * 1024 * 1024 ) , // Cap at 1GB
targetSearchLatency : 200 , // More lenient for browsers
enableCompression : true , // Always enable for browsers
maxNodesPerPartition : 25000 , // Smaller partitions
semanticClusters : 4 // Fewer clusters to save memory
}
break
case 'serverless' :
config = {
. . . config ,
targetSearchLatency : 500 , // Account for cold starts
enablePredictiveCaching : false , // Avoid background processes
maxNodesPerPartition : 30000 // Moderate partition size
}
break
case 'nodejs' :
config = {
. . . config ,
targetSearchLatency : 100 , // Aggressive for Node.js
maxNodesPerPartition : Math.min ( 100000 , Math . floor ( datasetSize / 10 ) ) , // Larger partitions
semanticClusters : Math.min ( 16 , Math . max ( 4 , Math . floor ( datasetSize / 50000 ) ) ) // Scale clusters with data
}
break
}
// Dataset size adjustments
if ( datasetSize > 1000000 ) {
config . semanticClusters = Math . min ( 32 , Math . floor ( datasetSize / 100000 ) )
config . maxNodesPerPartition = 100000
} else if ( datasetSize < 10000 ) {
config . enablePartitioning = false
config . enableDistributedSearch = false
config . partitionStrategy = 'semantic' // Keep semantic but disable partitioning
}
return config
}
/ * *
* Generate optimization flags based on environment and resources
* /
private generateOptimizationFlags (
environment : string ,
resources : { availableMemory : number ; cpuCores : number }
) : AutoConfigResult [ 'optimizationFlags' ] {
return {
useMemoryMapping : environment === 'nodejs' && resources . availableMemory > 4 * 1024 * 1024 * 1024 ,
aggressiveCaching : resources.availableMemory > 2 * 1024 * 1024 * 1024 ,
backgroundOptimization : environment !== 'serverless' && resources . cpuCores > 2 ,
compressionLevel : resources.availableMemory < 1024 * 1024 * 1024 ? 'aggressive' :
resources . availableMemory < 4 * 1024 * 1024 * 1024 ? 'light' : 'none'
}
}
/ * *
* Adapt configuration based on actual dataset analysis
* /
private adaptConfigurationToData (
baseConfig : AutoConfigResult ,
analysis : DatasetAnalysis
) : AutoConfigResult {
const updatedConfig = { . . . baseConfig }
// Adjust based on actual dataset size
if ( analysis . estimatedSize !== baseConfig . recommendedConfig . expectedDatasetSize ) {
const sizeRatio = analysis . estimatedSize / baseConfig . recommendedConfig . expectedDatasetSize
updatedConfig . recommendedConfig . expectedDatasetSize = analysis . estimatedSize
// Scale partition size with dataset
if ( sizeRatio > 2 ) {
updatedConfig . recommendedConfig . maxNodesPerPartition = Math . min (
100000 ,
Math . floor ( updatedConfig . recommendedConfig . maxNodesPerPartition * 1.5 )
)
updatedConfig . recommendedConfig . semanticClusters = Math . min (
32 ,
Math . floor ( updatedConfig . recommendedConfig . semanticClusters * 1.5 )
)
}
}
// Adjust based on vector dimension
if ( analysis . vectorDimension ) {
if ( analysis . vectorDimension > 1024 ) {
// High-dimensional vectors - optimize for compression
updatedConfig . recommendedConfig . enableCompression = true
updatedConfig . optimizationFlags . compressionLevel = 'aggressive'
}
}
// Adjust based on access patterns
if ( analysis . accessPatterns === 'read-heavy' ) {
updatedConfig . recommendedConfig . enablePredictiveCaching = true
updatedConfig . optimizationFlags . aggressiveCaching = true
} else if ( analysis . accessPatterns === 'write-heavy' ) {
updatedConfig . recommendedConfig . enablePredictiveCaching = false
updatedConfig . optimizationFlags . backgroundOptimization = false
}
return updatedConfig
}
/ * *
* Estimate dataset size if not provided
* /
private estimateDatasetSize ( ) : number {
// Start with conservative estimate
const environment = this . detectEnvironment ( )
switch ( environment ) {
case 'browser' : return 10000
case 'serverless' : return 50000
case 'nodejs' : return 100000
default : return 25000
}
}
/ * *
* Reset cached configuration ( for testing or manual refresh )
* /
public resetCache ( ) : void {
this . cachedConfig = null
this . datasetStats = { estimatedSize : 0 }
}
}
/ * *
* Convenience function for quick auto - configuration
* /
export async function autoConfigureBrainy ( hints ? : {
expectedDataSize? : number
s3Available? : boolean
memoryBudget? : number
} ) : Promise < AutoConfigResult > {
const autoConfig = AutoConfiguration . getInstance ( )
return autoConfig . detectAndConfigure ( hints )
}
/ * *
* Get quick setup configuration for common scenarios
* /
export async function getQuickSetup ( scenario : 'small' | 'medium' | 'large' | 'enterprise' ) {
const autoConfig = AutoConfiguration . getInstance ( )
return autoConfig . getQuickSetupConfig ( scenario )
}