nttp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +245 -0
  2. package/dist/NTTP.d.ts +121 -0
  3. package/dist/NTTP.d.ts.map +1 -0
  4. package/dist/NTTP.js +229 -0
  5. package/dist/NTTP.js.map +1 -0
  6. package/dist/cache/exact-cache.d.ts +46 -0
  7. package/dist/cache/exact-cache.d.ts.map +1 -0
  8. package/dist/cache/exact-cache.js +104 -0
  9. package/dist/cache/exact-cache.js.map +1 -0
  10. package/dist/cache/index.d.ts +8 -0
  11. package/dist/cache/index.d.ts.map +1 -0
  12. package/dist/cache/index.js +7 -0
  13. package/dist/cache/index.js.map +1 -0
  14. package/dist/cache/semantic-cache.d.ts +82 -0
  15. package/dist/cache/semantic-cache.d.ts.map +1 -0
  16. package/dist/cache/semantic-cache.js +243 -0
  17. package/dist/cache/semantic-cache.js.map +1 -0
  18. package/dist/cache/types.d.ts +135 -0
  19. package/dist/cache/types.d.ts.map +1 -0
  20. package/dist/cache/types.js +5 -0
  21. package/dist/cache/types.js.map +1 -0
  22. package/dist/cache.d.ts +71 -0
  23. package/dist/cache.d.ts.map +1 -0
  24. package/dist/cache.js +129 -0
  25. package/dist/cache.js.map +1 -0
  26. package/dist/errors.d.ts +35 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +55 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/executor.d.ts +82 -0
  31. package/dist/executor.d.ts.map +1 -0
  32. package/dist/executor.js +395 -0
  33. package/dist/executor.js.map +1 -0
  34. package/dist/index.d.ts +8 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +7 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/intent.d.ts +55 -0
  39. package/dist/intent.d.ts.map +1 -0
  40. package/dist/intent.js +183 -0
  41. package/dist/intent.js.map +1 -0
  42. package/dist/llm.d.ts +60 -0
  43. package/dist/llm.d.ts.map +1 -0
  44. package/dist/llm.js +171 -0
  45. package/dist/llm.js.map +1 -0
  46. package/dist/types.d.ts +280 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +5 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/utils.d.ts +61 -0
  51. package/dist/utils.d.ts.map +1 -0
  52. package/dist/utils.js +19 -0
  53. package/dist/utils.js.map +1 -0
  54. package/package.json +94 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * L1 Exact Match Cache
