@soulcraft/brainy 2.8.0 β†’ 2.10.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.
@@ -107,7 +107,7 @@ export class UniversalMemoryManager {
107
107
  const { TransformerEmbedding } = await import('../utils/embedding.js');
108
108
  this.embeddingFunction = new TransformerEmbedding({
109
109
  verbose: false,
110
- dtype: 'fp32',
110
+ precision: 'fp32',
111
111
  localFilesOnly: process.env.BRAINY_ALLOW_REMOTE_MODELS !== 'true'
112
112
  });
113
113
  await this.embeddingFunction.init();
@@ -13,7 +13,7 @@ async function initModel() {
13
13
  if (!model) {
14
14
  model = new TransformerEmbedding({
15
15
  verbose: false,
16
- dtype: 'fp32',
16
+ precision: 'fp32',
17
17
  localFilesOnly: process.env.BRAINY_ALLOW_REMOTE_MODELS !== 'true'
18
18
  });
19
19
  await model.init();
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@
11
11
  import { BrainyData, BrainyDataConfig } from './brainyData.js';
12
12
  export { BrainyData };
13
13
  export type { BrainyDataConfig };
14
+ export { PresetName, ModelPrecision, StorageOption, FeatureSet, DistributedRole, PresetCategory, BrainyZeroConfig, StorageProvider, registerStorageAugmentation, registerPresetAugmentation, getPreset, isValidPreset, getPresetsByCategory, getAllPresetNames, getPresetDescription } from './config/index.js';
14
15
  export { Cortex, cortex } from './cortex.js';
15
16
  export { NeuralImport } from './cortex/neuralImport.js';
16
17
  export type { NeuralAnalysisResult, DetectedEntity, DetectedRelationship, NeuralInsight, NeuralImportOptions } from './cortex/neuralImport.js';
package/dist/index.js CHANGED
@@ -11,6 +11,22 @@
11
11
  // Export main BrainyData class and related types
12
12
  import { BrainyData } from './brainyData.js';
13
13
  export { BrainyData };
14
+ // Export zero-configuration types and enums
15
+ export {
16
+ // Preset names
17
+ PresetName,
18
+ // Model configuration
19
+ ModelPrecision,
20
+ // Storage configuration
21
+ StorageOption,
22
+ // Feature configuration
23
+ FeatureSet,
24
+ // Distributed roles
25
+ DistributedRole,
26
+ // Categories
27
+ PresetCategory, registerStorageAugmentation, registerPresetAugmentation,
28
+ // Preset utilities
29
+ getPreset, isValidPreset, getPresetsByCategory, getAllPresetNames, getPresetDescription } from './config/index.js';
14
30
  // Export Cortex (the orchestrator)
15
31
  export { Cortex, cortex } from './cortex.js';
16
32
  // Export Neural Import (AI data understanding)
@@ -25,8 +25,8 @@ export interface TransformerEmbeddingOptions {
25
25
  cacheDir?: string;
26
26
  /** Force local files only (no downloads) */
27
27
  localFilesOnly?: boolean;
28
- /** Quantization setting (fp32, fp16, q8, q4) */
29
- dtype?: 'fp32' | 'fp16' | 'q8' | 'q4';
28
+ /** Model precision: 'q8' = 75% smaller quantized model, 'fp32' = full precision (default) */
29
+ precision?: 'fp32' | 'q8';
30
30
  /** Device to run inference on - 'auto' detects best available */
31
31
  device?: 'auto' | 'cpu' | 'webgpu' | 'cuda' | 'gpu';
32
32
  }
@@ -4,6 +4,8 @@
4
4
  */
5
5
  import { isBrowser } from './environment.js';
6
6
  import { ModelManager } from '../embeddings/model-manager.js';
7
+ import { join } from 'path';
8
+ import { existsSync } from 'fs';
7
9
  // @ts-ignore - Transformers.js is now the primary embedding library
8
10
  import { pipeline, env } from '@huggingface/transformers';
9
11
  // CRITICAL: Disable ONNX memory arena to prevent 4-8GB allocation
@@ -11,9 +13,10 @@ import { pipeline, env } from '@huggingface/transformers';
11
13
  if (typeof process !== 'undefined' && process.env) {
12
14
  process.env.ORT_DISABLE_MEMORY_ARENA = '1';
13
15
  process.env.ORT_DISABLE_MEMORY_PATTERN = '1';
14
- // Also limit ONNX thread count for more predictable memory usage
15
- process.env.ORT_INTRA_OP_NUM_THREADS = '2';
16
- process.env.ORT_INTER_OP_NUM_THREADS = '2';
16
+ // Force single-threaded operation for maximum stability (Node.js 24 compatibility)
17
+ process.env.ORT_INTRA_OP_NUM_THREADS = '1'; // Single thread for operators
18
+ process.env.ORT_INTER_OP_NUM_THREADS = '1'; // Single thread for sessions
19
+ process.env.ORT_NUM_THREADS = '1'; // Additional safety override
17
20
  }
18
21
  /**
19
22
  * Detect the best available GPU device for the current environment
@@ -77,7 +80,7 @@ export class TransformerEmbedding {
77
80
  localFilesOnly = options.localFilesOnly;
78
81
  }
79
82
  else if (process.env.BRAINY_ALLOW_REMOTE_MODELS === 'false') {
80
- // 2. Environment variable explicitly disables remote models
83
+ // 2. Environment variable explicitly disables remote models (legacy support)
81
84
  localFilesOnly = true;
82
85
  }
83
86
  else if (process.env.NODE_ENV === 'development') {
@@ -98,11 +101,11 @@ export class TransformerEmbedding {
98
101
  verbose: this.verbose,
99
102
  cacheDir: options.cacheDir || './models',
100
103
  localFilesOnly: localFilesOnly,
101
- dtype: options.dtype || 'fp32', // CRITICAL: fp32 default for backward compatibility
104
+ precision: options.precision || 'fp32', // Clean and clear!
102
105
  device: options.device || 'auto'
103
106
  };
104
107
  // ULTRA-CAREFUL: Runtime warnings for q8 usage
105
- if (this.options.dtype === 'q8') {
108
+ if (this.options.precision === 'q8') {
106
109
  const confirmed = process.env.BRAINY_Q8_CONFIRMED === 'true';
107
110
  if (!confirmed && this.verbose) {
108
111
  console.warn('🚨 Q8 MODEL WARNING:');
@@ -114,7 +117,7 @@ export class TransformerEmbedding {
114
117
  }
115
118
  }
116
119
  if (this.verbose) {
117
- this.logger('log', `Embedding config: dtype=${this.options.dtype}, localFilesOnly=${localFilesOnly}, model=${this.options.model}`);
120
+ this.logger('log', `Embedding config: precision=${this.options.precision}, localFilesOnly=${localFilesOnly}, model=${this.options.model}`);
118
121
  }
119
122
  // Configure transformers.js environment
120
123
  if (!isBrowser()) {
@@ -226,25 +229,40 @@ export class TransformerEmbedding {
226
229
  const startTime = Date.now();
227
230
  // Check model availability and select appropriate variant
228
231
  const available = modelManager.getAvailableModels(this.options.model);
229
- const actualType = modelManager.getBestAvailableModel(this.options.dtype, this.options.model);
232
+ let actualType = modelManager.getBestAvailableModel(this.options.precision, this.options.model);
230
233
  if (!actualType) {
231
234
  throw new Error(`No model variants available for ${this.options.model}. Run 'npm run download-models' to download models.`);
232
235
  }
233
- if (actualType !== this.options.dtype) {
234
- this.logger('log', `Using ${actualType} model (${this.options.dtype} not available)`);
236
+ if (actualType !== this.options.precision) {
237
+ this.logger('log', `Using ${actualType} model (${this.options.precision} not available)`);
238
+ }
239
+ // CRITICAL FIX: Control which model file transformers.js loads
240
+ // When both model.onnx and model_quantized.onnx exist, transformers.js defaults to model.onnx
241
+ // We need to explicitly control this based on the precision setting
242
+ // Set environment to control model selection BEFORE creating pipeline
243
+ if (actualType === 'q8') {
244
+ // For Q8, we want to use the quantized model
245
+ // transformers.js v3 doesn't have a direct flag, so we need to work around this
246
+ // HACK: Temporarily modify the model file preference
247
+ // This forces transformers.js to look for model_quantized.onnx first
248
+ const originalModelFileName = env.onnxModelFileName(env).onnxModelFileName = 'model_quantized';
249
+ this.logger('log', '🎯 Selecting Q8 quantized model (75% smaller)');
250
+ }
251
+ else {
252
+ this.logger('log', 'πŸ“¦ Using FP32 model (full precision)');
235
253
  }
236
254
  // Load the feature extraction pipeline with memory optimizations
237
255
  const pipelineOptions = {
238
256
  cache_dir: cacheDir,
239
257
  local_files_only: isBrowser() ? false : this.options.localFilesOnly,
240
- dtype: actualType, // Use the actual available model type
258
+ // Remove the quantized flag - it doesn't work in transformers.js v3
241
259
  // CRITICAL: ONNX memory optimizations
242
260
  session_options: {
243
261
  enableCpuMemArena: false, // Disable pre-allocated memory arena
244
262
  enableMemPattern: false, // Disable memory pattern optimization
245
- interOpNumThreads: 2, // Limit thread count
246
- intraOpNumThreads: 2, // Limit parallelism
247
- graphOptimizationLevel: 'all'
263
+ interOpNumThreads: 1, // Force single thread for V8 stability
264
+ intraOpNumThreads: 1, // Force single thread for V8 stability
265
+ graphOptimizationLevel: 'disabled' // Disable threading optimizations
248
266
  }
249
267
  };
250
268
  // Add device configuration for GPU acceleration
@@ -256,6 +274,18 @@ export class TransformerEmbedding {
256
274
  this.logger('log', `Pipeline options: ${JSON.stringify(pipelineOptions)}`);
257
275
  }
258
276
  try {
277
+ // For Q8 models, we need to explicitly specify the model file
278
+ if (actualType === 'q8') {
279
+ // Check if quantized model exists
280
+ const modelPath = join(cacheDir, this.options.model, 'onnx', 'model_quantized.onnx');
281
+ if (existsSync(modelPath)) {
282
+ this.logger('log', 'βœ… Q8 model found locally');
283
+ }
284
+ else {
285
+ this.logger('warn', '⚠️ Q8 model not found, will fall back to FP32');
286
+ actualType = 'fp32'; // Fall back to fp32
287
+ }
288
+ }
259
289
  this.extractor = await pipeline('feature-extraction', this.options.model, pipelineOptions);
260
290
  }
261
291
  catch (gpuError) {
@@ -282,8 +312,8 @@ export class TransformerEmbedding {
282
312
  // Both local and remote failed - throw comprehensive error
283
313
  const errorMsg = `Failed to load embedding model "${this.options.model}". ` +
284
314
  `Local models not found and remote download failed. ` +
285
- `To fix: 1) Set BRAINY_ALLOW_REMOTE_MODELS=true, ` +
286
- `2) Run "npm run download-models", or ` +
315
+ `To fix: 1) Run "npm run download-models", ` +
316
+ `2) Check your internet connection, or ` +
287
317
  `3) Use a custom embedding function.`;
288
318
  throw new Error(errorMsg);
289
319
  }
@@ -83,7 +83,7 @@ class HybridModelManager {
83
83
  // Smart configuration based on environment
84
84
  let options = {
85
85
  verbose: !isTest && !isServerless,
86
- dtype: 'fp32',
86
+ precision: 'fp32', // Use clearer precision parameter
87
87
  device: 'cpu'
88
88
  };
89
89
  // Environment-specific optimizations
@@ -91,7 +91,7 @@ class HybridModelManager {
91
91
  options = {
92
92
  ...options,
93
93
  localFilesOnly: forceLocalOnly || false, // Respect environment variable
94
- dtype: 'fp32',
94
+ precision: 'fp32',
95
95
  device: 'cpu',
96
96
  verbose: false
97
97
  };
@@ -100,7 +100,7 @@ class HybridModelManager {
100
100
  options = {
101
101
  ...options,
102
102
  localFilesOnly: forceLocalOnly || true, // Default true for serverless, but respect env
103
- dtype: 'fp32',
103
+ precision: 'fp32',
104
104
  device: 'cpu',
105
105
  verbose: false
106
106
  };
@@ -109,7 +109,7 @@ class HybridModelManager {
109
109
  options = {
110
110
  ...options,
111
111
  localFilesOnly: forceLocalOnly || true, // Default true for docker, but respect env
112
- dtype: 'fp32',
112
+ precision: 'fp32',
113
113
  device: 'auto',
114
114
  verbose: false
115
115
  };
@@ -119,7 +119,7 @@ class HybridModelManager {
119
119
  options = {
120
120
  ...options,
121
121
  localFilesOnly: forceLocalOnly || false, // Respect environment variable for tests
122
- dtype: 'fp32',
122
+ precision: 'fp32',
123
123
  device: 'cpu',
124
124
  verbose: false
125
125
  };
@@ -128,7 +128,7 @@ class HybridModelManager {
128
128
  options = {
129
129
  ...options,
130
130
  localFilesOnly: forceLocalOnly || false, // Respect environment variable for default node
131
- dtype: 'fp32',
131
+ precision: 'fp32',
132
132
  device: 'auto',
133
133
  verbose: true
134
134
  };
@@ -168,7 +168,7 @@ class HybridModelManager {
168
168
  // 2. If that fails, explicitly allow remote with verbose logging
169
169
  { ...options, localFilesOnly: false, verbose: true, source: 'fallback-verbose' },
170
170
  // 3. Last resort: basic configuration
171
- { verbose: false, dtype: 'fp32', device: 'cpu', localFilesOnly: false, source: 'last-resort' }
171
+ { verbose: false, precision: 'fp32', device: 'cpu', localFilesOnly: false, source: 'last-resort' }
172
172
  ];
173
173
  let lastError = null;
174
174
  for (const attemptOptions of attempts) {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Node.js Version Compatibility Check
3
+ *
4
+ * Brainy requires Node.js 22.x LTS for maximum stability with ONNX Runtime.
5
+ * This prevents V8 HandleScope locking issues in worker threads.
6
+ */
7
+ export interface VersionInfo {
8
+ current: string;
9
+ major: number;
10
+ isSupported: boolean;
11
+ recommendation: string;
12
+ }
13
+ /**
14
+ * Check if the current Node.js version is supported
15
+ */
16
+ export declare function checkNodeVersion(): VersionInfo;
17
+ /**
18
+ * Enforce Node.js version requirement with helpful error messaging
19
+ */
20
+ export declare function enforceNodeVersion(): void;
21
+ /**
22
+ * Soft warning for version issues (non-blocking)
23
+ */
24
+ export declare function warnNodeVersion(): boolean;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Node.js Version Compatibility Check
3
+ *
4
+ * Brainy requires Node.js 22.x LTS for maximum stability with ONNX Runtime.
5
+ * This prevents V8 HandleScope locking issues in worker threads.
6
+ */
7
+ /**
8
+ * Check if the current Node.js version is supported
9
+ */
10
+ export function checkNodeVersion() {
11
+ const nodeVersion = process.version;
12
+ const majorVersion = parseInt(nodeVersion.split('.')[0].substring(1));
13
+ const versionInfo = {
14
+ current: nodeVersion,
15
+ major: majorVersion,
16
+ isSupported: majorVersion === 22,
17
+ recommendation: 'Node.js 22.x LTS'
18
+ };
19
+ return versionInfo;
20
+ }
21
+ /**
22
+ * Enforce Node.js version requirement with helpful error messaging
23
+ */
24
+ export function enforceNodeVersion() {
25
+ const versionInfo = checkNodeVersion();
26
+ if (!versionInfo.isSupported) {
27
+ const errorMessage = [
28
+ '🚨 BRAINY COMPATIBILITY ERROR',
29
+ '━'.repeat(50),
30
+ `❌ Current Node.js: ${versionInfo.current}`,
31
+ `βœ… Required: ${versionInfo.recommendation}`,
32
+ '',
33
+ 'πŸ’‘ Quick Fix:',
34
+ ' nvm install 22 && nvm use 22',
35
+ ' npm install',
36
+ '',
37
+ 'πŸ“– Why Node.js 22?',
38
+ ' β€’ Maximum ONNX Runtime stability',
39
+ ' β€’ Prevents V8 threading crashes',
40
+ ' β€’ Optimal zero-config performance',
41
+ '',
42
+ 'πŸ”— More info: https://github.com/soulcraftlabs/brainy#node-version',
43
+ '━'.repeat(50)
44
+ ].join('\n');
45
+ throw new Error(errorMessage);
46
+ }
47
+ }
48
+ /**
49
+ * Soft warning for version issues (non-blocking)
50
+ */
51
+ export function warnNodeVersion() {
52
+ const versionInfo = checkNodeVersion();
53
+ if (!versionInfo.isSupported) {
54
+ console.warn([
55
+ '⚠️ BRAINY VERSION WARNING',
56
+ ` Current: ${versionInfo.current}`,
57
+ ` Recommended: ${versionInfo.recommendation}`,
58
+ ' Consider upgrading for best stability',
59
+ ''
60
+ ].join('\n'));
61
+ return false;
62
+ }
63
+ return true;
64
+ }
65
+ //# sourceMappingURL=nodeVersionCheck.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/brainy",
3
- "version": "2.8.0",
3
+ "version": "2.10.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",
@@ -55,7 +55,7 @@
55
55
  }
56
56
  },
57
57
  "engines": {
58
- "node": ">=22.0.0"
58
+ "node": "22.x"
59
59
  },
60
60
  "scripts": {
61
61
  "build": "npm run build:patterns:if-needed && tsc",