@claude-flow/embeddings
Version:
V3 Embedding Service - OpenAI, Transformers.js, Agentic-Flow (ONNX), Mock providers with hyperbolic embeddings, normalization, and chunking
87 lines • 3.62 kB
TypeScript
/**
* ADR-121 Phase 21 — Content-addressed embed cache (BEYOND SOTA).
*
* The Phase 20 lazy router cuts feature-extraction cost by 24% on a
* mixed workload — but it still pays the question-embed cost on
* EVERY query, even when the same question was asked moments ago.
* Production RAG has heavy repeated-query patterns (FAQs, common
* queries hit thousands of times). The right fix is a
* content-addressed cache: hash the (normalized) input text, look
* up the cached vector, skip the embed entirely on a hit.
*
* This module ships:
* - `EmbedCache` — in-memory LRU cache with hit/miss stats
* - `wrapWithCache(embedFn, cache)` — transparent adapter that
* turns any embed function into a cache-checking one
*
* Cache key = sha256-hex of (normalized text + dim). The dim is
* mixed in so two providers with different output sizes don't
* collide. Normalization: lowercase + trim + collapse internal
* whitespace — matches what production cache lookups would do.
*
* Composes with the Phase 20 lazy router by passing
* `wrapWithCache(embedFn, cache)` as the `embed` adapter.
*/
export interface EmbedCacheOptions {
/** Max entries before LRU eviction kicks in. Default 1000. */
readonly maxEntries?: number;
/** Vector dimension — mixed into the cache key. Default auto-detected on first set. */
readonly dimension?: number;
}
export interface EmbedCacheStats {
readonly entries: number;
readonly maxEntries: number;
readonly hits: number;
readonly misses: number;
/** Total lookups (hits + misses). */
readonly lookups: number;
/** Hit rate in [0, 1]. */
readonly hitRate: number;
/** Total bytes occupied by cached vectors (best-effort estimate). */
readonly approxByteSize: number;
}
/**
* In-memory LRU cache for embeddings. The cache key is the sha256
* hex of the canonicalized text + dim — so two distinct text bodies
* never collide and the same text always lands on the same key.
*
* Cache state is process-local. For cross-process sharing use
* `PersistentEmbeddingCache` from `persistent-cache.ts`.
*/
export declare class EmbedCache {
private readonly maxEntries;
private dim;
private readonly store;
private hits;
private misses;
constructor(options?: EmbedCacheOptions);
/**
* Compute the cache key for a text + dim pair. Exposed for
* testing + so the lazy router can pre-key lookups.
*/
keyFor(text: string, dimension: number): string;
get(text: string): Float32Array | undefined;
set(text: string, vector: Float32Array | number[]): void;
has(text: string): boolean;
/** Clear all entries; reset stats. */
reset(): void;
stats(): EmbedCacheStats;
}
/**
* Canonicalize text for stable cache key derivation: trim, collapse
* internal whitespace, lowercase. Identical to what production cache
* lookups should do — "how does AUTH work?" and "how does auth work?"
* should hit the same cache entry.
*/
export declare function canonicalizeText(text: string): string;
/**
* Wrap an async embed function with a cache-checking adapter. On
* cache hit, returns the cached vector without calling the wrapped
* embedder. On miss, calls the wrapped embedder and stores the
* result.
*
* The returned function has the same signature as the input function
* so it can be passed to any router as a drop-in replacement.
*/
export declare function wrapWithCache(embedder: (text: string) => Promise<Float32Array | number[]>, cache: EmbedCache): (text: string) => Promise<Float32Array>;
//# sourceMappingURL=embed-cache.d.ts.map