UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

793 lines 37.7 kB
/** * Neural MCP Tools for CLI * * V2 Compatibility - Neural network and ML tools * * ✅ HYBRID Implementation: * - Uses @claude-flow/embeddings for REAL ML embeddings when available * - Falls back to deterministic hash-based embeddings when ML model not installed * - Pattern storage and search with cosine similarity (real math in all tiers) * - Training stores patterns as searchable embeddings (not simulated) * * Note: For production neural features, use @claude-flow/neural module */ import { getProjectCwd } from './types.js'; import { validateIdentifier, validateText } from './validate-input.js'; import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; import { join } from 'node:path'; // Try to import real embeddings — prefer agentic-flow v3 ReasoningBank, then @claude-flow/embeddings let realEmbeddings = null; let embeddingServiceName = 'none'; try { // Tier 1: agentic-flow v3 ReasoningBank (fastest — WASM-accelerated) const rb = await import('agentic-flow/reasoningbank').catch(() => null); if (rb?.computeEmbedding) { realEmbeddings = { embed: (text) => rb.computeEmbedding(text) }; embeddingServiceName = 'agentic-flow/reasoningbank'; } // Tier 2: @claude-flow/embeddings with agentic-flow provider if (!realEmbeddings) { const embeddingsModule = await import('@claude-flow/embeddings').catch(() => null); if (embeddingsModule?.createEmbeddingService) { try { const service = embeddingsModule.createEmbeddingService({ provider: 'agentic-flow' }); realEmbeddings = { embed: async (text) => { const result = await service.embed(text); return Array.from(result.embedding); }, }; embeddingServiceName = 'agentic-flow'; } catch { // agentic-flow provider not available, try ONNX } } } // Tier 3: @claude-flow/embeddings with ONNX provider if (!realEmbeddings) { const embeddingsModule = await import('@claude-flow/embeddings').catch(() => null); if (embeddingsModule?.createEmbeddingService) { try { const service = embeddingsModule.createEmbeddingService({ provider: 'onnx' }); realEmbeddings = { embed: async (text) => { const result = await service.embed(text); return Array.from(result.embedding); }, }; embeddingServiceName = 'onnx'; } catch { // ONNX provider not available, fall through to mock } } } // No Tier 4 mock fallback. If Tier 1 (agentic-flow) and Tier 3 (onnx) // both failed to import, leave realEmbeddings null and let downstream // code use the explicit hash-fallback path with a clear _embeddingNote // in stats. Silently substituting mock embeddings would hide a missing // production dependency from callers. } catch { // No embedding provider available, will use fallback } // Storage paths const STORAGE_DIR = '.claude-flow'; const NEURAL_DIR = 'neural'; const MODELS_FILE = 'models.json'; const PATTERNS_FILE = 'patterns.json'; function getNeuralDir() { return join(getProjectCwd(), STORAGE_DIR, NEURAL_DIR); } function getNeuralPath() { return join(getNeuralDir(), MODELS_FILE); } function ensureNeuralDir() { const dir = getNeuralDir(); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } } function loadNeuralStore() { try { const path = getNeuralPath(); if (existsSync(path)) { return JSON.parse(readFileSync(path, 'utf-8')); } } catch { // Return empty store } return { models: {}, patterns: {}, version: '3.0.0' }; } function saveNeuralStore(store) { ensureNeuralDir(); writeFileSync(getNeuralPath(), JSON.stringify(store, null, 2), 'utf-8'); } // Generate embedding - uses real ML embeddings if available, falls back to deterministic hash async function generateEmbedding(text, dims = 384) { // If real embeddings available and text provided, use them if (realEmbeddings && text) { try { return await realEmbeddings.embed(text); } catch { // Fall back to hash-based } } // Hash-based deterministic embedding (better than pure random for consistency) // NOTE: No semantic meaning — only useful for consistent deduplication, not similarity search if (text) { if (embeddingServiceName === 'none') { embeddingServiceName = 'hash-fallback'; } const hash = text.split('').reduce((acc, char, i) => { return acc + char.charCodeAt(0) * (i + 1); }, 0); // Use hash to seed a deterministic embedding const embedding = []; let seed = hash; for (let i = 0; i < dims; i++) { // Simple LCG random with seed seed = (seed * 1103515245 + 12345) & 0x7fffffff; embedding.push((seed / 0x7fffffff) * 2 - 1); } return embedding; } // No text provided — return zero vector (callers should always provide text) return new Array(dims).fill(0); } // Cosine similarity for pattern search function cosineSimilarity(a, b) { if (a.length !== b.length) return 0; let dotProduct = 0; let normA = 0; let normB = 0; for (let i = 0; i < a.length; i++) { dotProduct += a[i] * b[i]; normA += a[i] * a[i]; normB += b[i] * b[i]; } return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB) || 1); } export const neuralTools = [ { name: 'neural_train', description: 'Train a neural model Use when nothing native trains on your workflow — Claude Code has no learning loop. Use to train SONA/MoE/EWC patterns from successful task outcomes; query via neural_predict before spawning agents. Off-path for one-shot work.', category: 'neural', inputSchema: { type: 'object', properties: { modelId: { type: 'string', description: 'Model ID to train' }, modelType: { type: 'string', enum: ['moe', 'transformer', 'classifier', 'embedding'], description: 'Model type' }, epochs: { type: 'number', description: 'Number of training epochs' }, learningRate: { type: 'number', description: 'Learning rate' }, data: { type: 'object', description: 'Training data' }, }, required: ['modelType'], }, handler: async (input) => { if (input.modelId) { const v = validateIdentifier(input.modelId, 'modelId'); if (!v.valid) return { success: false, error: v.error }; } const store = loadNeuralStore(); const modelId = input.modelId || `model-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`; const modelType = input.modelType; const epochs = input.epochs || 10; const model = { id: modelId, name: `${modelType}-model`, type: modelType, status: 'training', accuracy: 0, epochs, config: { learningRate: input.learningRate || 0.001, batchSize: 32, }, }; store.models[modelId] = model; saveNeuralStore(store); // Real training: embed training data and store as searchable patterns const trainingData = input.data; let patternsStored = 0; if (trainingData) { const entries = Array.isArray(trainingData) ? trainingData : [trainingData]; for (let i = 0; i < entries.length; i++) { const entry = entries[i]; const text = typeof entry === 'string' ? entry : entry?.text || entry?.content || entry?.label || JSON.stringify(entry); if (!text) continue; const embedding = await generateEmbedding(text, 384); const patternId = `${modelId}-train-${i}`; // ADR-093 F11: extract a meaningful label instead of dumping raw // training JSON as the pattern name. Audit reported neural_predict // returned `label: <raw training data JSON>` because the previous // fallback was `text.slice(0, 100)` where text was `JSON.stringify(entry)`. let label; if (typeof entry === 'string') { label = entry.slice(0, 80); } else if (entry && typeof entry === 'object') { const e = entry; // Prefer common semantic fields over a JSON dump const labelField = e.label ?? e.category ?? e.class ?? e.tag ?? e.intent ?? e.name ?? e.title; if (typeof labelField === 'string' && labelField.length > 0) { label = labelField.slice(0, 80); } else { const summaryField = e.text ?? e.input ?? e.task ?? e.description ?? e.content; if (typeof summaryField === 'string' && summaryField.length > 0) { label = `${summaryField.slice(0, 60)}${summaryField.length > 60 ? '…' : ''}`; } else { // Last resort: reduce to a stable short hash-like id label = `${modelType}:entry-${i}`; } } } else { label = `${modelType}:entry-${i}`; } store.patterns[patternId] = { id: patternId, name: label, type: modelType, embedding, metadata: { modelId, epoch: epochs, index: i, raw: entry }, createdAt: new Date().toISOString(), usageCount: 0, }; patternsStored++; } } model.status = 'ready'; model.accuracy = patternsStored > 0 ? 1.0 : 0; // accuracy = data stored, not simulated model.trainedAt = new Date().toISOString(); saveNeuralStore(store); return { success: true, _realEmbedding: !!realEmbeddings, _embeddingSource: embeddingServiceName, embeddingProvider: embeddingServiceName, modelId, type: modelType, status: model.status, patternsStored, totalPatterns: Object.keys(store.patterns).length, epochs, trainedAt: model.trainedAt, ...(embeddingServiceName === 'hash-fallback' || embeddingServiceName === 'none' ? { platformNote: 'ONNX embeddings not available — using hash-based fallback. Install @claude-flow/embeddings and run "embeddings init --download" for semantic search.', } : {}), }; }, }, { name: 'neural_predict', description: 'Make predictions using a neural model Use when nothing native trains on your workflow — Claude Code has no learning loop. Use to train SONA/MoE/EWC patterns from successful task outcomes; query via neural_predict before spawning agents. Off-path for one-shot work.', category: 'neural', inputSchema: { type: 'object', properties: { modelId: { type: 'string', description: 'Model ID to use' }, input: { type: 'string', description: 'Input text or data' }, topK: { type: 'number', description: 'Number of top predictions' }, }, required: ['input'], }, handler: async (input) => { { const v = validateText(input.input, 'input'); if (!v.valid) return { success: false, error: v.error }; } if (input.modelId) { const v = validateIdentifier(input.modelId, 'modelId'); if (!v.valid) return { success: false, error: v.error }; } const store = loadNeuralStore(); const modelId = input.modelId; const inputText = input.input; const topK = input.topK || 3; // Find model or use default const model = modelId ? store.models[modelId] : Object.values(store.models).find(m => m.status === 'ready'); if (model && model.status !== 'ready') { return { success: false, error: 'Model not ready' }; } // Generate real embedding for the input const startTime = performance.now(); const embedding = await generateEmbedding(inputText, 384); const latency = Math.round(performance.now() - startTime); // ADR-093 F11: real classifier head over stored patterns. Previously // confidence was the raw cosine similarity (often clamped to 0 when // stored embeddings were stale or zero-vectored). Now we run k-NN // with cosine distance and apply a temperature-controlled softmax // over the top-K so confidence is a proper distribution that sums // to 1, and we surface enough metadata to trust the result. const storedPatterns = Object.values(store.patterns); let predictions; if (storedPatterns.length > 0) { // Step 1: k-NN with cosine const scored = storedPatterns .map(p => { const sim = cosineSimilarity(embedding, p.embedding); return { patternId: p.id, label: p.name || p.type || p.id, cosineSimilarity: sim, }; }) .sort((a, b) => b.cosineSimilarity - a.cosineSimilarity) .slice(0, topK); // Step 2: temperature-softmax over the top-K so confidence sums to 1. // Temperature 0.1 sharpens differences between similar candidates. const tau = 0.1; const exps = scored.map(s => Math.exp(s.cosineSimilarity / tau)); const z = exps.reduce((a, b) => a + b, 0) || 1; predictions = scored.map((s, i) => ({ label: s.label, patternId: s.patternId, cosineSimilarity: Number(s.cosineSimilarity.toFixed(4)), confidence: Number((exps[i] / z).toFixed(4)), })); } else { // No patterns stored — no predictions possible. Be honest about it // instead of returning empty silently. predictions = []; } const topConfidence = predictions[0]?.confidence ?? 0; const topSimilarity = predictions[0]?.cosineSimilarity ?? 0; return { success: true, _realEmbedding: !!realEmbeddings, _embeddingSource: embeddingServiceName, embeddingProvider: embeddingServiceName, _hasStoredPatterns: storedPatterns.length > 0, _classifierHead: storedPatterns.length > 0 ? 'knn-cosine+softmax(tau=0.1)' : 'none', modelId: model?.id || 'default', input: inputText, predictions, // Surface cosineSimilarity separately so callers know whether the // softmax confidence reflects true match strength. topPrediction: predictions[0]?.label ?? null, topConfidence, topSimilarity, embedding: embedding.slice(0, 8), // Preview of embedding embeddingDims: embedding.length, latency, ...(storedPatterns.length === 0 ? { _note: 'No patterns stored. Train with neural_train(modelType, trainingData) before predicting.', } : {}), }; }, }, { name: 'neural_patterns', description: 'Get or manage neural patterns Use when nothing native trains on your workflow — Claude Code has no learning loop. Use to train SONA/MoE/EWC patterns from successful task outcomes; query via neural_predict before spawning agents. Off-path for one-shot work.', category: 'neural', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: ['list', 'get', 'store', 'search', 'delete'], description: 'Action to perform' }, patternId: { type: 'string', description: 'Pattern ID' }, name: { type: 'string', description: 'Pattern name' }, type: { type: 'string', description: 'Pattern type' }, query: { type: 'string', description: 'Search query' }, data: { type: 'object', description: 'Pattern data' }, }, }, handler: async (input) => { if (input.patternId) { const v = validateIdentifier(input.patternId, 'patternId'); if (!v.valid) return { success: false, error: v.error }; } if (input.name) { const v = validateText(input.name, 'name'); if (!v.valid) return { success: false, error: v.error }; } if (input.type) { const v = validateIdentifier(input.type, 'type'); if (!v.valid) return { success: false, error: v.error }; } if (input.query) { const v = validateText(input.query, 'query'); if (!v.valid) return { success: false, error: v.error }; } const store = loadNeuralStore(); const action = input.action || 'list'; if (action === 'list') { const patterns = Object.values(store.patterns); const typeFilter = input.type; const filtered = typeFilter ? patterns.filter(p => p.type === typeFilter) : patterns; return { patterns: filtered.map(p => ({ id: p.id, name: p.name, type: p.type, usageCount: p.usageCount, createdAt: p.createdAt, })), total: filtered.length, }; } if (action === 'get') { const pattern = store.patterns[input.patternId]; if (!pattern) { return { success: false, error: 'Pattern not found' }; } return { success: true, pattern }; } if (action === 'store') { const patternId = `pattern-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`; const patternName = input.name || 'Unnamed pattern'; // Generate embedding from pattern name/content const embedding = await generateEmbedding(patternName, 384); const pattern = { id: patternId, name: patternName, type: input.type || 'general', embedding, metadata: input.data || {}, createdAt: new Date().toISOString(), usageCount: 0, }; store.patterns[patternId] = pattern; saveNeuralStore(store); return { success: true, _realEmbedding: !!realEmbeddings, _embeddingSource: embeddingServiceName, embeddingProvider: embeddingServiceName, patternId, name: pattern.name, type: pattern.type, embeddingDims: embedding.length, createdAt: pattern.createdAt, }; } if (action === 'search') { const query = input.query; // Generate query embedding for real similarity search const queryEmbedding = await generateEmbedding(query, 384); // Calculate REAL cosine similarity against stored patterns const results = Object.values(store.patterns) .map(p => ({ ...p, similarity: cosineSimilarity(queryEmbedding, p.embedding), })) .sort((a, b) => b.similarity - a.similarity) .slice(0, 10); return { _realSimilarity: true, _realEmbedding: !!realEmbeddings, _embeddingSource: embeddingServiceName, embeddingProvider: embeddingServiceName, query, results: results.map(r => ({ id: r.id, name: r.name, type: r.type, similarity: r.similarity, })), total: results.length, }; } if (action === 'delete') { const patternId = input.patternId; if (!store.patterns[patternId]) { return { success: false, error: 'Pattern not found' }; } delete store.patterns[patternId]; saveNeuralStore(store); return { success: true, deleted: patternId }; } return { success: false, error: 'Unknown action' }; }, }, { name: 'neural_compress', description: 'Compress neural model or embeddings Use when nothing native trains on your workflow — Claude Code has no learning loop. Use to train SONA/MoE/EWC patterns from successful task outcomes; query via neural_predict before spawning agents. Off-path for one-shot work.', category: 'neural', inputSchema: { type: 'object', properties: { modelId: { type: 'string', description: 'Model ID to compress' }, method: { type: 'string', enum: ['quantize', 'prune', 'distill'], description: 'Compression method' }, targetSize: { type: 'number', description: 'Target size reduction (0-1)' }, }, }, handler: async (input) => { if (input.modelId) { const v = validateIdentifier(input.modelId, 'modelId'); if (!v.valid) return { success: false, error: v.error }; } const store = loadNeuralStore(); const method = input.method || 'quantize'; const targetReduction = input.targetSize || 0.5; const patterns = Object.values(store.patterns); if (patterns.length === 0) { return { success: false, error: 'No patterns to compress. Train patterns first with neural_train.' }; } const beforeCount = patterns.length; const beforeSize = patterns.reduce((s, p) => s + (p.embedding?.length || 0) * 4, 0); // Float32 = 4 bytes if (method === 'quantize') { try { const { quantizeInt8, getQuantizationStats } = await import('../memory/memory-initializer.js'); let totalCompressed = 0; for (const pattern of patterns) { if (pattern.embedding && pattern.embedding.length > 0) { const stats = getQuantizationStats(pattern.embedding); const quantized = quantizeInt8(pattern.embedding); // Store quantized metadata (keep original embedding for search) pattern._quantized = { scale: quantized.scale, zeroPoint: quantized.zeroPoint, compressionRatio: stats.compressionRatio, }; totalCompressed++; } } saveNeuralStore(store); return { success: true, _real: true, method, embeddingProvider: embeddingServiceName, patternsCompressed: totalCompressed, compressionRatio: '3.92x (Int8)', beforeBytes: beforeSize, afterBytes: Math.round(beforeSize / 3.92), }; } catch { return { success: false, error: 'Quantization requires memory-initializer. Run `memory init` first.' }; } } if (method === 'prune') { // Prune patterns with low usage count below threshold (targetReduction as min usage) const threshold = targetReduction; const toRemove = []; for (const [id, pattern] of Object.entries(store.patterns)) { if ((pattern.usageCount || 0) < threshold) toRemove.push(id); } for (const id of toRemove) delete store.patterns[id]; saveNeuralStore(store); return { success: true, _real: true, method, embeddingProvider: embeddingServiceName, threshold, patternsRemoved: toRemove.length, patternsBefore: beforeCount, patternsAfter: Object.keys(store.patterns).length, }; } if (method === 'distill') { // Merge similar patterns by cosine similarity > 0.95 const patternList = Object.entries(store.patterns); const merged = []; for (let i = 0; i < patternList.length; i++) { const [idA, a] = patternList[i]; if (merged.includes(idA)) continue; for (let j = i + 1; j < patternList.length; j++) { const [idB, b] = patternList[j]; if (!a.embedding || !b.embedding || merged.includes(idB)) continue; const sim = cosineSimilarity(a.embedding, b.embedding); if (sim > 0.95) { // Merge: average embeddings, keep higher usage count for (let k = 0; k < a.embedding.length; k++) { a.embedding[k] = (a.embedding[k] + (b.embedding[k] || 0)) / 2; } a.usageCount = Math.max(a.usageCount || 0, b.usageCount || 0); delete store.patterns[idB]; merged.push(idB); } } } saveNeuralStore(store); return { success: true, _real: true, method, embeddingProvider: embeddingServiceName, patternsMerged: merged.length, patternsBefore: beforeCount, patternsAfter: Object.keys(store.patterns).length, }; } return { success: false, error: `Unknown method: ${method}. Use quantize, prune, or distill.` }; }, }, { name: 'neural_status', description: 'Get neural system status Use when nothing native trains on your workflow — Claude Code has no learning loop. Use to train SONA/MoE/EWC patterns from successful task outcomes; query via neural_predict before spawning agents. Off-path for one-shot work.', category: 'neural', inputSchema: { type: 'object', properties: { modelId: { type: 'string', description: 'Specific model ID' }, detailed: { type: 'boolean', description: 'Include detailed info' }, }, }, handler: async (input) => { if (input.modelId) { const v = validateIdentifier(input.modelId, 'modelId'); if (!v.valid) return { success: false, error: v.error }; } const store = loadNeuralStore(); if (input.modelId) { const model = store.models[input.modelId]; if (!model) { return { success: false, error: 'Model not found' }; } return { success: true, model }; } const models = Object.values(store.models); const patterns = Object.values(store.patterns); return { _realEmbeddings: !!realEmbeddings, embeddingProvider: realEmbeddings ? `@claude-flow/embeddings (${embeddingServiceName})` : 'hash-based (deterministic)', models: { total: models.length, ready: models.filter(m => m.status === 'ready').length, training: models.filter(m => m.status === 'training').length, avgAccuracy: models.length > 0 ? models.reduce((sum, m) => sum + m.accuracy, 0) / models.length : 0, }, patterns: { total: patterns.length, byType: patterns.reduce((acc, p) => { acc[p.type] = (acc[p.type] || 0) + 1; return acc; }, {}), totalEmbeddingDims: patterns.length > 0 ? patterns[0].embedding.length : 384, }, features: { hnsw: true, quantization: true, // #1770: probe the real loader instead of returning a literal false. // Was hardcoded false, which contradicted hooks_intelligence_stats's // simultaneous claim of `implementation: real-flash-attention`. // The two surfaces now agree on a single source of truth. flashAttention: await (async () => { try { // #1773 item 4 — flash-attention now lives in @claude-flow/neural const { getFlashAttention } = await import('@claude-flow/neural'); return getFlashAttention() !== null; } catch { return false; } })(), reasoningBank: true, }, }; }, }, { name: 'neural_optimize', description: 'Optimize neural model performance Use when nothing native trains on your workflow — Claude Code has no learning loop. Use to train SONA/MoE/EWC patterns from successful task outcomes; query via neural_predict before spawning agents. Off-path for one-shot work.', category: 'neural', inputSchema: { type: 'object', properties: { modelId: { type: 'string', description: 'Model ID to optimize' }, target: { type: 'string', enum: ['speed', 'memory', 'accuracy', 'balanced'], description: 'Optimization target' }, }, }, handler: async (input) => { if (input.modelId) { const v = validateIdentifier(input.modelId, 'modelId'); if (!v.valid) return { success: false, error: v.error }; } const store = loadNeuralStore(); const target = input.target || 'balanced'; const patterns = Object.values(store.patterns); if (patterns.length === 0) { return { success: false, error: 'No patterns to optimize. Train patterns first with neural_train.' }; } const startTime = performance.now(); const actions = []; const beforeCount = patterns.length; const dims = patterns[0]?.embedding?.length || 0; let patternsRemoved = 0; let patternsQuantized = 0; let duplicatesRemoved = 0; // speed / balanced: deduplicate identical or near-identical patterns if (target === 'speed' || target === 'balanced') { const seen = new Map(); // hash -> id for (const [id, p] of Object.entries(store.patterns)) { if (!p.embedding || p.embedding.length === 0) continue; // Quick hash: first 8 dims rounded const hash = p.embedding.slice(0, 8).map(v => v.toFixed(4)).join(','); if (seen.has(hash)) { // Verify with full cosine similarity const existingId = seen.get(hash); const existing = store.patterns[existingId]; if (existing && cosineSimilarity(p.embedding, existing.embedding) > 0.99) { existing.usageCount = Math.max(existing.usageCount || 0, p.usageCount || 0); delete store.patterns[id]; duplicatesRemoved++; } } else { seen.set(hash, id); } } if (duplicatesRemoved > 0) actions.push(`Removed ${duplicatesRemoved} near-duplicate patterns`); } // memory / balanced: quantize large embeddings if (target === 'memory' || target === 'balanced') { try { const { quantizeInt8, getQuantizationStats } = await import('../memory/memory-initializer.js'); for (const p of Object.values(store.patterns)) { if (p.embedding && p.embedding.length > 0 && !p._quantized) { const stats = getQuantizationStats(p.embedding); const q = quantizeInt8(p.embedding); p._quantized = { scale: q.scale, zeroPoint: q.zeroPoint, compressionRatio: stats.compressionRatio }; patternsQuantized++; } } if (patternsQuantized > 0) actions.push(`Quantized ${patternsQuantized} pattern embeddings (Int8, ~3.92x)`); } catch { actions.push('Quantization skipped (memory-initializer not available)'); } } // accuracy / balanced: prune low-usage, zero-embedding patterns if (target === 'accuracy' || target === 'balanced') { for (const [id, p] of Object.entries(store.patterns)) { if (!p.embedding || p.embedding.length === 0) { delete store.patterns[id]; patternsRemoved++; continue; } // Remove patterns with all-zero embeddings (no useful signal) const norm = p.embedding.reduce((s, v) => s + v * v, 0); if (norm < 1e-10) { delete store.patterns[id]; patternsRemoved++; } } if (patternsRemoved > 0) actions.push(`Pruned ${patternsRemoved} empty/zero-signal patterns`); } saveNeuralStore(store); const elapsed = Math.round(performance.now() - startTime); return { success: true, _real: true, target, embeddingProvider: embeddingServiceName, actions, patternsBefore: beforeCount, patternsAfter: Object.keys(store.patterns).length, duplicatesRemoved, patternsQuantized, patternsRemoved, embeddingDims: dims, elapsedMs: elapsed, }; }, }, ]; //# sourceMappingURL=neural-tools.js.map