/** * SMI-584: Semantic Embeddings Service * SMI-754: Added fallback mode for deterministic mock embeddings * SMI-1127: Lazy loading of @huggingface/transformers to avoid blocking CLI startup * * Uses all-MiniLM-L6-v2 model for fast, accurate skill embeddings. * Supports fallback mode for tests and when model unavailable. * * @see ADR-009: Embedding Service Fallback Strategy */ export type { EmbeddingResult, SimilarityResult, EmbeddingServiceOptions, FeatureExtractionPipeline, } from './embedding-types.js'; import type { FeatureExtractionPipeline } from './embedding-types.js'; import { hashText, generateMockEmbedding } from './embedding-utils.js'; export declare const testUtils: { /** Generate a deterministic mock embedding (for testing) */ generateMockEmbedding: typeof generateMockEmbedding; /** Generate a hash from text (for testing) */ hashText: typeof hashText; }; export declare class EmbeddingService { private model; private modelPromise; private modelLoadFailed; private db; private readonly modelName; private readonly embeddingDim; private readonly useFallback; private hnswHandle; private hnswLoadPromise; /** Set to true when `hnswlib-node` is structurally absent (MODULE_NOT_FOUND). Permanent. */ private hnswPermanentlyUnavailable; /** * Create an EmbeddingService instance. * * @deprecated If dbPath is passed, use EmbeddingService.create(options) instead — * the async factory supports both native and WASM SQLite. Passing dbPath to this * constructor throws to prevent silent data loss. * * @param optionsOrDbPath - Options object or legacy dbPath string (dbPath throws) */ constructor(optionsOrDbPath?: string | { dbPath?: string; useFallback?: boolean; }); /** * Async factory — supports both native and WASM SQLite. * * @param optionsOrDbPath - Options object or dbPath string * @returns Fully initialised EmbeddingService instance */ static create(optionsOrDbPath?: string | { dbPath?: string; useFallback?: boolean; }): Promise; /** Check if service is running in fallback (mock) mode */ isUsingFallback(): boolean; private initEmbeddingTable; /** Static: Check if the transformers module is available without loading it */ static isTransformersAvailable(): boolean | undefined; /** Static: Check if embeddings functionality is available */ static checkAvailability(): Promise; /** Static: Get the error that occurred when loading the transformers module */ static getTransformersLoadError(): Error | null; /** Lazily load the embedding model */ loadModel(): Promise; /** Generate embedding for a single text */ embed(text: string): Promise; /** Batch embed multiple texts efficiently */ embedBatch(texts: Array<{ id: string; text: string; }>): Promise>; /** Store embedding in SQLite cache (and incrementally update HNSW if loaded) */ storeEmbedding(skillId: string, embedding: Float32Array, text: string): void; /** * Remove an embedding from both the SQLite cache and the in-memory HNSW * graph (if loaded). Returns true when at least one row was removed. * * SMI-4577: added so `EmbeddingService` can keep HNSW state consistent * during skill uninstall / re-index workflows. Previously embeddings * accumulated forever; this is a tiny surface tax for the new backend * but matches `HNSWEmbeddingStore.removeEmbedding`. */ removeEmbedding(skillId: string): boolean; /** Retrieve cached embedding */ getEmbedding(skillId: string): Float32Array | null; /** Get all cached embeddings */ getAllEmbeddings(): Map; /** Compute cosine similarity between two embeddings */ cosineSimilarity(a: Float32Array, b: Float32Array): number; /** * Find most similar skills to a query embedding. * * SMI-4577: now async so we can lazy-load the HNSW backend on first call. * - HNSW path (default): O(log n) approximate nearest-neighbour search * using `hnswlib-node`. Cache lives at `~/.skillsmith/cache/hnsw-*.bin`. * - Brute-force fallback: O(n) cosine over the full embedding map. * Triggered when (a) `SKILLSMITH_USE_HNSW=false`, (b) `hnswlib-node` * is not installed (optional dependency), or (c) the HNSW index fails * to load/build for any reason. * * @see ADR-009 (2026-05 amendment) */ findSimilar(queryEmbedding: Float32Array, topK?: number): Promise>; /** * Brute-force cosine similarity over the full embedding map. Exposed as a * named fallback so callers (and tests) can opt out of HNSW deterministically. * * SMI-4577: kept synchronous so legacy bench code and embedded use-cases * that can't await still have a working path; the async `findSimilar` * delegates here when HNSW is unavailable. */ findSimilarBruteForce(queryEmbedding: Float32Array, topK?: number): Array<{ skillId: string; score: number; }>; /** * Lazy-load (or build) the HNSW backend. Returns null when permanently * unavailable (optional dep missing) or when the build/load failed * transiently — the caller falls back to brute-force search. * * SMI-4577. Concurrent calls share a single in-flight promise. */ private loadOrBuildHNSW; /** Pre-compute embeddings for all skills in database */ precomputeEmbeddings(skills: Array<{ id: string; name: string; description: string; }>): Promise; /** Close database connection (and flush HNSW persist) */ close(): void; } export default EmbeddingService; export * from './hnsw-store.exports.js'; //# sourceMappingURL=index.d.ts.map