3
+ * Fast hash-based cache for identical queries
4
+ */
5
+ import { createHash } from 'crypto';
6
+ /**
7
+ * L1 exact match cache using Map with LRU eviction
8
+ */
9
+ export class ExactCache {
10
+ cache = new Map();
11
+ accessOrder = new Map();
12
+ accessCounter = 0;
13
+ maxSize;
14
+ hits = 0;
15
+ misses = 0;
16
+ constructor(maxSize = 1000) {
17
+ this.maxSize = maxSize;
18
+ }
19
+ /**
20
+ * Get cached result for a query
21
+ */
22
+ get(query) {
23
+ const key = this.normalizeQuery(query);
24
+ const result = this.cache.get(key);
25
+ if (result) {
26
+ // Update hit count and access time
27
+ result.hitCount++;
28
+ result.lastUsedAt = new Date();
29
+ this.accessOrder.set(key, ++this.accessCounter);
30
+ this.hits++;
31
+ return result;
32
+ }
33
+ this.misses++;
34
+ return null;
35
+ }
36
+ /**
37
+ * Set cached result for a query
38
+ */
39
+ set(query, result) {
40
+ const key = this.normalizeQuery(query);
41
+ // Evict if at max size
42
+ if (!this.cache.has(key) && this.cache.size >= this.maxSize) {
43
+ this.evictLRU();
44
+ }
45
+ this.cache.set(key, result);
46
+ this.accessOrder.set(key, ++this.accessCounter);
47
+ }
48
+ /**
49
+ * Clear all cached results
50
+ */
51
+ clear() {
52
+ this.cache.clear();
53
+ this.accessOrder.clear();
54
+ this.accessCounter = 0;
55
+ this.hits = 0;
56
+ this.misses = 0;
57
+ }
58
+ /**
59
+ * Get cache statistics
60
+ */
61
+ getStats() {
62
+ return {
63
+ size: this.cache.size,
64
+ hits: this.hits,
65
+ misses: this.misses,
66
+ };
67
+ }
68
+ /**
69
+ * Normalize query string for consistent cache keys
70
+ * - Convert to lowercase
71
+ * - Trim whitespace
72
+ * - Collapse multiple spaces
73
+ * - Hash to fixed-length key
74
+ */
75
+ normalizeQuery(query) {
76
+ const normalized = query
77
+ .toLowerCase()
78
+ .trim()
79
+ .replace(/\s+/g, ' ');
80
+ // Use SHA-256 hash for cache key
81
+ return createHash('sha256')
82
+ .update(normalized)
83
+ .digest('hex')
84
+ .substring(0, 16);
85
+ }
86
+ /**
87
+ * Evict least recently used entry
88
+ */
89
+ evictLRU() {
90
+ let oldestKey = null;
91
+ let oldestAccess = Infinity;
92
+ for (const [key, accessTime] of this.accessOrder.entries()) {
93
+ if (accessTime < oldestAccess) {
94
+ oldestAccess = accessTime;
95
+ oldestKey = key;
96
+ }
97
+ }
98
+ if (oldestKey) {
99
+ this.cache.delete(oldestKey);
100
+ this.accessOrder.delete(oldestKey);
101
+ }
102
+ }
103
+ }
104
+ //# sourceMappingURL=exact-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exact-cache.js","sourceRoot":"","sources":["../../src/cache/exact-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * nttp cache system
3
+ * Exports for 3-layer caching architecture
4
+ */
5
+ export { ExactCache } from './exact-cache.js';
6
+ export { SemanticCache } from './semantic-cache.js';
7
+ export type { CachedResult, SemanticMatch, SemanticCacheConfig, LayerStats, CacheStats, } from './types.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EACV,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * nttp cache system
3
+ * Exports for 3-layer caching architecture
4
+ */
5
+ export { ExactCache } from './exact-cache.js';
6
+ export { SemanticCache } from './semantic-cache.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * L2 Semantic Cache
3
+ * Embedding-based similarity matching using AI SDK
4
+ *
5
+ * PERFORMANCE NOTE: This implementation uses O(N) linear scan for similarity search.
6
+ * For large caches (>10,000 entries), consider using a vector database like:
7
+ * - Pinecone
8
+ * - Weaviate
9
+ * - FAISS (via Node.js bindings)
10
+ * - Qdrant
11
+ *
12
+ * These provide approximate nearest neighbor (ANN) search in O(log N) time.
13
+ */
14
+ import type { CachedResult, SemanticMatch, SemanticCacheConfig, LayerStats } from './types.js';
15
+ /**
16
+ * L2 semantic similarity cache using embeddings
17
+ */
18
+ export declare class SemanticCache {
19
+ private entries;
20
+ private threshold;
21
+ private maxSize;
22
+ private model;
23
+ private modelPromise;
24
+ private config;
25
+ private hits;
26
+ private misses;
27
+ constructor(config: SemanticCacheConfig);
28
+ /**
29
+ * Lazy initialization of embedding model
30
+ * Supports multiple providers with dynamic imports
31
+ */
32
+ private initializeModel;
33
+ /**
34
+ * Load the embedding model based on provider configuration
35
+ * Passes API keys directly to avoid process.env race conditions
36
+ */
37
+ private loadEmbeddingModel;
38
+ /**
39
+ * Find semantically similar cached query
40
+ * ALWAYS returns the embedding to prevent double API billing on cache miss
41
+ *
42
+ * Usage pattern:
43
+ * const { match, embedding } = await cache.find(query);
44
+ * if (match) {
45
+ * // Cache hit - use match.result
46
+ * } else {
47
+ * // Cache miss - generate result and use addWithEmbedding(query, embedding, result)
48
+ * }
49
+ */
50
+ find(query: string): Promise<{
51
+ match: SemanticMatch | null;
52
+ embedding: number[];
53
+ }>;
54
+ /**
55
+ * Add new entry to cache with embedding generation
56
+ */
57
+ add(query: string, result: CachedResult): Promise<void>;
58
+ /**
59
+ * Add new entry with pre-computed embedding
60
+ * Used when embedding was already computed during find()
61
+ */
62
+ addWithEmbedding(query: string, embedding: number[], result: CachedResult): void;
63
+ /**
64
+ * Clear all cached results
65
+ */
66
+ clear(): void;
67
+ /**
68
+ * Get cache statistics
69
+ */
70
+ getStats(): LayerStats;
71
+ /**
72
+ * Evict least recently used entry
73
+ *
74
+ * NOTE: Minor race condition possible with concurrent adds in async code.
75
+ * Multiple parallel add() calls might all pass the size check before any
76
+ * eviction completes, temporarily exceeding maxSize by a few entries.
77
+ * This is acceptable for most use cases. For strict size limits, consider
78
+ * using a mutex/semaphore around the add operation.
79
+ */
80
+ private evictLRU;
81
+ }
82
+ //# sourceMappingURL=semantic-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-cache.d.ts","sourceRoot":"","sources":["../../src/cache/semantic-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,UAAU,EACX,MAAM,YAAY,CAAC;AAWpB;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;gBAEP,MAAM,EAAE,mBAAmB;IAMvC;;;OAGG;YACW,eAAe;IAa7B;;;OAGG;YACW,kBAAkB;IAmFhC;;;;;;;;;;;OAWG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA8CxF;;OAEG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7D;;;OAGG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IAahF;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAQtB;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ;CAkBjB"}
@@ -0,0 +1,243 @@
1
+ /**
2
+ * L2 Semantic Cache
3
+ * Embedding-based similarity matching using AI SDK
4
+ *
5
+ * PERFORMANCE NOTE: This implementation uses O(N) linear scan for similarity search.
6
+ * For large caches (>10,000 entries), consider using a vector database like:
7
+ * - Pinecone
8
+ * - Weaviate
9
+ * - FAISS (via Node.js bindings)
10
+ * - Qdrant
11
+ *
12
+ * These provide approximate nearest neighbor (ANN) search in O(log N) time.
13
+ */
14
+ import { embed, cosineSimilarity } from 'ai';
15
+ /**
16
+ * L2 semantic similarity cache using embeddings
17
+ */
18
+ export class SemanticCache {
19
+ entries = [];
20
+ threshold;
21
+ maxSize;
22
+ model;
23
+ modelPromise = null;
24
+ config;
25
+ hits = 0;
26
+ misses = 0;
27
+ constructor(config) {
28
+ this.threshold = config.threshold ?? 0.85;
29
+ this.maxSize = config.maxSize ?? 500;
30
+ this.config = config;
31
+ }
32
+ /**
33
+ * Lazy initialization of embedding model
34
+ * Supports multiple providers with dynamic imports
35
+ */
36
+ async initializeModel() {
37
+ if (this.model) {
38
+ return this.model;
39
+ }
40
+ if (this.modelPromise) {
41
+ return this.modelPromise;
42
+ }
43
+ this.modelPromise = this.loadEmbeddingModel();
44
+ return this.modelPromise;
45
+ }
46
+ /**
47
+ * Load the embedding model based on provider configuration
48
+ * Passes API keys directly to avoid process.env race conditions
49
+ */
50
+ async loadEmbeddingModel() {
51
+ switch (this.config.provider) {
52
+ case 'openai': {
53
+ try {
54
+ const { createOpenAI } = await import('@ai-sdk/openai');
55
+ const openai = createOpenAI({
56
+ apiKey: this.config.apiKey || process.env.OPENAI_API_KEY,
57
+ });
58
+ this.model = openai.textEmbeddingModel(this.config.model);
59
+ return this.model;
60
+ }
61
+ catch (error) {
62
+ throw new Error(`Failed to load @ai-sdk/openai. Install it with: npm install @ai-sdk/openai\nOriginal error: ${error}`);
63
+ }
64
+ }
65
+ case 'cohere': {
66
+ try {
67
+ // @ts-expect-error - Optional peer dependency
68
+ const { createCohere } = await import('@ai-sdk/cohere');
69
+ const cohere = createCohere({
70
+ apiKey: this.config.apiKey || process.env.COHERE_API_KEY,
71
+ });
72
+ this.model = cohere.embedding(this.config.model);
73
+ return this.model;
74
+ }
75
+ catch (error) {
76
+ throw new Error(`Failed to load @ai-sdk/cohere. Install it with: npm install @ai-sdk/cohere\nOriginal error: ${error}`);
77
+ }
78
+ }
79
+ case 'mistral': {
80
+ try {
81
+ // @ts-expect-error - Optional peer dependency
82
+ const { createMistral } = await import('@ai-sdk/mistral');
83
+ const mistral = createMistral({
84
+ apiKey: this.config.apiKey || process.env.MISTRAL_API_KEY,
85
+ });
86
+ this.model = mistral.embedding(this.config.model);
87
+ return this.model;
88
+ }
89
+ catch (error) {
90
+ throw new Error(`Failed to load @ai-sdk/mistral. Install it with: npm install @ai-sdk/mistral\nOriginal error: ${error}`);
91
+ }
92
+ }
93
+ case 'google': {
94
+ try {
95
+ // @ts-expect-error - Optional peer dependency
96
+ const { createGoogleGenerativeAI } = await import('@ai-sdk/google');
97
+ const google = createGoogleGenerativeAI({
98
+ apiKey: this.config.apiKey || process.env.GOOGLE_GENERATIVE_AI_API_KEY,
99
+ });
100
+ this.model = google.textEmbeddingModel(this.config.model);
101
+ return this.model;
102
+ }
103
+ catch (error) {
104
+ throw new Error(`Failed to load @ai-sdk/google. Install it with: npm install @ai-sdk/google\nOriginal error: ${error}`);
105
+ }
106
+ }
107
+ default: {
108
+ // Default to OpenAI for backward compatibility
109
+ try {
110
+ const { createOpenAI } = await import('@ai-sdk/openai');
111
+ const openai = createOpenAI({
112
+ apiKey: this.config.apiKey || process.env.OPENAI_API_KEY,
113
+ });
114
+ this.model = openai.textEmbeddingModel(this.config.model);
115
+ return this.model;
116
+ }
117
+ catch (error) {
118
+ throw new Error(`Failed to load @ai-sdk/openai. Install it with: npm install @ai-sdk/openai\nOriginal error: ${error}`);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * Find semantically similar cached query
125
+ * ALWAYS returns the embedding to prevent double API billing on cache miss
126
+ *
127
+ * Usage pattern:
128
+ * const { match, embedding } = await cache.find(query);
129
+ * if (match) {
130
+ * // Cache hit - use match.result
131
+ * } else {
132
+ * // Cache miss - generate result and use addWithEmbedding(query, embedding, result)
133
+ * }
134
+ */
135
+ async find(query) {
136
+ // Initialize model if needed
137
+ const model = await this.initializeModel();
138
+ // Generate embedding for the query (COST: 1 API call)
139
+ const { embedding } = await embed({
140
+ model,
141
+ value: query,
142
+ });
143
+ // Search for best match above threshold (O(N) linear scan)
144
+ let bestMatch = null;
145
+ let bestScore = 0;
146
+ for (const entry of this.entries) {
147
+ const score = cosineSimilarity(embedding, entry.embedding);
148
+ if (score >= this.threshold && score > bestScore) {
149
+ bestScore = score;
150
+ bestMatch = entry;
151
+ }
152
+ }
153
+ if (bestMatch) {
154
+ // Update hit count and access time
155
+ bestMatch.result.hitCount++;
156
+ bestMatch.result.lastUsedAt = new Date();
157
+ this.hits++;
158
+ return {
159
+ match: {
160
+ result: bestMatch.result,
161
+ similarity: bestScore,
162
+ originalQuery: bestMatch.query,
163
+ },
164
+ embedding, // Return embedding for potential reuse
165
+ };
166
+ }
167
+ this.misses++;
168
+ return {
169
+ match: null,
170
+ embedding, // CRITICAL: Return embedding so caller can use addWithEmbedding()
171
+ };
172
+ }
173
+ /**
174
+ * Add new entry to cache with embedding generation
175
+ */
176
+ async add(query, result) {
177
+ // Initialize model if needed
178
+ const model = await this.initializeModel();
179
+ const { embedding } = await embed({
180
+ model,
181
+ value: query,
182
+ });
183
+ this.addWithEmbedding(query, embedding, result);
184
+ }
185
+ /**
186
+ * Add new entry with pre-computed embedding
187
+ * Used when embedding was already computed during find()
188
+ */
189
+ addWithEmbedding(query, embedding, result) {
190
+ // Evict if at max size
191
+ if (this.entries.length >= this.maxSize) {
192
+ this.evictLRU();
193
+ }
194
+ this.entries.push({
195
+ query,
196
+ embedding,
197
+ result,
198
+ });
199
+ }
200
+ /**
201
+ * Clear all cached results
202
+ */
203
+ clear() {
204
+ this.entries = [];
205
+ this.hits = 0;
206
+ this.misses = 0;
207
+ }
208
+ /**
209
+ * Get cache statistics
210
+ */
211
+ getStats() {
212
+ return {
213
+ size: this.entries.length,
214
+ hits: this.hits,
215
+ misses: this.misses,
216
+ };
217
+ }
218
+ /**
219
+ * Evict least recently used entry
220
+ *
221
+ * NOTE: Minor race condition possible with concurrent adds in async code.
222
+ * Multiple parallel add() calls might all pass the size check before any
223
+ * eviction completes, temporarily exceeding maxSize by a few entries.
224
+ * This is acceptable for most use cases. For strict size limits, consider
225
+ * using a mutex/semaphore around the add operation.
226
+ */
227
+ evictLRU() {
228
+ if (this.entries.length === 0) {
229
+ return;
230
+ }
231
+ let oldestIndex = 0;
232
+ let oldestTime = this.entries[0].result.lastUsedAt;
233
+ for (let i = 1; i < this.entries.length; i++) {
234
+ const entryTime = this.entries[i].result.lastUsedAt;
235
+ if (entryTime < oldestTime) {
236
+ oldestTime = entryTime;
237
+ oldestIndex = i;
238
+ }
239
+ }
240
+ this.entries.splice(oldestIndex, 1);
241
+ }
242
+ }
243
+ //# sourceMappingURL=semantic-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-cache.js","sourceRoot":"","sources":["../../src/cache/semantic-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Types for nttp caching system
3
+ */
4
+ import type { JsonValue } from '../utils.js';
5
+ /**
6
+ * Cached query result with metadata
7
+ */
8
+ export interface CachedResult {
9
+ /**
10
+ * Schema ID for this query pattern
11
+ */
12
+ readonly schemaId: string;
13
+ /**
14
+ * Generated SQL query
15
+ */
16
+ readonly sql: string;
17
+ /**
18
+ * SQL query parameters
19
+ */
20
+ readonly params: JsonValue[];
21
+ /**
22
+ * Number of times this cache entry was hit (mutable)
23
+ */
24
+ hitCount: number;
25
+ /**
26
+ * When this cache entry was created
27
+ */
28
+ readonly createdAt: Date;
29
+ /**
30
+ * When this cache entry was last used (mutable)
31
+ */
32
+ lastUsedAt: Date;
33
+ }
34
+ /**
35
+ * Semantic match result from L2 cache
36
+ * Note: Embedding is returned separately from find() to prevent double API billing
37
+ */
38
+ export interface SemanticMatch {
39
+ /**
40
+ * The cached result
41
+ */
42
+ result: CachedResult;
43
+ /**
44
+ * Cosine similarity score (0-1)
45
+ */
46
+ similarity: number;
47
+ /**
48
+ * Original query that was cached
49
+ */
50
+ originalQuery: string;
51
+ }
52
+ /**
53
+ * Statistics for a single cache layer
54
+ */
55
+ export interface LayerStats {
56
+ /**
57
+ * Current size of the cache
58
+ */
59
+ size: number;
60
+ /**
61
+ * Number of cache hits
62
+ */
63
+ hits: number;
64
+ /**
65
+ * Number of cache misses
66
+ */
67
+ misses: number;
68
+ }
69
+ /**
70
+ * Aggregate cache statistics
71
+ */
72
+ export interface CacheStats {
73
+ /**
74
+ * L1 exact match cache stats
75
+ */
76
+ l1: LayerStats;
77
+ /**
78
+ * L2 semantic cache stats
79
+ */
80
+ l2: LayerStats;
81
+ /**
82
+ * L3 LLM fallback stats
83
+ */
84
+ l3: {
85
+ /**
86
+ * Number of LLM calls made
87
+ */
88
+ calls: number;
89
+ };
90
+ /**
91
+ * Total queries processed
92
+ */
93
+ totalQueries: number;
94
+ /**
95
+ * Hit rates for each layer
96
+ */
97
+ hitRates: {
98
+ l1: number;
99
+ l2: number;
100
+ l3: number;
101
+ };
102
+ /**
103
+ * Estimated cost saved (USD)
104
+ */
105
+ estimatedCostSaved: number;
106
+ }
107
+ /**
108
+ * Configuration for L2 semantic cache
109
+ */
110
+ export interface SemanticCacheConfig {
111
+ /**
112
+ * Embedding provider
113
+ */
114
+ provider: 'openai' | 'cohere' | 'mistral' | 'google';
115
+ /**
116
+ * Embedding model name
117
+ */
118
+ model: string;
119
+ /**
120
+ * Similarity threshold for matches (0-1)
121
+ * Recommended: 0.80-0.85 for natural language queries
122
+ * @default 0.85
123
+ */
124
+ threshold?: number;
125
+ /**
126
+ * Maximum cache size
127
+ * @default 500
128
+ */
129
+ maxSize?: number;
130
+ /**
131
+ * API key for embedding provider (if needed)
132
+ */
133
+ apiKey?: string;
134
+ }
135
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;IAE7B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IAEzB;;OAEG;IACH,UAAU,EAAE,IAAI,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,MAAM,EAAE,YAAY,CAAC;IAErB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,EAAE,EAAE,UAAU,CAAC;IAEf;;OAEG;IACH,EAAE,EAAE,UAAU,CAAC;IAEf;;OAEG;IACH,EAAE,EAAE;QACF;;WAEG;QACH,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAEF;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IAEF;;OAEG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAErD;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types for nttp caching system
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}