@soulcraft/brainy 2.12.0 → 2.14.0

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.
@@ -1,25 +1,25 @@
1
1
  /**
2
2
  * Hybrid Model Manager - BEST OF BOTH WORLDS
3
3
  *
4
- * Combines:
4
+ * NOW A WRAPPER AROUND SingletonModelManager
5
+ * Maintained for backward compatibility
6
+ *
7
+ * Previously combined:
5
8
  * 1. Multi-source downloading strategy (GitHub → CDN → Hugging Face)
6
9
  * 2. Singleton pattern preventing multiple ONNX model loads
7
10
  * 3. Environment-specific optimizations
8
11
  * 4. Graceful fallbacks and error handling
12
+ *
13
+ * Now delegates all operations to SingletonModelManager for true unification
9
14
  */
10
- import { TransformerEmbedding } from './embedding.js';
11
- import { existsSync } from 'fs';
12
- import { join } from 'path';
15
+ import { singletonModelManager, getUnifiedEmbeddingFunction } from '../embeddings/SingletonModelManager.js';
13
16
  /**
14
- * Global singleton model manager - PREVENTS MULTIPLE MODEL LOADS
17
+ * HybridModelManager - Now a wrapper around SingletonModelManager
18
+ * Maintained for backward compatibility
15
19
  */
