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
243 lines • 7.98 kB
JavaScript
/**
* Vector Database Module
*
* Provides optional ruvector WASM-accelerated vector operations for:
* - Semantic similarity search
* - HNSW indexing (150x faster)
* - Embedding generation
*
* Gracefully degrades when ruvector is not installed.
*
* Created with love by ruv.io
*/
// ============================================================================
// Fallback Implementation (when ruvector not available)
// ============================================================================
class FallbackVectorDB {
vectors = new Map();
dimensions;
constructor(dimensions) {
this.dimensions = dimensions;
}
insert(embedding, id, metadata) {
this.vectors.set(id, { embedding, metadata });
}
search(query, k = 10) {
const results = [];
for (const [id, { embedding, metadata }] of this.vectors) {
const score = cosineSimilarity(query, embedding);
results.push({ id, score, metadata });
}
return results
.sort((a, b) => b.score - a.score)
.slice(0, k);
}
remove(id) {
return this.vectors.delete(id);
}
size() {
return this.vectors.size;
}
clear() {
this.vectors.clear();
}
}
/**
* Compute cosine similarity between two vectors
*/
function cosineSimilarity(a, b) {
if (a.length !== b.length) {
throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
}
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];
}
const denom = Math.sqrt(normA) * Math.sqrt(normB);
return denom === 0 ? 0 : dotProduct / denom;
}
/**
* Generate a simple hash-based embedding (fallback when ruvector not available)
*/
function generateHashEmbedding(text, dimensions = 768) {
const embedding = new Float32Array(dimensions);
const normalized = text.toLowerCase().trim();
// Simple hash function
let hash = 0;
for (let i = 0; i < normalized.length; i++) {
hash = ((hash << 5) - hash) + normalized.charCodeAt(i);
hash = hash & hash; // Convert to 32bit integer
}
// Generate pseudo-random embedding based on hash
for (let i = 0; i < dimensions; i++) {
embedding[i] = Math.sin(hash * (i + 1) * 0.001) * 0.5 + 0.5;
}
// Normalize
let norm = 0;
for (let i = 0; i < dimensions; i++) {
norm += embedding[i] * embedding[i];
}
norm = Math.sqrt(norm);
for (let i = 0; i < dimensions; i++) {
embedding[i] /= norm;
}
return embedding;
}
// ============================================================================
// Module State
// ============================================================================
let ruvectorModule = null;
let loadAttempted = false;
let isAvailable = false;
// ============================================================================
// Public API
// ============================================================================
/**
* Attempt to load the ruvector module
* Returns true if successfully loaded, false otherwise
*/
export async function loadRuVector() {
if (loadAttempted) {
return isAvailable;
}
loadAttempted = true;
try {
// Dynamic import to handle missing dependency gracefully
const ruvector = await import('ruvector').catch(() => null);
// ruvector exports VectorDB class, not createVectorDB function
if (ruvector && (typeof ruvector.VectorDB === 'function' || typeof ruvector.VectorDb === 'function')) {
// Create adapter module that matches our expected interface
const VectorDBClass = ruvector.VectorDB || ruvector.VectorDb;
ruvectorModule = {
createVectorDB: async (dimensions) => {
const db = new VectorDBClass({ dimensions });
// Wrap ruvector's VectorDB to match our interface
return {
insert: (embedding, id, metadata) => {
db.insert({ id, vector: embedding, metadata });
},
search: async (query, k = 10) => {
const results = await db.search({ vector: query, k });
return results.map((r) => ({
id: r.id,
score: r.score,
metadata: r.metadata,
}));
},
remove: (id) => {
db.delete(id);
return true;
},
size: async () => {
const len = await db.len();
return len;
},
clear: () => {
// Not directly supported - would need to recreate
},
};
},
generateEmbedding: (text, dimensions = 768) => {
// ruvector may not have this - use fallback
return generateHashEmbedding(text, dimensions);
},
cosineSimilarity: (a, b) => {
return cosineSimilarity(a, b);
},
isWASMAccelerated: () => {
return ruvector.isWasm?.() ?? false;
},
};
isAvailable = true;
return true;
}
}
catch {
// Silently fail - ruvector is optional
}
isAvailable = false;
return false;
}
/**
* Check if ruvector is available
*/
export function isRuVectorAvailable() {
return isAvailable;
}
/**
* Check if WASM acceleration is enabled
*/
export function isWASMAccelerated() {
if (ruvectorModule && typeof ruvectorModule.isWASMAccelerated === 'function') {
return ruvectorModule.isWASMAccelerated();
}
return false;
}
/**
* Create a vector database
* Uses ruvector HNSW if available, falls back to brute-force search
*/
export async function createVectorDB(dimensions = 768) {
await loadRuVector();
if (ruvectorModule && typeof ruvectorModule.createVectorDB === 'function') {
try {
return await ruvectorModule.createVectorDB(dimensions);
}
catch {
// Fall back to simple implementation
}
}
return new FallbackVectorDB(dimensions);
}
/**
* Generate an embedding for text
* Uses ruvector if available, falls back to hash-based embedding
*/
export function generateEmbedding(text, dimensions = 768) {
if (ruvectorModule && typeof ruvectorModule.generateEmbedding === 'function') {
try {
return ruvectorModule.generateEmbedding(text, dimensions);
}
catch {
// Fall back to hash-based embedding
}
}
return generateHashEmbedding(text, dimensions);
}
/**
* Compute cosine similarity between two vectors
*/
export function computeSimilarity(a, b) {
if (ruvectorModule && typeof ruvectorModule.cosineSimilarity === 'function') {
try {
return ruvectorModule.cosineSimilarity(a, b);
}
catch {
// Fall back to JS implementation
}
}
return cosineSimilarity(a, b);
}
/**
* Get status information about the ruvector module
*/
export function getStatus() {
if (!isAvailable) {
return {
available: false,
wasmAccelerated: false,
backend: 'fallback',
};
}
const wasmAccelerated = isWASMAccelerated();
return {
available: true,
wasmAccelerated,
backend: wasmAccelerated ? 'ruvector-wasm' : 'ruvector',
};
}
//# sourceMappingURL=vector-db.js.map