@soulcraft/brainy 2.9.0 → 2.10.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.
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Zero-Configuration System
3
+ * Main entry point for all auto-configuration features
4
+ */
5
+ // Model configuration
6
+ export { autoSelectModelPrecision, shouldAutoDownloadModels, getModelPath, logModelConfig } from './modelAutoConfig.js';
7
+ // Storage configuration
8
+ export { autoDetectStorage, StorageType, StoragePreset, logStorageConfig } from './storageAutoConfig.js';
9
+ // Shared configuration for multi-instance
10
+ export { SharedConfigManager } from './sharedConfigManager.js';
11
+ // Main zero-config processor
12
+ export { processZeroConfig, createEmbeddingFunctionWithPrecision } from './zeroConfig.js';
13
+ // Strongly-typed presets and enums
14
+ export { PresetName, PresetCategory, ModelPrecision, StorageOption, FeatureSet, DistributedRole, PRESET_CONFIGS, getPreset, isValidPreset, getPresetsByCategory, getAllPresetNames, getPresetDescription, presetToBrainyConfig } from './distributedPresets.js';
15
+ // Extensible configuration
16
+ export { registerStorageAugmentation, registerPresetAugmentation, getConfigRegistry } from './extensibleConfig.js';
17
+ /**
18
+ * Main zero-config processor
19
+ * This is what BrainyData will call
20
+ */
21
+ export async function applyZeroConfig(input) {
22
+ // Handle legacy config (full object) by detecting known legacy properties
23
+ if (input && typeof input === 'object' &&
24
+ (input.storage?.forceMemoryStorage || input.storage?.forceFileSystemStorage || input.storage?.s3Storage)) {
25
+ // This is a legacy config object - pass through unchanged
26
+ console.log('📦 Using legacy configuration format');
27
+ return input;
28
+ }
29
+ // Process as zero-config (includes new object format)
30
+ const { processZeroConfig } = await import('./zeroConfig.js');
31
+ return processZeroConfig(input);
32
+ }
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Model Configuration Auto-Selection
3
+ * Intelligently selects model precision based on environment
4
+ * while allowing manual override
5
+ */
6
+ export type ModelPrecision = 'fp32' | 'q8';
7
+ export type ModelPreset = 'fast' | 'small' | 'auto';
8
+ interface ModelConfigResult {
9
+ precision: ModelPrecision;
10
+ reason: string;
11
+ autoSelected: boolean;
12
+ }
13
+ /**
14
+ * Auto-select model precision based on environment and resources
15
+ * @param override - Manual override: 'fp32', 'q8', 'fast' (fp32), 'small' (q8), or 'auto'
16
+ */
17
+ export declare function autoSelectModelPrecision(override?: ModelPrecision | ModelPreset): ModelConfigResult;
18
+ /**
19
+ * Convenience function to check if models need to be downloaded
20
+ * This replaces the need for BRAINY_ALLOW_REMOTE_MODELS
21
+ */
22
+ export declare function shouldAutoDownloadModels(): boolean;
23
+ /**
24
+ * Get the model path with intelligent defaults
25
+ * This replaces the need for BRAINY_MODELS_PATH env var
26
+ */
27
+ export declare function getModelPath(): string;
28
+ /**
29
+ * Log model configuration decision (only in verbose mode)
30
+ */
31
+ export declare function logModelConfig(config: ModelConfigResult, verbose?: boolean): void;
32
+ export {};
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Model Configuration Auto-Selection
3
+ * Intelligently selects model precision based on environment
4
+ * while allowing manual override
5
+ */
6
+ import { isBrowser, isNode } from '../utils/environment.js';
7
+ /**
8
+ * Auto-select model precision based on environment and resources
9
+ * @param override - Manual override: 'fp32', 'q8', 'fast' (fp32), 'small' (q8), or 'auto'
10
+ */
11
+ export function autoSelectModelPrecision(override) {
12
+ // Handle direct precision override
13
+ if (override === 'fp32' || override === 'q8') {
14
+ return {
15
+ precision: override,
16
+ reason: `Manually specified: ${override}`,
17
+ autoSelected: false
18
+ };
19
+ }
20
+ // Handle preset overrides
21
+ if (override === 'fast') {
22
+ return {
23
+ precision: 'fp32',
24
+ reason: 'Preset: fast (fp32 for best quality)',
25
+ autoSelected: false
26
+ };
27
+ }
28
+ if (override === 'small') {
29
+ return {
30
+ precision: 'q8',
31
+ reason: 'Preset: small (q8 for reduced size)',
32
+ autoSelected: false
33
+ };
34
+ }
35
+ // Auto-selection logic
36
+ return autoDetectBestPrecision();
37
+ }
38
+ /**
39
+ * Automatically detect the best model precision for the environment
40
+ */
41
+ function autoDetectBestPrecision() {
42
+ // Browser environment - use Q8 for smaller download/memory
43
+ if (isBrowser()) {
44
+ return {
45
+ precision: 'q8',
46
+ reason: 'Browser environment detected - using Q8 for smaller size',
47
+ autoSelected: true
48
+ };
49
+ }
50
+ // Serverless environments - use Q8 for faster cold starts
51
+ if (isServerlessEnvironment()) {
52
+ return {
53
+ precision: 'q8',
54
+ reason: 'Serverless environment detected - using Q8 for faster cold starts',
55
+ autoSelected: true
56
+ };
57
+ }
58
+ // Check available memory
59
+ const memoryMB = getAvailableMemoryMB();
60
+ if (memoryMB < 512) {
61
+ return {
62
+ precision: 'q8',
63
+ reason: `Low memory detected (${memoryMB}MB) - using Q8`,
64
+ autoSelected: true
65
+ };
66
+ }
67
+ // Development environment - use FP32 for best quality
68
+ if (process.env.NODE_ENV === 'development') {
69
+ return {
70
+ precision: 'fp32',
71
+ reason: 'Development environment - using FP32 for best quality',
72
+ autoSelected: true
73
+ };
74
+ }
75
+ // Production with adequate memory - use FP32
76
+ if (memoryMB >= 2048) {
77
+ return {
78
+ precision: 'fp32',
79
+ reason: `Adequate memory (${memoryMB}MB) - using FP32 for best quality`,
80
+ autoSelected: true
81
+ };
82
+ }
83
+ // Default to Q8 for moderate memory environments
84
+ return {
85
+ precision: 'q8',
86
+ reason: `Moderate memory (${memoryMB}MB) - using Q8 for balance`,
87
+ autoSelected: true
88
+ };
89
+ }
90
+ /**
91
+ * Check if running in a serverless environment
92
+ */
93
+ function isServerlessEnvironment() {
94
+ if (!isNode())
95
+ return false;
96
+ return !!(process.env.AWS_LAMBDA_FUNCTION_NAME ||
97
+ process.env.VERCEL ||
98
+ process.env.NETLIFY ||
99
+ process.env.CLOUDFLARE_WORKERS ||
100
+ process.env.FUNCTIONS_WORKER_RUNTIME ||
101
+ process.env.K_SERVICE // Google Cloud Run
102
+ );
103
+ }
104
+ /**
105
+ * Get available memory in MB
106
+ */
107
+ function getAvailableMemoryMB() {
108
+ if (isBrowser()) {
109
+ // @ts-ignore - navigator.deviceMemory is experimental
110
+ if (navigator.deviceMemory) {
111
+ // @ts-ignore
112
+ return navigator.deviceMemory * 1024; // Device memory in GB
113
+ }
114
+ return 256; // Conservative default for browsers
115
+ }
116
+ if (isNode()) {
117
+ try {
118
+ // Try to get memory info synchronously for Node.js
119
+ // This will be available in Node.js environments
120
+ if (typeof process !== 'undefined' && process.memoryUsage) {
121
+ // Use RSS (Resident Set Size) as a proxy for available memory
122
+ const rss = process.memoryUsage().rss;
123
+ // Assume we can use up to 4GB or 50% more than current usage
124
+ return Math.min(4096, Math.floor(rss / (1024 * 1024) * 1.5));
125
+ }
126
+ }
127
+ catch {
128
+ // Fall through to default
129
+ }
130
+ return 1024; // Default 1GB for Node.js
131
+ }
132
+ return 512; // Conservative default
133
+ }
134
+ /**
135
+ * Convenience function to check if models need to be downloaded
136
+ * This replaces the need for BRAINY_ALLOW_REMOTE_MODELS
137
+ */
138
+ export function shouldAutoDownloadModels() {
139
+ // Always allow downloads unless explicitly disabled
140
+ // This eliminates the need for BRAINY_ALLOW_REMOTE_MODELS
141
+ const explicitlyDisabled = process.env.BRAINY_ALLOW_REMOTE_MODELS === 'false';
142
+ if (explicitlyDisabled) {
143
+ console.warn('Model downloads disabled via BRAINY_ALLOW_REMOTE_MODELS=false');
144
+ return false;
145
+ }
146
+ // In production, always allow downloads for seamless operation
147
+ if (process.env.NODE_ENV === 'production') {
148
+ return true;
149
+ }
150
+ // In development, allow downloads with a one-time notice
151
+ if (process.env.NODE_ENV === 'development') {
152
+ return true;
153
+ }
154
+ // Default: allow downloads
155
+ return true;
156
+ }
157
+ /**
158
+ * Get the model path with intelligent defaults
159
+ * This replaces the need for BRAINY_MODELS_PATH env var
160
+ */
161
+ export function getModelPath() {
162
+ // Check if user explicitly set a path (keeping this for advanced users)
163
+ if (process.env.BRAINY_MODELS_PATH) {
164
+ return process.env.BRAINY_MODELS_PATH;
165
+ }
166
+ // Browser - use cache API or IndexedDB (handled by transformers.js)
167
+ if (isBrowser()) {
168
+ return 'browser-cache';
169
+ }
170
+ // Serverless - use /tmp for ephemeral storage
171
+ if (isServerlessEnvironment()) {
172
+ return '/tmp/.brainy/models';
173
+ }
174
+ // Node.js - use home directory for persistent storage
175
+ if (isNode()) {
176
+ // Use process.env.HOME as a fallback
177
+ const homeDir = process.env.HOME || process.env.USERPROFILE || '~';
178
+ return `${homeDir}/.brainy/models`;
179
+ }
180
+ // Fallback
181
+ return './.brainy/models';
182
+ }
183
+ /**
184
+ * Log model configuration decision (only in verbose mode)
185
+ */
186
+ export function logModelConfig(config, verbose = false) {
187
+ if (!verbose && process.env.NODE_ENV === 'production') {
188
+ return; // Silent in production unless verbose
189
+ }
190
+ const icon = config.autoSelected ? '🤖' : '👤';
191
+ console.log(`${icon} Model: ${config.precision.toUpperCase()} - ${config.reason}`);
192
+ }
193
+ //# sourceMappingURL=modelAutoConfig.js.map
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Shared Configuration Manager
3
+ * Ensures configuration consistency across multiple instances using shared storage
4
+ */
5
+ import { ModelPrecision } from './modelAutoConfig.js';
6
+ export interface SharedConfig {
7
+ version: string;
8
+ precision: ModelPrecision;
9
+ dimensions: number;
10
+ hnswM: number;
11
+ hnswEfConstruction: number;
12
+ distanceFunction: string;
13
+ createdAt: string;
14
+ lastUpdated: string;
15
+ instanceCount?: number;
16
+ lastAccessedBy?: string;
17
+ }
18
+ /**
19
+ * Manages configuration consistency for shared storage
20
+ */
21
+ export declare class SharedConfigManager {
22
+ private static CONFIG_FILE;
23
+ /**
24
+ * Load or create shared configuration
25
+ * When connecting to existing data, this OVERRIDES auto-configuration!
26
+ */
27
+ static loadOrCreateSharedConfig(storage: any, localConfig: any): Promise<{
28
+ config: any;
29
+ warnings: string[];
30
+ }>;
31
+ /**
32
+ * Check if storage type is shared (multi-instance)
33
+ */
34
+ private static isSharedStorage;
35
+ /**
36
+ * Load configuration from shared storage
37
+ */
38
+ private static loadConfigFromStorage;
39
+ /**
40
+ * Save configuration to shared storage
41
+ */
42
+ private static saveConfigToStorage;
43
+ /**
44
+ * Create shared configuration from local config
45
+ */
46
+ private static createSharedConfig;
47
+ /**
48
+ * Check for critical configuration mismatches
49
+ */
50
+ private static checkCriticalMismatches;
51
+ /**
52
+ * Merge local config with shared config (shared takes precedence for critical params)
53
+ */
54
+ private static mergeWithSharedConfig;
55
+ /**
56
+ * Update access information in shared config
57
+ */
58
+ private static updateAccessInfo;
59
+ /**
60
+ * Get unique identifier for this instance
61
+ */
62
+ private static getInstanceIdentifier;
63
+ /**
64
+ * Validate that a configuration is compatible with shared data
65
+ */
66
+ static validateCompatibility(config1: SharedConfig, config2: SharedConfig): boolean;
67
+ }
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Shared Configuration Manager
3
+ * Ensures configuration consistency across multiple instances using shared storage
4
+ */
5
+ /**
6
+ * Manages configuration consistency for shared storage
7
+ */
8
+ export class SharedConfigManager {
9
+ /**
10
+ * Load or create shared configuration
11
+ * When connecting to existing data, this OVERRIDES auto-configuration!
12
+ */
13
+ static async loadOrCreateSharedConfig(storage, localConfig) {
14
+ const warnings = [];
15
+ try {
16
+ // Check if we're using shared storage
17
+ if (!this.isSharedStorage(localConfig.storageType)) {
18
+ // Local storage - use local config
19
+ return { config: localConfig, warnings: [] };
20
+ }
21
+ // Try to load existing configuration from shared storage
22
+ const existingConfig = await this.loadConfigFromStorage(storage);
23
+ if (existingConfig) {
24
+ // EXISTING SHARED DATA - Must use its configuration!
25
+ console.log('📁 Found existing shared data configuration');
26
+ // Check for critical mismatches
27
+ const mismatches = this.checkCriticalMismatches(localConfig, existingConfig);
28
+ if (mismatches.length > 0) {
29
+ console.warn('⚠️ Configuration override required for shared storage:');
30
+ mismatches.forEach(m => {
31
+ console.warn(` - ${m.param}: ${m.local} → ${m.shared} (using shared)`);
32
+ warnings.push(`${m.param} overridden: ${m.local} → ${m.shared}`);
33
+ });
34
+ }
35
+ // Override critical parameters with shared values
36
+ const mergedConfig = this.mergeWithSharedConfig(localConfig, existingConfig);
37
+ // Update last accessed
38
+ await this.updateAccessInfo(storage, existingConfig);
39
+ return { config: mergedConfig, warnings };
40
+ }
41
+ else {
42
+ // NEW SHARED STORAGE - Save our configuration
43
+ console.log('📝 Initializing new shared storage with configuration');
44
+ const sharedConfig = this.createSharedConfig(localConfig);
45
+ await this.saveConfigToStorage(storage, sharedConfig);
46
+ return { config: localConfig, warnings: [] };
47
+ }
48
+ }
49
+ catch (error) {
50
+ console.error('Failed to manage shared configuration:', error);
51
+ warnings.push('Could not verify shared configuration - proceeding with caution');
52
+ return { config: localConfig, warnings };
53
+ }
54
+ }
55
+ /**
56
+ * Check if storage type is shared (multi-instance)
57
+ */
58
+ static isSharedStorage(storageType) {
59
+ return ['s3', 'gcs', 'r2'].includes(storageType);
60
+ }
61
+ /**
62
+ * Load configuration from shared storage
63
+ */
64
+ static async loadConfigFromStorage(storage) {
65
+ try {
66
+ const configData = await storage.get(this.CONFIG_FILE);
67
+ if (!configData)
68
+ return null;
69
+ const config = JSON.parse(configData);
70
+ return config;
71
+ }
72
+ catch (error) {
73
+ // Config doesn't exist yet
74
+ return null;
75
+ }
76
+ }
77
+ /**
78
+ * Save configuration to shared storage
79
+ */
80
+ static async saveConfigToStorage(storage, config) {
81
+ try {
82
+ await storage.set(this.CONFIG_FILE, JSON.stringify(config, null, 2));
83
+ }
84
+ catch (error) {
85
+ console.error('Failed to save shared configuration:', error);
86
+ throw new Error('Cannot initialize shared storage without saving configuration');
87
+ }
88
+ }
89
+ /**
90
+ * Create shared configuration from local config
91
+ */
92
+ static createSharedConfig(localConfig) {
93
+ return {
94
+ version: '2.10.0', // Brainy version
95
+ precision: localConfig.embeddingOptions?.precision || 'fp32',
96
+ dimensions: 384, // Fixed for all-MiniLM-L6-v2
97
+ hnswM: localConfig.hnsw?.M || 16,
98
+ hnswEfConstruction: localConfig.hnsw?.efConstruction || 200,
99
+ distanceFunction: localConfig.distanceFunction || 'cosine',
100
+ createdAt: new Date().toISOString(),
101
+ lastUpdated: new Date().toISOString(),
102
+ instanceCount: 1,
103
+ lastAccessedBy: this.getInstanceIdentifier()
104
+ };
105
+ }
106
+ /**
107
+ * Check for critical configuration mismatches
108
+ */
109
+ static checkCriticalMismatches(localConfig, sharedConfig) {
110
+ const mismatches = [];
111
+ // Model precision - CRITICAL!
112
+ const localPrecision = localConfig.embeddingOptions?.precision || 'fp32';
113
+ if (localPrecision !== sharedConfig.precision) {
114
+ mismatches.push({
115
+ param: 'Model Precision',
116
+ local: localPrecision,
117
+ shared: sharedConfig.precision
118
+ });
119
+ }
120
+ // HNSW parameters - Important for index consistency
121
+ const localM = localConfig.hnsw?.M || 16;
122
+ if (localM !== sharedConfig.hnswM) {
123
+ mismatches.push({
124
+ param: 'HNSW M',
125
+ local: localM,
126
+ shared: sharedConfig.hnswM
127
+ });
128
+ }
129
+ const localEf = localConfig.hnsw?.efConstruction || 200;
130
+ if (localEf !== sharedConfig.hnswEfConstruction) {
131
+ mismatches.push({
132
+ param: 'HNSW efConstruction',
133
+ local: localEf,
134
+ shared: sharedConfig.hnswEfConstruction
135
+ });
136
+ }
137
+ // Distance function
138
+ const localDistance = localConfig.distanceFunction || 'cosine';
139
+ if (localDistance !== sharedConfig.distanceFunction) {
140
+ mismatches.push({
141
+ param: 'Distance Function',
142
+ local: localDistance,
143
+ shared: sharedConfig.distanceFunction
144
+ });
145
+ }
146
+ return mismatches;
147
+ }
148
+ /**
149
+ * Merge local config with shared config (shared takes precedence for critical params)
150
+ */
151
+ static mergeWithSharedConfig(localConfig, sharedConfig) {
152
+ return {
153
+ ...localConfig,
154
+ // Override critical parameters with shared values
155
+ embeddingOptions: {
156
+ ...localConfig.embeddingOptions,
157
+ precision: sharedConfig.precision // MUST use shared precision!
158
+ },
159
+ hnsw: {
160
+ ...localConfig.hnsw,
161
+ M: sharedConfig.hnswM,
162
+ efConstruction: sharedConfig.hnswEfConstruction
163
+ },
164
+ distanceFunction: sharedConfig.distanceFunction,
165
+ // Add metadata about shared configuration
166
+ _sharedConfig: {
167
+ loaded: true,
168
+ version: sharedConfig.version,
169
+ createdAt: sharedConfig.createdAt,
170
+ precision: sharedConfig.precision
171
+ }
172
+ };
173
+ }
174
+ /**
175
+ * Update access information in shared config
176
+ */
177
+ static async updateAccessInfo(storage, config) {
178
+ try {
179
+ config.lastUpdated = new Date().toISOString();
180
+ config.instanceCount = (config.instanceCount || 0) + 1;
181
+ config.lastAccessedBy = this.getInstanceIdentifier();
182
+ await this.saveConfigToStorage(storage, config);
183
+ }
184
+ catch {
185
+ // Non-critical - don't fail if we can't update access info
186
+ }
187
+ }
188
+ /**
189
+ * Get unique identifier for this instance
190
+ */
191
+ static getInstanceIdentifier() {
192
+ if (process.env.HOSTNAME)
193
+ return process.env.HOSTNAME;
194
+ if (process.env.CONTAINER_ID)
195
+ return process.env.CONTAINER_ID;
196
+ if (process.env.K_SERVICE)
197
+ return process.env.K_SERVICE;
198
+ if (process.env.AWS_LAMBDA_FUNCTION_NAME)
199
+ return process.env.AWS_LAMBDA_FUNCTION_NAME;
200
+ // Generate a random identifier
201
+ return `instance-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
202
+ }
203
+ /**
204
+ * Validate that a configuration is compatible with shared data
205
+ */
206
+ static validateCompatibility(config1, config2) {
207
+ return (config1.precision === config2.precision &&
208
+ config1.dimensions === config2.dimensions &&
209
+ config1.hnswM === config2.hnswM &&
210
+ config1.hnswEfConstruction === config2.hnswEfConstruction &&
211
+ config1.distanceFunction === config2.distanceFunction);
212
+ }
213
+ }
214
+ SharedConfigManager.CONFIG_FILE = '.brainy/config.json';
215
+ //# sourceMappingURL=sharedConfigManager.js.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Storage Configuration Auto-Detection
3
+ * Intelligently selects storage based on environment and available services
4
+ */
5
+ /**
6
+ * Low-level storage implementation types
7
+ */
8
+ export declare enum StorageType {
9
+ MEMORY = "memory",
10
+ FILESYSTEM = "filesystem",
11
+ OPFS = "opfs",
12
+ S3 = "s3",
13
+ GCS = "gcs",
14
+ R2 = "r2"
15
+ }
16
+ /**
17
+ * High-level storage presets (maps to StorageType)
18
+ */
19
+ export declare enum StoragePreset {
20
+ AUTO = "auto",
21
+ MEMORY = "memory",
22
+ DISK = "disk",
23
+ CLOUD = "cloud"
24
+ }
25
+ export type StorageTypeString = 'memory' | 'filesystem' | 'opfs' | 's3' | 'gcs' | 'r2';
26
+ export type StoragePresetString = 'auto' | 'memory' | 'disk' | 'cloud';
27
+ export interface StorageConfigResult {
28
+ type: StorageType | StorageTypeString;
29
+ config: any;
30
+ reason: string;
31
+ autoSelected: boolean;
32
+ }
33
+ /**
34
+ * Auto-detect the best storage configuration
35
+ * @param override - Manual override: specific type or preset
36
+ */
37
+ export declare function autoDetectStorage(override?: StorageType | StoragePreset | StorageTypeString | StoragePresetString | any): Promise<StorageConfigResult>;
38
+ /**
39
+ * Log storage configuration decision
40
+ */
41
+ export declare function logStorageConfig(config: StorageConfigResult, verbose?: boolean): void;