16
20
  class HybridModelManager {
17
21
  constructor() {
18
- this.primaryModel = null;
19
- this.modelPromise = null;
20
- this.isInitialized = false;
21
- // Smart model path detection
22
- this.modelsPath = this.getModelsPath();
22
+ console.log('🔄 HybridModelManager now delegates to SingletonModelManager');
23
23
  }
24
24
  static getInstance() {
25
25
  if (!HybridModelManager.instance) {
@@ -28,207 +28,42 @@ class HybridModelManager {
28
28
  return HybridModelManager.instance;
29
29
  }
30
30
  /**
31
- * Get the primary embedding model - LOADS ONCE, REUSES FOREVER
31
+ * Get the primary embedding model - delegates to SingletonModelManager
32
32
  */
33
33
  async getPrimaryModel() {
34
- // If already initialized, return immediately
35
- if (this.primaryModel && this.isInitialized) {
36
- return this.primaryModel;
37
- }
38
- // If initialization is in progress, wait for it
39
- if (this.modelPromise) {
40
- return await this.modelPromise;
41
- }
42
- // Start initialization with multi-source strategy
43
- this.modelPromise = this.initializePrimaryModel();
44
- return await this.modelPromise;
45
- }
46
- /**
47
- * Smart model path detection
48
- */
49
- getModelsPath() {
50
- const paths = [
51
- process.env.BRAINY_MODELS_PATH,
52
- './models',
53
- './node_modules/@soulcraft/brainy/models',
54
- join(process.cwd(), 'models')
55
- ];
56
- // Find first existing path or use default
57
- for (const path of paths) {
58
- if (path && existsSync(path)) {
59
- return path;
60
- }
61
- }
62
- return join(process.cwd(), 'models');
63
- }
64
- /**
65
- * Initialize with BEST OF BOTH: Multi-source + Singleton
66
- */
67
- async initializePrimaryModel() {
68
- try {
69
- // Environment detection for optimal configuration
70
- const isTest = globalThis.__BRAINY_TEST_ENV__ || process.env.NODE_ENV === 'test';
71
- const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
72
- const isServerless = typeof process !== 'undefined' && (process.env.VERCEL ||
73
- process.env.NETLIFY ||
74
- process.env.AWS_LAMBDA_FUNCTION_NAME ||
75
- process.env.FUNCTIONS_WORKER_RUNTIME);
76
- const isDocker = typeof process !== 'undefined' && (process.env.DOCKER_CONTAINER ||
77
- process.env.KUBERNETES_SERVICE_HOST);
78
- // Respect BRAINY_ALLOW_REMOTE_MODELS environment variable first
79
- let forceLocalOnly = false;
80
- if (process.env.BRAINY_ALLOW_REMOTE_MODELS !== undefined) {
81
- forceLocalOnly = process.env.BRAINY_ALLOW_REMOTE_MODELS !== 'true';
82
- }
83
- // Smart configuration based on environment
84
- let options = {
85
- verbose: !isTest && !isServerless,
86
- precision: 'fp32', // Use clearer precision parameter
87
- device: 'cpu'
88
- };
89
- // Environment-specific optimizations
90
- if (isBrowser) {
91
- options = {
92
- ...options,
93
- localFilesOnly: forceLocalOnly || false, // Respect environment variable
94
- precision: 'fp32',
95
- device: 'cpu',
96
- verbose: false
97
- };
98
- }
99
- else if (isServerless) {
100
- options = {
101
- ...options,
102
- localFilesOnly: forceLocalOnly || true, // Default true for serverless, but respect env
103
- precision: 'fp32',
104
- device: 'cpu',
105
- verbose: false
106
- };
107
- }
108
- else if (isDocker) {
109
- options = {
110
- ...options,
111
- localFilesOnly: forceLocalOnly || true, // Default true for docker, but respect env
112
- precision: 'fp32',
113
- device: 'auto',
114
- verbose: false
115
- };
116
- }
117
- else if (isTest) {
118
- // CRITICAL FOR TESTS: Allow remote downloads but be smart about it
119
- options = {
120
- ...options,
121
- localFilesOnly: forceLocalOnly || false, // Respect environment variable for tests
122
- precision: 'fp32',
123
- device: 'cpu',
124
- verbose: false
125
- };
126
- }
127
- else {
128
- options = {
129
- ...options,
130
- localFilesOnly: forceLocalOnly || false, // Respect environment variable for default node
131
- precision: 'fp32',
132
- device: 'auto',
133
- verbose: true
134
- };
135
- }
136
- const environmentName = isBrowser ? 'browser' :
137
- isServerless ? 'serverless' :
138
- isDocker ? 'container' :
139
- isTest ? 'test' : 'node';
140
- if (options.verbose) {
141
- console.log(`🧠 Initializing hybrid model manager (${environmentName} mode)...`);
142
- }
143
- // MULTI-SOURCE STRATEGY: Try local first, then remote fallbacks
144
- this.primaryModel = await this.createModelWithFallbacks(options, environmentName);
145
- this.isInitialized = true;
146
- this.modelPromise = null; // Clear the promise
147
- if (options.verbose) {
148
- console.log(`✅ Hybrid model manager initialized successfully`);
149
- }
150
- return this.primaryModel;
151
- }
152
- catch (error) {
153
- this.modelPromise = null; // Clear failed promise
154
- const errorMessage = error instanceof Error ? error.message : String(error);
155
- const environmentInfo = typeof window !== 'undefined' ? 'browser' :
156
- typeof process !== 'undefined' ? `node (${process.version})` : 'unknown';
157
- throw new Error(`Failed to initialize hybrid model manager in ${environmentInfo} environment: ${errorMessage}. ` +
158
- `This is critical for all Brainy operations.`);
159
- }
34
+ // Delegate to SingletonModelManager
35
+ return await singletonModelManager.getModel();
160
36
  }
161
37
  /**
162
- * Create model with multi-source fallback strategy
163
- */
164
- async createModelWithFallbacks(options, environmentName) {
165
- const attempts = [
166
- // 1. Try with current configuration (may use local cache)
167
- { ...options, localFilesOnly: false, source: 'primary' },
168
- // 2. If that fails, explicitly allow remote with verbose logging
169
- { ...options, localFilesOnly: false, verbose: true, source: 'fallback-verbose' },
170
- // 3. Last resort: basic configuration
171
- { verbose: false, precision: 'fp32', device: 'cpu', localFilesOnly: false, source: 'last-resort' }
172
- ];
173
- let lastError = null;
174
- for (const attemptOptions of attempts) {
175
- try {
176
- const { source, ...modelOptions } = attemptOptions;
177
- if (attemptOptions.verbose) {
178
- console.log(`🔄 Attempting model load (${source})...`);
179
- }
180
- const model = new TransformerEmbedding(modelOptions);
181
- await model.init();
182
- if (attemptOptions.verbose) {
183
- console.log(`✅ Model loaded successfully with ${source} strategy`);
184
- }
185
- return model;
186
- }
187
- catch (error) {
188
- lastError = error instanceof Error ? error : new Error(String(error));
189
- if (attemptOptions.verbose) {
190
- console.log(`❌ Failed ${attemptOptions.source} strategy:`, lastError.message);
191
- }
192
- // Continue to next attempt
193
- }
194
- }
195
- // All attempts failed
196
- throw new Error(`All model loading strategies failed in ${environmentName} environment. ` +
197
- `Last error: ${lastError?.message}. ` +
198
- `Check network connectivity or ensure models are available locally.`);
199
- }
200
- /**
201
- * Get embedding function that reuses the singleton model
38
+ * Get embedding function - delegates to SingletonModelManager
202
39
  */
203
40
  async getEmbeddingFunction() {
204
- const model = await this.getPrimaryModel();
205
- return async (data) => {
206
- return await model.embed(data);
207
- };
41
+ return await getUnifiedEmbeddingFunction();
208
42
  }
209
43
  /**
210
- * Check if model is ready (loaded and initialized)
44
+ * Check if model is ready - delegates to SingletonModelManager
211
45
  */
212
46
  isModelReady() {
213
- return this.isInitialized && this.primaryModel !== null;
47
+ return singletonModelManager.isInitialized();
214
48
  }
215
49
  /**
216
- * Force model reload (for testing or recovery)
50
+ * Force model reload - not supported with SingletonModelManager
217
51
  */
218
52
  async reloadModel() {
219
- this.primaryModel = null;
220
- this.isInitialized = false;
221
- this.modelPromise = null;
53
+ console.warn('⚠️ Model reload not supported with SingletonModelManager');
54
+ console.log('ℹ️ Singleton model persists for consistency');
55
+ // Just ensure model is initialized
222
56
  await this.getPrimaryModel();
223
57
  }
224
58
  /**
225
- * Get model status for debugging
59
+ * Get model status - delegates to SingletonModelManager
226
60
  */
227
61
  getModelStatus() {
62
+ const isReady = singletonModelManager.isInitialized();
228
63
  return {
229
- loaded: this.primaryModel !== null,
230
- ready: this.isInitialized,
231
- modelType: 'HybridModelManager (Multi-source + Singleton)'
64
+ loaded: isReady,
65
+ ready: isReady,
66
+ modelType: 'SingletonModelManager (Unified model instance)'
232
67
  };
233
68
  }
234
69
  }
@@ -236,24 +71,25 @@ HybridModelManager.instance = null;
236
71
  // Export singleton instance
237
72
  export const hybridModelManager = HybridModelManager.getInstance();
238
73
  /**
239
- * Get the hybrid singleton embedding function - USE THIS EVERYWHERE!
74
+ * Get the hybrid singleton embedding function - Now delegates to SingletonModelManager
75
+ * Maintained for backward compatibility
240
76
  */
241
77
  export async function getHybridEmbeddingFunction() {
242
- return await hybridModelManager.getEmbeddingFunction();
78
+ return await getUnifiedEmbeddingFunction();
243
79
  }
244
80
  /**
245
- * Optimized hybrid embedding function that uses multi-source + singleton
81
+ * Hybrid embedding function - Now delegates to SingletonModelManager
82
+ * Maintained for backward compatibility
246
83
  */
247
84
  export const hybridEmbeddingFunction = async (data) => {
248
- const embeddingFn = await getHybridEmbeddingFunction();
249
- return await embeddingFn(data);
85
+ return await singletonModelManager.embed(data);
250
86
  };
251
87
  /**
252
- * Preload model for tests or production - CALL THIS ONCE AT START
88
+ * Preload model for tests or production - Now delegates to SingletonModelManager
253
89
  */
254
90
  export async function preloadHybridModel() {
255
- console.log('🚀 Preloading hybrid model...');
256
- await hybridModelManager.getPrimaryModel();
257
- console.log('✅ Hybrid model preloaded and ready!');
91
+ console.log('🚀 Preloading model via SingletonModelManager...');
92
+ await singletonModelManager.getModel();
93
+ console.log('✅ Singleton model preloaded and ready!');
258
94
  }
259
95
  //# sourceMappingURL=hybridModelManager.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/brainy",
3
- "version": "2.12.0",
3
+ "version": "2.14.0",
4
4
  "description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. 31 nouns × 40 verbs for infinite expressiveness.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",