chore: recovery checkpoint - v3.0 API successfully recovered
CRITICAL CHECKPOINT - DO NOT PUSH TO GITHUB Recovery Status: - Successfully recovered brainy.ts from compiled JavaScript - All core v3.0 API methods functional (add, get, update, delete, relate, find, etc.) - Neural subsystem intact (562KB embedded patterns, NLP working) - Augmentation pipeline operational (20+ augmentations) - HNSW clustering system complete - Triple Intelligence compiled (needs constructor fix) - Test suite validates functionality Changes preserved: - 898 files with changes from last 3 days - 144,475 insertions - All augmentation improvements - All test coverage enhancements - Complete v3.0 feature set This is a LOCAL checkpoint only - contains recovered work after corruption incident. Created backup in .backups/brainy-full-20250910-151314.tar.gz Branch: recovery-checkpoint-20250910-151433 Date: Wed Sep 10 03:18:04 PM PDT 2025
This commit is contained in:
parent
f65455fb22
commit
8ff382ca3b
895 changed files with 143654 additions and 28268 deletions
|
|
@ -0,0 +1,166 @@
|
|||
/**
|
||||
* Universal Memory Manager for Embeddings
|
||||
*
|
||||
* Works in ALL environments: Node.js, browsers, serverless, workers
|
||||
* Solves transformers.js memory leak with environment-specific strategies
|
||||
*/
|
||||
import { getModelPrecision } from '../config/modelPrecisionManager.js';
|
||||
// Environment detection
|
||||
const isNode = typeof process !== 'undefined' && process.versions?.node;
|
||||
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
||||
const isServerless = typeof process !== 'undefined' && (process.env.VERCEL ||
|
||||
process.env.NETLIFY ||
|
||||
process.env.AWS_LAMBDA_FUNCTION_NAME ||
|
||||
process.env.FUNCTIONS_WORKER_RUNTIME);
|
||||
export class UniversalMemoryManager {
|
||||
constructor() {
|
||||
// CRITICAL FIX: Never use worker threads with ONNX Runtime
|
||||
// Worker threads cause HandleScope V8 API errors due to isolate issues
|
||||
// Always use direct embedding on main thread for ONNX compatibility
|
||||
this.embeddingFunction = null;
|
||||
this.embedCount = 0;
|
||||
this.restartCount = 0;
|
||||
this.lastRestart = 0;
|
||||
if (isServerless) {
|
||||
this.strategy = 'serverless-restart';
|
||||
this.maxEmbeddings = 50; // Restart frequently in serverless
|
||||
}
|
||||
else if (isNode && !isBrowser) {
|
||||
// CHANGED: Use direct strategy instead of node-worker to avoid V8 isolate issues
|
||||
this.strategy = 'node-direct';
|
||||
this.maxEmbeddings = 200; // Main thread can handle more with single model instance
|
||||
}
|
||||
else if (isBrowser) {
|
||||
this.strategy = 'browser-dispose';
|
||||
this.maxEmbeddings = 25; // Browser memory is limited
|
||||
}
|
||||
else {
|
||||
this.strategy = 'fallback-dispose';
|
||||
this.maxEmbeddings = 75;
|
||||
}
|
||||
console.log(`🧠 Universal Memory Manager: Using ${this.strategy} strategy`);
|
||||
console.log('✅ UNIVERSAL: Memory-safe embedding system initialized');
|
||||
}
|
||||
async getEmbeddingFunction() {
|
||||
return async (data) => {
|
||||
return this.embed(data);
|
||||
};
|
||||
}
|
||||
async embed(data) {
|
||||
// Check if we need to restart/cleanup
|
||||
await this.checkMemoryLimits();
|
||||
// Ensure embedding function is available
|
||||
await this.ensureEmbeddingFunction();
|
||||
// Perform embedding
|
||||
const result = await this.embeddingFunction.embed(data);
|
||||
this.embedCount++;
|
||||
return result;
|
||||
}
|
||||
async checkMemoryLimits() {
|
||||
if (this.embedCount >= this.maxEmbeddings) {
|
||||
console.log(`🔄 Memory cleanup: ${this.embedCount} embeddings processed`);
|
||||
await this.cleanup();
|
||||
}
|
||||
}
|
||||
async ensureEmbeddingFunction() {
|
||||
if (this.embeddingFunction) {
|
||||
return;
|
||||
}
|
||||
switch (this.strategy) {
|
||||
case 'node-direct':
|
||||
await this.initNodeDirect();
|
||||
break;
|
||||
case 'serverless-restart':
|
||||
await this.initServerless();
|
||||
break;
|
||||
case 'browser-dispose':
|
||||
await this.initBrowser();
|
||||
break;
|
||||
default:
|
||||
await this.initFallback();
|
||||
}
|
||||
}
|
||||
async initNodeDirect() {
|
||||
if (isNode) {
|
||||
// CRITICAL: Use direct embedding to avoid worker thread V8 isolate issues
|
||||
// This prevents HandleScope errors and ensures single model instance
|
||||
console.log('✅ Using Node.js direct embedding (main thread - ONNX compatible)');
|
||||
await this.initDirect();
|
||||
}
|
||||
}
|
||||
async initServerless() {
|
||||
// In serverless, use direct embedding but restart more aggressively
|
||||
await this.initDirect();
|
||||
console.log('✅ Using serverless strategy with aggressive cleanup');
|
||||
}
|
||||
async initBrowser() {
|
||||
// In browser, use direct embedding with disposal
|
||||
await this.initDirect();
|
||||
console.log('✅ Using browser strategy with disposal');
|
||||
}
|
||||
async initFallback() {
|
||||
await this.initDirect();
|
||||
console.log('✅ Using fallback direct embedding strategy');
|
||||
}
|
||||
async initDirect() {
|
||||
try {
|
||||
// Dynamic import to handle different environments
|
||||
const { TransformerEmbedding } = await import('../utils/embedding.js');
|
||||
this.embeddingFunction = new TransformerEmbedding({
|
||||
verbose: false,
|
||||
precision: getModelPrecision(), // Use centrally managed precision
|
||||
localFilesOnly: process.env.BRAINY_ALLOW_REMOTE_MODELS !== 'true'
|
||||
});
|
||||
await this.embeddingFunction.init();
|
||||
console.log('✅ Direct embedding function initialized');
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`Failed to initialize embedding function: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
async cleanup() {
|
||||
const startTime = Date.now();
|
||||
// SingletonModelManager persists - we just reset our counters
|
||||
// The singleton model stays alive for consistency across all operations
|
||||
// Reset counters
|
||||
this.embedCount = 0;
|
||||
this.restartCount++;
|
||||
this.lastRestart = Date.now();
|
||||
const cleanupTime = Date.now() - startTime;
|
||||
console.log(`🧹 Memory counters reset in ${cleanupTime}ms (strategy: ${this.strategy})`);
|
||||
console.log('ℹ️ Singleton model persists for consistency across all operations');
|
||||
}
|
||||
getMemoryStats() {
|
||||
let memoryUsage = 'unknown';
|
||||
// Get memory stats based on environment
|
||||
if (isNode && typeof process !== 'undefined') {
|
||||
const mem = process.memoryUsage();
|
||||
memoryUsage = `${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB`;
|
||||
}
|
||||
else if (isBrowser && performance.memory) {
|
||||
const mem = performance.memory;
|
||||
memoryUsage = `${(mem.usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`;
|
||||
}
|
||||
return {
|
||||
embeddings: this.embedCount,
|
||||
memoryUsage,
|
||||
restarts: this.restartCount,
|
||||
strategy: this.strategy
|
||||
};
|
||||
}
|
||||
async dispose() {
|
||||
// SingletonModelManager persists - nothing to dispose
|
||||
console.log('ℹ️ Universal Memory Manager: Singleton model persists');
|
||||
}
|
||||
}
|
||||
// Export singleton instance
|
||||
export const universalMemoryManager = new UniversalMemoryManager();
|
||||
// Export convenience function
|
||||
export async function getUniversalEmbeddingFunction() {
|
||||
return universalMemoryManager.getEmbeddingFunction();
|
||||
}
|
||||
// Export memory stats function
|
||||
export function getEmbeddingMemoryStats() {
|
||||
return universalMemoryManager.getMemoryStats();
|
||||
}
|
||||
//# sourceMappingURL=universal-memory-manager.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue