/** * Zero-Configuration System for Brainy * Provides intelligent defaults while preserving full control */ import { autoSelectModelPrecision, ModelPrecision, ModelPreset, getModelPath, shouldAutoDownloadModels } from './modelAutoConfig.js' import { autoDetectStorage, StorageType, StoragePreset } from './storageAutoConfig.js' import { AutoConfiguration } from '../utils/autoConfiguration.js' /** * Simplified configuration interface * Everything is optional - zero config by default! */ export interface BrainyZeroConfig { /** * Configuration preset for common scenarios * - 'production': Optimized for production (disk storage, auto model, default features) * - 'development': Optimized for development (memory storage, fp32, verbose logging) * - 'minimal': Minimal footprint (memory storage, q8, minimal features) * - 'zero': True zero config (all auto-detected) * - 'writer': Write-only instance for distributed setups (no index loading) * - 'reader': Read-only instance for distributed setups (no write operations) */ mode?: 'production' | 'development' | 'minimal' | 'zero' | 'writer' | 'reader' /** * Model precision configuration * - 'fp32': Full precision (best quality, larger size) * - 'q8': Quantized 8-bit (smaller size, slightly lower quality) * - 'fast': Alias for fp32 * - 'small': Alias for q8 * - 'auto': Auto-detect based on environment (default) */ model?: ModelPrecision | ModelPreset /** * Storage configuration * - 'memory': In-memory only (no persistence) * - 'disk': Local disk (filesystem or OPFS) * - 'cloud': Cloud storage (S3/GCS/R2 if configured) * - 'auto': Auto-detect best option (default) * - Object: Custom storage configuration */ storage?: StorageType | StoragePreset | any /** * Feature set configuration * - 'minimal': Core features only (fastest startup) * - 'default': Standard features (balanced) * - 'full': All features enabled (most capable) * - Array: Specific features to enable */ features?: 'minimal' | 'default' | 'full' | string[] /** * Logging verbosity * - true: Show configuration decisions and progress * - false: Silent operation (default in production) */ verbose?: boolean /** * Advanced configuration (escape hatch for power users) * Any additional configuration can be passed here */ advanced?: any } /** * Configuration presets for common scenarios */ const PRESETS = { production: { storage: 'disk' as const, model: 'auto' as const, features: 'default' as const, verbose: false }, development: { storage: 'memory' as const, model: 'fp32' as const, features: 'full' as const, verbose: true }, minimal: { storage: 'memory' as const, model: 'q8' as const, features: 'minimal' as const, verbose: false }, zero: { storage: 'auto' as const, model: 'auto' as const, features: 'default' as const, verbose: false }, writer: { storage: 'auto' as const, model: 'auto' as const, features: 'minimal' as const, verbose: false, // Writer-specific settings distributed: true, role: 'writer' as const, writeOnly: true, allowDirectReads: true // Allow deduplication checks }, reader: { storage: 'auto' as const, model: 'auto' as const, features: 'default' as const, verbose: false, // Reader-specific settings distributed: true, role: 'reader' as const, readOnly: true, lazyLoadInReadOnlyMode: true // Optimize for search } } /** * Feature sets configuration */ const FEATURE_SETS = { minimal: [ 'core', 'search', 'storage' ], default: [ 'core', 'search', 'storage', 'cache', 'metadata-index', 'batch-processing', 'entity-registry', 'request-deduplicator' ], full: [ 'core', 'search', 'storage', 'cache', 'metadata-index', 'batch-processing', 'entity-registry', 'request-deduplicator', 'connection-pool', 'wal', 'monitoring', 'metrics', 'intelligent-verb-scoring', 'triple-intelligence', 'neural-api' ] } /** * Process zero-config input into full configuration */ export async function processZeroConfig(input?: string | BrainyZeroConfig): Promise { let config: BrainyZeroConfig = {} // Handle string shorthand (preset name) if (typeof input === 'string') { if (input in PRESETS) { config = { mode: input as any } } else { throw new Error(`Unknown preset: ${input}. Valid presets: ${Object.keys(PRESETS).join(', ')}`) } } else if (input) { config = input } // Apply preset if specified if (config.mode && config.mode in PRESETS) { const preset = PRESETS[config.mode] config = { ...preset, ...config, // Preserve explicit overrides model: config.model ?? preset.model, storage: config.storage ?? preset.storage, features: config.features ?? preset.features, verbose: config.verbose ?? preset.verbose } } // Auto-detect environment if not in preset mode const environment = detectEnvironmentMode() // Process model configuration const modelConfig = autoSelectModelPrecision(config.model) // Process storage configuration const storageConfig = await autoDetectStorage(config.storage) // Process features configuration const features = processFeatures(config.features) // Get auto-configuration recommendations const autoConfig = await AutoConfiguration.getInstance().detectAndConfigure({ expectedDataSize: estimateDataSize(environment), s3Available: storageConfig.type === 's3', memoryBudget: undefined // Let it auto-detect }) // Determine verbosity const verbose = config.verbose ?? (process.env.NODE_ENV === 'development') // Log configuration decisions if verbose if (verbose) { logConfigurationSummary({ mode: config.mode || 'auto', model: modelConfig, storage: storageConfig, features: features, environment: environment, autoConfig: autoConfig }) } // Build final configuration const finalConfig: any = { // Model configuration embeddingFunction: undefined, // Will be created with correct precision embeddingOptions: { precision: modelConfig.precision, modelPath: getModelPath(), allowRemoteDownload: shouldAutoDownloadModels() }, // Storage configuration storage: storageConfig.config, storageType: storageConfig.type, // HNSW configuration from auto-config hnsw: { M: autoConfig.recommendedConfig.enablePartitioning ? 32 : 16, efConstruction: autoConfig.recommendedConfig.enablePartitioning ? 400 : 200, maxDatasetSize: autoConfig.recommendedConfig.expectedDatasetSize, partitioning: autoConfig.recommendedConfig.enablePartitioning, maxNodesPerPartition: autoConfig.recommendedConfig.maxNodesPerPartition }, // Cache configuration from auto-config cache: { autoTune: true, hotCacheMaxSize: Math.floor(autoConfig.recommendedConfig.maxMemoryUsage / (1024 * 1024 * 10)), // 10% of memory budget batchSize: autoConfig.recommendedConfig.enablePartitioning ? 100 : 50 }, // Features configuration enabledFeatures: features, // Metadata index configuration metadataIndex: features.includes('metadata-index') ? { enabled: true, autoRebuild: true } : undefined, // Intelligent verb scoring intelligentVerbScoring: features.includes('intelligent-verb-scoring') ? { enabled: true } : undefined, // Logging configuration logging: { verbose: verbose }, // Performance flags from auto-config optimizations: autoConfig.optimizationFlags, // Advanced overrides (if any) ...config.advanced } // Apply distributed preset settings if applicable if (config.mode === 'writer' || config.mode === 'reader') { const presetSettings = PRESETS[config.mode] as any // Cast to any since we know these presets have additional properties // Apply distributed-specific settings finalConfig.distributed = presetSettings.distributed finalConfig.readOnly = presetSettings.readOnly || false finalConfig.writeOnly = presetSettings.writeOnly || false finalConfig.allowDirectReads = presetSettings.allowDirectReads || false finalConfig.lazyLoadInReadOnlyMode = presetSettings.lazyLoadInReadOnlyMode || false // Set distributed role in distributed config if (finalConfig.distributed) { finalConfig.distributed = { enabled: true, role: presetSettings.role } } // Log distributed mode if verbose if (verbose) { console.log(`📡 Distributed mode: ${config.mode.toUpperCase()}`) console.log(` Role: ${presetSettings.role}`) console.log(` Read-only: ${finalConfig.readOnly}`) console.log(` Write-only: ${finalConfig.writeOnly}`) } } return finalConfig } /** * Detect environment mode if not specified */ function detectEnvironmentMode(): 'production' | 'development' | 'unknown' { if (process.env.NODE_ENV === 'production') return 'production' if (process.env.NODE_ENV === 'development') return 'development' if (process.env.NODE_ENV === 'test') return 'development' // Check for CI environments if (process.env.CI || process.env.GITHUB_ACTIONS) return 'production' // Check for production indicators if (process.env.VERCEL_ENV === 'production' || process.env.NETLIFY_ENV === 'production' || process.env.RAILWAY_ENVIRONMENT === 'production') { return 'production' } return 'unknown' } /** * Process features configuration */ function processFeatures(features?: 'minimal' | 'default' | 'full' | string[]): string[] { if (Array.isArray(features)) { return features } if (features && features in FEATURE_SETS) { return FEATURE_SETS[features] } // Default based on environment const env = detectEnvironmentMode() if (env === 'production') return FEATURE_SETS.default if (env === 'development') return FEATURE_SETS.full return FEATURE_SETS.default } /** * Estimate dataset size based on environment */ function estimateDataSize(environment: string): number { switch (environment) { case 'production': return 100000 case 'development': return 10000 default: return 50000 } } /** * Log configuration summary */ function logConfigurationSummary(config: any): void { console.log('\n🧠 Brainy Zero-Config Summary') console.log('================================') console.log(`Mode: ${config.mode}`) console.log(`Environment: ${config.environment}`) console.log(`Model: ${config.model.precision.toUpperCase()} (${config.model.reason})`) console.log(`Storage: ${config.storage.type.toUpperCase()} (${config.storage.reason})`) console.log(`Features: ${config.features.length} enabled`) console.log(`Memory Budget: ${Math.floor(config.autoConfig.recommendedConfig.maxMemoryUsage / (1024 * 1024))}MB`) console.log(`Expected Dataset: ${config.autoConfig.recommendedConfig.expectedDatasetSize.toLocaleString()} items`) console.log('================================\n') } /** * Create embedding function with specified precision * This ensures the model precision is respected */ export async function createEmbeddingFunctionWithPrecision(precision: ModelPrecision): Promise { const { createEmbeddingFunction } = await import('../utils/embedding.js') // Create embedding function with specified precision return createEmbeddingFunction({ precision: precision, verbose: false // Silent by default in zero-config }) }