fix: remove dead model config code for true zero-config

- Remove unused model.type validation that caused Workshop error
- Remove model config from BrainyConfig type (never used)
- Simplify modelAutoConfig.ts (always Q8 WASM)
- Clean up zeroConfig.ts model references

This fixes the "Invalid model type: balanced" error and removes
unnecessary configuration options that did nothing.
This commit is contained in:
David Snelling 2025-12-18 10:31:02 -08:00
parent 746b1b8e24
commit e6769d6d9f
6 changed files with 37 additions and 163 deletions

View file

@ -177,7 +177,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
...this.config, ...this.config,
...configOverrides, ...configOverrides,
storage: { ...this.config.storage, ...configOverrides.storage }, storage: { ...this.config.storage, ...configOverrides.storage },
model: { ...this.config.model, ...configOverrides.model },
index: { ...this.config.index, ...configOverrides.index }, index: { ...this.config.index, ...configOverrides.index },
augmentations: { ...this.config.augmentations, ...configOverrides.augmentations }, augmentations: { ...this.config.augmentations, ...configOverrides.augmentations },
verbose: configOverrides.verbose ?? this.config.verbose, verbose: configOverrides.verbose ?? this.config.verbose,
@ -4972,11 +4971,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
// Both 'gcs' and 'gcs-native' can now use either gcsStorage or gcsNativeStorage // Both 'gcs' and 'gcs-native' can now use either gcsStorage or gcsNativeStorage
} }
// Validate model configuration
if (config?.model?.type && !['fast', 'accurate', 'custom'].includes(config.model.type)) {
throw new Error(`Invalid model type: ${config.model.type}. Must be one of: fast, accurate, custom`)
}
// Validate numeric configurations // Validate numeric configurations
if (config?.index?.m && (config.index.m < 1 || config.index.m > 128)) { if (config?.index?.m && (config.index.m < 1 || config.index.m > 128)) {
throw new Error(`Invalid index m parameter: ${config.index.m}. Must be between 1 and 128`) throw new Error(`Invalid index m parameter: ${config.index.m}. Must be between 1 and 128`)
@ -4995,7 +4989,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
return { return {
storage: config?.storage || { type: 'auto' }, storage: config?.storage || { type: 'auto' },
model: config?.model || { type: 'fast' },
index: config?.index || {}, index: config?.index || {},
cache: config?.cache ?? true, cache: config?.cache ?? true,
augmentations: config?.augmentations || {}, augmentations: config?.augmentations || {},

View file

@ -3,19 +3,13 @@
* Main entry point for all auto-configuration features * Main entry point for all auto-configuration features
*/ */
// Model configuration // Model configuration (simplified - always Q8 WASM)
export { export {
autoSelectModelPrecision, getModelPrecision,
ModelPrecision as ModelPrecisionType, // Avoid conflict
ModelPreset,
shouldAutoDownloadModels, shouldAutoDownloadModels,
getModelPath, getModelPath
logModelConfig
} from './modelAutoConfig.js' } from './modelAutoConfig.js'
// Model precision - Always Q8 now (99% accuracy, 75% smaller)
export const getModelPrecision = () => 'q8' as const
// Storage configuration // Storage configuration
export { export {
autoDetectStorage, autoDetectStorage,

View file

@ -1,49 +1,24 @@
/** /**
* Model Configuration Auto-Selection * Model Configuration
* Always uses Q8 for optimal size/performance balance (99% accuracy, 75% smaller) * Brainy uses Q8 WASM embeddings - no configuration needed (zero-config)
*/ */
import { isBrowser, isNode } from '../utils/environment.js' import { isBrowser, isNode } from '../utils/environment.js'
export type ModelPrecision = 'q8'
export type ModelPreset = 'small' | 'auto'
interface ModelConfigResult { interface ModelConfigResult {
precision: ModelPrecision precision: 'q8'
reason: string reason: string
autoSelected: boolean autoSelected: boolean
} }
/** /**
* Auto-select model precision - Always returns Q8 * Get model precision configuration
* Q8 provides 99% accuracy with 75% smaller size * Always returns Q8 - the optimal balance of size and accuracy
* @param override - For backward compatibility, ignored
*/ */
export function autoSelectModelPrecision(override?: ModelPrecision | ModelPreset): ModelConfigResult { export function getModelPrecision(): ModelConfigResult {
// Always use Q8 regardless of override for simplicity
// Q8 is optimal: 33MB vs 130MB, 99% accuracy retained
// Log deprecation notice if FP32 was requested
if (typeof override === 'string' && override.toLowerCase().includes('fp32')) {
console.log('Note: FP32 precision is deprecated. Using Q8 (99% accuracy, 75% smaller).')
}
return { return {
precision: 'q8', precision: 'q8',
reason: 'Q8 precision (99% accuracy, 75% smaller)', reason: 'Q8 WASM (23MB bundled, no downloads)',
autoSelected: true
}
}
/**
* Automatically detect the best model precision for the environment
* DEPRECATED: Always returns Q8 now
*/
function autoDetectBestPrecision(): ModelConfigResult {
// Always return Q8 - deprecated function kept for backward compatibility
return {
precision: 'q8',
reason: 'Q8 precision (99% accuracy, 75% smaller)',
autoSelected: true autoSelected: true
} }
} }
@ -53,7 +28,7 @@ function autoDetectBestPrecision(): ModelConfigResult {
*/ */
function isServerlessEnvironment(): boolean { function isServerlessEnvironment(): boolean {
if (!isNode()) return false if (!isNode()) return false
return !!( return !!(
process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.AWS_LAMBDA_FUNCTION_NAME ||
process.env.VERCEL || process.env.VERCEL ||
@ -65,104 +40,42 @@ function isServerlessEnvironment(): boolean {
} }
/** /**
* Get available memory in MB * Check if models need to be downloaded
*/ * With bundled WASM model, this is rarely needed
function getAvailableMemoryMB(): number {
if (isBrowser()) {
// @ts-ignore - navigator.deviceMemory is experimental
if (navigator.deviceMemory) {
// @ts-ignore
return navigator.deviceMemory * 1024 // Device memory in GB
}
return 256 // Conservative default for browsers
}
if (isNode()) {
try {
// Try to get memory info synchronously for Node.js
// This will be available in Node.js environments
if (typeof process !== 'undefined' && process.memoryUsage) {
// Use RSS (Resident Set Size) as a proxy for available memory
const rss = process.memoryUsage().rss
// Assume we can use up to 4GB or 50% more than current usage
return Math.min(4096, Math.floor(rss / (1024 * 1024) * 1.5))
}
} catch {
// Fall through to default
}
return 1024 // Default 1GB for Node.js
}
return 512 // Conservative default
}
/**
* Convenience function to check if models need to be downloaded
* This replaces the need for BRAINY_ALLOW_REMOTE_MODELS
*/ */
export function shouldAutoDownloadModels(): boolean { export function shouldAutoDownloadModels(): boolean {
// Always allow downloads unless explicitly disabled // Model is bundled - no downloads needed in normal operation
// This eliminates the need for BRAINY_ALLOW_REMOTE_MODELS // This flag exists for edge cases only
const explicitlyDisabled = process.env.BRAINY_ALLOW_REMOTE_MODELS === 'false' const explicitlyDisabled = process.env.BRAINY_ALLOW_REMOTE_MODELS === 'false'
return !explicitlyDisabled
if (explicitlyDisabled) {
console.warn('Model downloads disabled via BRAINY_ALLOW_REMOTE_MODELS=false')
return false
}
// In production, always allow downloads for seamless operation
if (process.env.NODE_ENV === 'production') {
return true
}
// In development, allow downloads with a one-time notice
if (process.env.NODE_ENV === 'development') {
return true
}
// Default: allow downloads
return true
} }
/** /**
* Get the model path with intelligent defaults * Get the model path
* This replaces the need for BRAINY_MODELS_PATH env var * With bundled WASM model, this points to the package assets
*/ */
export function getModelPath(): string { export function getModelPath(): string {
// Check if user explicitly set a path (keeping this for advanced users) // Check if user explicitly set a path (for advanced users)
if (process.env.BRAINY_MODELS_PATH) { if (process.env.BRAINY_MODELS_PATH) {
return process.env.BRAINY_MODELS_PATH return process.env.BRAINY_MODELS_PATH
} }
// Browser - use cache API or IndexedDB (handled by transformers.js) // Browser - use cache API or IndexedDB
if (isBrowser()) { if (isBrowser()) {
return 'browser-cache' return 'browser-cache'
} }
// Serverless - use /tmp for ephemeral storage // Serverless - use /tmp for ephemeral storage
if (isServerlessEnvironment()) { if (isServerlessEnvironment()) {
return '/tmp/.brainy/models' return '/tmp/.brainy/models'
} }
// Node.js - use home directory for persistent storage // Node.js - use home directory for persistent storage
if (isNode()) { if (isNode()) {
// Use process.env.HOME as a fallback
const homeDir = process.env.HOME || process.env.USERPROFILE || '~' const homeDir = process.env.HOME || process.env.USERPROFILE || '~'
return `${homeDir}/.brainy/models` return `${homeDir}/.brainy/models`
} }
// Fallback // Fallback
return './.brainy/models' return './.brainy/models'
} }
/**
* Log model configuration decision (only in verbose mode)
*/
export function logModelConfig(config: ModelConfigResult, verbose: boolean = false): void {
if (!verbose && process.env.NODE_ENV === 'production') {
return // Silent in production unless verbose
}
const icon = config.autoSelected ? '🤖' : '👤'
console.log(`${icon} Model: ${config.precision.toUpperCase()} - ${config.reason}`)
}

View file

@ -3,14 +3,13 @@
* Ensures configuration consistency across multiple instances using shared storage * Ensures configuration consistency across multiple instances using shared storage
*/ */
import { ModelPrecision } from './modelAutoConfig.js'
import { StorageType } from './storageAutoConfig.js' import { StorageType } from './storageAutoConfig.js'
import { getBrainyVersion } from '../utils/version.js' import { getBrainyVersion } from '../utils/version.js'
export interface SharedConfig { export interface SharedConfig {
// Critical parameters that MUST match across instances // Critical parameters that MUST match across instances
version: string version: string
precision: ModelPrecision precision: 'q8'
dimensions: number dimensions: number
hnswM: number hnswM: number
hnswEfConstruction: number hnswEfConstruction: number

View file

@ -3,7 +3,7 @@
* Provides intelligent defaults while preserving full control * Provides intelligent defaults while preserving full control
*/ */
import { autoSelectModelPrecision, ModelPrecision, ModelPreset, getModelPath, shouldAutoDownloadModels } from './modelAutoConfig.js' import { getModelPrecision, getModelPath, shouldAutoDownloadModels } from './modelAutoConfig.js'
import { autoDetectStorage, StorageType, StoragePreset } from './storageAutoConfig.js' import { autoDetectStorage, StorageType, StoragePreset } from './storageAutoConfig.js'
import { AutoConfiguration } from '../utils/autoConfiguration.js' import { AutoConfiguration } from '../utils/autoConfiguration.js'
@ -23,16 +23,6 @@ export interface BrainyZeroConfig {
*/ */
mode?: 'production' | 'development' | 'minimal' | 'zero' | 'writer' | 'reader' mode?: 'production' | 'development' | 'minimal' | 'zero' | 'writer' | 'reader'
/**
* Model precision configuration
* - 'fp32': Full precision (best quality, larger size)
* - 'q8': Quantized 8-bit (smaller size, slightly lower quality)
* - 'fast': Alias for fp32
* - 'small': Alias for q8
* - 'auto': Auto-detect based on environment (default)
*/
model?: ModelPrecision | ModelPreset
/** /**
* Storage configuration * Storage configuration
* - 'memory': In-memory only (no persistence) * - 'memory': In-memory only (no persistence)
@ -72,31 +62,26 @@ export interface BrainyZeroConfig {
const PRESETS = { const PRESETS = {
production: { production: {
storage: 'disk' as const, storage: 'disk' as const,
model: 'auto' as const,
features: 'default' as const, features: 'default' as const,
verbose: false verbose: false
}, },
development: { development: {
storage: 'memory' as const, storage: 'memory' as const,
model: 'q8' as const, // Q8 is now the default for all presets
features: 'full' as const, features: 'full' as const,
verbose: true verbose: true
}, },
minimal: { minimal: {
storage: 'memory' as const, storage: 'memory' as const,
model: 'q8' as const,
features: 'minimal' as const, features: 'minimal' as const,
verbose: false verbose: false
}, },
zero: { zero: {
storage: 'auto' as const, storage: 'auto' as const,
model: 'auto' as const,
features: 'default' as const, features: 'default' as const,
verbose: false verbose: false
}, },
writer: { writer: {
storage: 'auto' as const, storage: 'auto' as const,
model: 'auto' as const,
features: 'minimal' as const, features: 'minimal' as const,
verbose: false, verbose: false,
// Writer-specific settings // Writer-specific settings
@ -107,7 +92,6 @@ const PRESETS = {
}, },
reader: { reader: {
storage: 'auto' as const, storage: 'auto' as const,
model: 'auto' as const,
features: 'default' as const, features: 'default' as const,
verbose: false, verbose: false,
// Reader-specific settings // Reader-specific settings
@ -180,18 +164,17 @@ export async function processZeroConfig(input?: string | BrainyZeroConfig): Prom
...preset, ...preset,
...config, ...config,
// Preserve explicit overrides // Preserve explicit overrides
model: config.model ?? preset.model,
storage: config.storage ?? preset.storage, storage: config.storage ?? preset.storage,
features: config.features ?? preset.features, features: config.features ?? preset.features,
verbose: config.verbose ?? preset.verbose verbose: config.verbose ?? preset.verbose
} }
} }
// Auto-detect environment if not in preset mode // Auto-detect environment if not in preset mode
const environment = detectEnvironmentMode() const environment = detectEnvironmentMode()
// Process model configuration // Get model configuration (always Q8 WASM)
const modelConfig = autoSelectModelPrecision(config.model) const modelConfig = getModelPrecision()
// Process storage configuration // Process storage configuration
const storageConfig = await autoDetectStorage(config.storage) const storageConfig = await autoDetectStorage(config.storage)
@ -376,15 +359,14 @@ function logConfigurationSummary(config: any): void {
} }
/** /**
* Create embedding function with specified precision * Create embedding function (always Q8 WASM)
* This ensures the model precision is respected
*/ */
export async function createEmbeddingFunctionWithPrecision(precision: ModelPrecision): Promise<any> { export async function createEmbeddingFunctionWithPrecision(): Promise<any> {
const { createEmbeddingFunction } = await import('../utils/embedding.js') const { createEmbeddingFunction } = await import('../utils/embedding.js')
// Create embedding function with specified precision // Create embedding function - always Q8 WASM
return createEmbeddingFunction({ return createEmbeddingFunction({
precision: precision, precision: 'q8',
verbose: false // Silent by default in zero-config verbose: false // Silent by default in zero-config
}) })
} }

View file

@ -632,14 +632,7 @@ export interface BrainyConfig {
options?: any options?: any
branch?: string // COW branch name (default: 'main') branch?: string // COW branch name (default: 'main')
} }
// Model configuration
model?: {
type: 'fast' | 'accurate' | 'balanced' | 'custom'
name?: string // Custom model name
precision?: 'q8'
}
// Index configuration // Index configuration
index?: { index?: {
m?: number // HNSW M parameter m?: number // HNSW M parameter