/** * Semantic query result cache. * * Sits between `DatasetClient.execute()` and the underlying query builder / * backend, keyed by the canonical query signature (see query-signature.ts). * Supports TTL freshness, an optional stale-while-revalidate window, and * deduplication of concurrent identical lookups so a burst of the same query * executes once — including against async stores, where the in-flight lookup * is registered before the store read. Piggybacked callers inherit the * initiating caller's TTL resolution. * * Values are cloned on write and on read: callers can mutate results freely * without contaminating the cache, and cached hits never alias each other. */ export interface SemanticCacheEntry { value: unknown; storedAt: number; } /** * Pluggable store. The default is an in-process LRU; provide a custom store * (e.g. Redis-backed) for multi-instance deployments. Stores hold opaque * entries — freshness is decided by the cache from `storedAt` and the * effective TTL, so per-call TTLs work against shared entries. * * Store errors are non-fatal: a failed read is treated as a miss and a failed * write is dropped, so a store outage degrades to uncached execution rather * than failing queries. */ export interface SemanticCacheStore { get(key: string): SemanticCacheEntry | undefined | Promise; set(key: string, entry: SemanticCacheEntry): void | Promise; delete(key: string): void | Promise; clear?(): void | Promise; } /** Client-level cache defaults (see `CreateDatasetClientOptions.cache`). */ export interface SemanticCacheOptions { /** Fresh window in milliseconds. 0 / omitted = only per-call opt-in caches. */ ttlMs?: number; /** * Additional window after `ttlMs` during which a stale result is returned * immediately while a background refresh repopulates the entry. */ staleWhileRevalidateMs?: number; /** Max entries for the default in-memory store. Ignored when `store` is set. */ maxEntries?: number; /** Custom store; defaults to an in-process LRU. */ store?: SemanticCacheStore; /** * Default cache partition included in every key. Set this when multiple * clients pointing at different data sources share one store (e.g. Redis), * so identical queries against different backends never collide. */ scope?: string; } /** Per-call cache controls, passed via `ExecutionContext.cache`. */ export interface SemanticCacheRuntime { /** Overrides the client-level TTL for this call. */ ttlMs?: number; /** Overrides the client-level stale-while-revalidate window for this call. */ staleWhileRevalidateMs?: number; /** * `bypass` skips the cache entirely (no read, no write); * `refresh` skips the read but stores the fresh result. Refresh needs a * TTL (per-call or client-level) to store under; when neither is * configured it executes uncached and logs a one-time warning. */ mode?: 'bypass' | 'refresh'; /** * Cache partition for this call, mixed into the query signature. Required * to cache calls that override the query builder via `runtime.builderFactory` * — without it such calls bypass the cache, because the key alone cannot * tell two data sources apart. */ scope?: string; } /** Cache observability attached to `meta.cache` on cached-path results. */ export interface SemanticCacheMetaInfo { hit: boolean; /** Milliseconds since the entry was stored; only on hits. */ ageMs?: number; /** True when served from the stale-while-revalidate window. */ stale?: boolean; } /** * Aggregate lookup counters, snapshot via `SemanticQueryCache.getStats()`. * * Counters are per cache instance and in-process: with a shared store (e.g. * Redis) each process reports its own lookups, not cluster-wide totals. Every * caller counts once — concurrent callers deduplicated onto one execution * each record their own outcome. Bypassed calls (no TTL, `cache: false`, * `mode: 'bypass'`, unscoped builder overrides) never reach the cache and are * not counted. */ export interface SemanticCacheStats { /** Fresh hits (within TTL). */ hits: number; /** Lookups that executed the query (includes `mode: 'refresh'` calls). */ misses: number; /** Hits served from the stale-while-revalidate window. */ staleHits: number; /** (hits + staleHits) / total lookups; 0 when no lookups yet. */ hitRate: number; /** Whether `clear()` can clear entries (the store implements `clear`). */ clearSupported: boolean; } export declare function createMemoryCacheStore(options?: { maxEntries?: number; }): SemanticCacheStore; type CacheableResult = { meta?: object; }; export declare class SemanticQueryCache { private readonly store; private readonly defaults; private readonly pending; private readonly refreshing; private warnedRefreshWithoutTtl; private hits; private misses; private staleHits; constructor(options?: SemanticCacheOptions); private resolveConfig; /** * Runs `execute` through the cache. Errors are never cached; concurrent * identical misses share one execution. */ through(key: string, execute: () => Promise, runtime?: SemanticCacheRuntime | false): Promise; private record; /** Snapshot of this instance's lookup counters (see `SemanticCacheStats`). */ getStats(): SemanticCacheStats; /** * Clears all entries. Returns false without touching anything when the * store does not implement `clear` (see `SemanticCacheStats.clearSupported` * — callers advertising a clear affordance should check it first). Lookup * counters are not reset: they count lookups, not entries. */ clear(): Promise; /** Best-effort write: a failing store degrades to "no caching", never a failed call. */ private writeEntry; private refreshInBackground; } export {}; //# sourceMappingURL=semantic-query-cache.d.ts.map