@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.
- package/CHANGELOG.md +2 -0
- package/README.md +61 -18
- package/dist/brainyData.d.ts +4 -1
- package/dist/brainyData.js +94 -38
- package/dist/config/distributedPresets-new.d.ts +118 -0
- package/dist/config/distributedPresets-new.js +318 -0
- package/dist/config/distributedPresets.d.ts +118 -0
- package/dist/config/distributedPresets.js +318 -0
- package/dist/config/extensibleConfig.d.ts +99 -0
- package/dist/config/extensibleConfig.js +268 -0
- package/dist/config/index.d.ts +16 -0
- package/dist/config/index.js +33 -0
- package/dist/config/modelAutoConfig.d.ts +32 -0
- package/dist/config/modelAutoConfig.js +193 -0
- package/dist/config/sharedConfigManager.d.ts +67 -0
- package/dist/config/sharedConfigManager.js +215 -0
- package/dist/config/storageAutoConfig.d.ts +41 -0
- package/dist/config/storageAutoConfig.js +328 -0
- package/dist/config/zeroConfig.d.ts +68 -0
- package/dist/config/zeroConfig.js +301 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +16 -0
- package/dist/utils/embedding.js +10 -9
- package/dist/utils/nodeVersionCheck.d.ts +24 -0
- package/dist/utils/nodeVersionCheck.js +65 -0
- package/package.json +2 -2
|
@@ -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;
|