adaptive-memory-multi-model-router 2.6.0 → 2.7.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.
@@ -1,140 +1,273 @@
1
1
  "use strict";
2
2
  /**
3
- * A3M Router - Semantic Cache
3
+ * A3M Router - Semantic Cache (Embedding-based)
4
4
  *
5
5
  * Stores previous query->response pairs and returns cached responses
6
- * for semantically similar queries using character n-gram Jaccard similarity.
6
+ * for semantically similar queries using cosine similarity on embeddings.
7
7
  *
8
- * No external embedding API needed. Trigram overlap catches paraphrases like:
9
- * "What is Python?" ≈ "Tell me about Python" ≈ "Explain Python"
10
- * "Write a sort fn" ≈ "Create a sorting fn" ≈ "How to sort an array"
8
+ * Supports embedders: nomic (via Ollama), openai, or local Ollama.
9
+ * Uses nomic-embed-text by default via local Ollama.
11
10
  */
12
11
  Object.defineProperty(exports, "__esModule", { value: true });
13
12
  exports.SemanticCache = void 0;
13
+ class NomicEmbedder {
14
+ url;
15
+ constructor(url = 'http://127.0.0.1:11434/api/embeddings') {
16
+ this.url = url;
17
+ }
18
+ async embed(text) {
19
+ const response = await fetch(this.url, {
20
+ method: 'POST',
21
+ headers: { 'Content-Type': 'application/json' },
22
+ body: JSON.stringify({
23
+ model: 'nomic-embed-text',
24
+ prompt: text,
25
+ }),
26
+ });
27
+ if (!response.ok) {
28
+ throw new Error(`Nomic embedder error: ${response.status} ${response.statusText}`);
29
+ }
30
+ const data = await response.json();
31
+ return data.embedding;
32
+ }
33
+ }
34
+ class OpenAIEmbedder {
35
+ apiKey;
36
+ url;
37
+ constructor(apiKey, url = 'https://api.openai.com/v1/embeddings') {
38
+ this.apiKey = apiKey;
39
+ this.url = url;
40
+ }
41
+ async embed(text) {
42
+ const response = await fetch(this.url, {
43
+ method: 'POST',
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ 'Authorization': `Bearer ${this.apiKey}`,
47
+ },
48
+ body: JSON.stringify({
49
+ model: 'text-embedding-3-small',
50
+ input: text,
51
+ }),
52
+ });
53
+ if (!response.ok) {
54
+ throw new Error(`OpenAI embedder error: ${response.status} ${response.statusText}`);
55
+ }
56
+ const data = await response.json();
57
+ return data.data[0]?.embedding ?? [];
58
+ }
59
+ }
60
+ class LocalOllamaEmbedder {
61
+ baseUrl;
62
+ model;
63
+ constructor(baseUrl = 'http://127.0.0.1:11434/api/embeddings', model = 'nomic-embed-text') {
64
+ this.baseUrl = baseUrl;
65
+ this.model = model;
66
+ }
67
+ async embed(text) {
68
+ const response = await fetch(this.baseUrl, {
69
+ method: 'POST',
70
+ headers: { 'Content-Type': 'application/json' },
71
+ body: JSON.stringify({
72
+ model: this.model,
73
+ prompt: text,
74
+ }),
75
+ });
76
+ if (!response.ok) {
77
+ throw new Error(`Local Ollama embedder error: ${response.status} ${response.statusText}`);
78
+ }
79
+ const data = await response.json();
80
+ return data.embedding;
81
+ }
82
+ }
14
83
  // ============================================================
15
- // N-gram utilities
84
+ // Utilities
16
85
  // ============================================================
17
86
  /**
18
- * Normalize text: lowercase, collapse whitespace, strip punctuation edges.
87
+ * Compute cosine similarity between two vectors.
88
+ */
89
+ function cosineSimilarity(a, b) {
90
+ if (a.length !== b.length)
91
+ return 0;
92
+ if (a.length === 0)
93
+ return 0;
94
+ let dotProduct = 0;
95
+ let normA = 0;
96
+ let normB = 0;
97
+ for (let i = 0; i < a.length; i++) {
98
+ dotProduct += a[i] * b[i];
99
+ normA += a[i] * a[i];
100
+ normB += b[i] * b[i];
101
+ }
102
+ const denominator = Math.sqrt(normA) * Math.sqrt(normB);
103
+ return denominator === 0 ? 0 : dotProduct / denominator;
104
+ }
105
+ /**
106
+ * Normalize text for hashing: lowercase, collapse whitespace.
19
107
  */
20
108
  function normalize(text) {
21
109
  return text
22
110
  .toLowerCase()
23
- .replace(/\s+/g, " ")
111
+ .replace(/\s+/g, ' ')
24
112
  .trim();
25
113
  }
26
114
  /**
27
- * Extract character trigrams from text.
28
- * Pads with spaces so short words still produce trigrams.
115
+ * Simple hash for cache key (deterministic, fast).
29
116
  */
30
- function extractTrigrams(text) {
31
- const normalized = " " + normalize(text) + " ";
32
- const trigrams = new Set();
33
- for (let i = 0; i <= normalized.length - 3; i++) {
34
- trigrams.add(normalized.substring(i, i + 3));
117
+ function hashKey(text) {
118
+ let hash = 0;
119
+ const normalized = normalize(text);
120
+ for (let i = 0; i < normalized.length; i++) {
121
+ const char = normalized.charCodeAt(i);
122
+ hash = ((hash << 5) - hash) + char;
123
+ hash = hash & hash; // Convert to 32-bit integer
35
124
  }
36
- return trigrams;
37
- }
38
- /**
39
- * Compute Jaccard similarity between two sets.
40
- * |A ∩ B| / |A ∪ B|
41
- */
42
- function jaccard(a, b) {
43
- if (a.size === 0 && b.size === 0)
44
- return 1.0;
45
- let intersection = 0;
46
- for (const item of a) {
47
- if (b.has(item))
48
- intersection++;
49
- }
50
- const union = a.size + b.size - intersection;
51
- return union === 0 ? 0 : intersection / union;
125
+ return hash.toString(36) + '_' + normalized.slice(0, 20);
52
126
  }
53
127
  // ============================================================
54
128
  // Semantic Cache
55
129
  // ============================================================
56
130
  class SemanticCache {
57
- entries = [];
58
- maxSize;
131
+ entries = new Map();
132
+ accessOrder = []; // track LRU order
133
+ embedder;
59
134
  similarityThreshold;
60
- ttl;
135
+ ttlMs;
136
+ maxEntries;
61
137
  hits = 0;
62
138
  misses = 0;
63
- constructor(options) {
64
- this.maxSize = options?.maxSize ?? 1000;
65
- this.similarityThreshold = options?.similarityThreshold ?? 0.92;
66
- this.ttl = options?.ttl ?? 3600000; // 1 hour
139
+ constructor(config) {
140
+ this.similarityThreshold = config.similarityThreshold;
141
+ this.ttlMs = (config.ttlSeconds || 3600) * 1000;
142
+ this.maxEntries = config.maxEntries || 1000;
143
+ // Initialize embedder based on config
144
+ switch (config.embedder) {
145
+ case 'openai':
146
+ if (!config.embedderApiKey) {
147
+ throw new Error('OpenAI embedder requires apiKey in config.embedderApiKey');
148
+ }
149
+ this.embedder = new OpenAIEmbedder(config.embedderApiKey, config.embedderUrl);
150
+ break;
151
+ case 'local':
152
+ this.embedder = new LocalOllamaEmbedder(config.embedderUrl || 'http://127.0.0.1:11434/api/embeddings', 'nomic-embed-text');
153
+ break;
154
+ case 'nomic':
155
+ default:
156
+ this.embedder = new NomicEmbedder(config.embedderUrl || 'http://127.0.0.1:11434/api/embeddings');
157
+ break;
158
+ }
67
159
  }
68
160
  /**
69
161
  * Get cached response for a semantically similar query.
70
- * Returns the best match above the similarity threshold, or null.
162
+ * Returns the best match above the similarity threshold, or { hit: false }.
71
163
  */
72
164
  async get(query) {
73
165
  const now = Date.now();
74
- const queryTrigrams = extractTrigrams(query);
166
+ // Generate embedding for the query
167
+ let queryEmbedding;
168
+ try {
169
+ queryEmbedding = await this.embedder.embed(query);
170
+ }
171
+ catch (error) {
172
+ console.warn('SemanticCache: Failed to generate embedding for query:', error);
173
+ this.misses++;
174
+ return { hit: false };
175
+ }
75
176
  let bestEntry = null;
76
- let bestScore = 0;
77
- for (const entry of this.entries) {
78
- // Skip expired
79
- if (now > entry.expiresAt)
177
+ let bestSimilarity = 0;
178
+ for (const entry of this.entries.values()) {
179
+ // Skip expired entries
180
+ if (now > entry.createdAt + entry.ttl)
80
181
  continue;
81
- const score = jaccard(queryTrigrams, entry.trigrams);
82
- if (score > bestScore) {
83
- bestScore = score;
182
+ const similarity = cosineSimilarity(queryEmbedding, entry.embedding);
183
+ if (similarity > bestSimilarity) {
184
+ bestSimilarity = similarity;
84
185
  bestEntry = entry;
85
186
  }
86
187
  }
87
- if (bestEntry && bestScore >= this.similarityThreshold) {
188
+ if (bestEntry && bestSimilarity >= this.similarityThreshold) {
88
189
  this.hits++;
89
190
  bestEntry.hitCount++;
191
+ bestEntry.lastAccessedAt = now;
192
+ this.updateAccessOrder(bestEntry.key);
90
193
  return {
91
- query: bestEntry.query,
194
+ hit: true,
92
195
  response: bestEntry.response,
93
- metadata: bestEntry.metadata,
94
- cachedAt: bestEntry.cachedAt,
95
- hitCount: bestEntry.hitCount,
196
+ provider: bestEntry.provider,
197
+ model: bestEntry.model,
198
+ cost: bestEntry.cost,
199
+ similarity: bestSimilarity,
96
200
  };
97
201
  }
98
202
  this.misses++;
99
- return null;
203
+ return { hit: false };
100
204
  }
101
205
  /**
102
206
  * Store a query->response pair in the cache.
103
207
  */
104
208
  async set(query, response, metadata) {
105
209
  const now = Date.now();
106
- // Evict expired entries first
210
+ const key = hashKey(query);
211
+ // Generate embedding
212
+ let embedding;
213
+ try {
214
+ embedding = await this.embedder.embed(query);
215
+ }
216
+ catch (error) {
217
+ console.warn('SemanticCache: Failed to generate embedding for set:', error);
218
+ return;
219
+ }
220
+ // Evict expired entries
107
221
  this.evictExpired();
108
- // Evict oldest if at capacity
109
- if (this.entries.length >= this.maxSize) {
110
- this.evictOldest();
222
+ // Evict oldest if at capacity (LRU)
223
+ if (this.entries.size >= this.maxEntries) {
224
+ this.evictLRU();
111
225
  }
112
- // Check if an exact-match entry already exists and update it
113
- const normalized = normalize(query);
114
- const existing = this.entries.find((e) => normalize(e.query) === normalized && now <= e.expiresAt);
115
- if (existing) {
226
+ // Check if entry already exists and update it
227
+ if (this.entries.has(key)) {
228
+ const existing = this.entries.get(key);
116
229
  existing.response = response;
117
- existing.metadata = metadata;
118
- existing.cachedAt = now;
119
- existing.expiresAt = now + this.ttl;
120
- existing.trigrams = extractTrigrams(query);
230
+ existing.embedding = embedding;
231
+ existing.provider = metadata.provider;
232
+ existing.model = metadata.model;
233
+ existing.cost = metadata.cost;
234
+ existing.createdAt = now;
235
+ existing.ttl = (metadata.ttl !== undefined ? metadata.ttl : this.ttlMs / 1000) * 1000;
236
+ existing.lastAccessedAt = now;
237
+ existing.hitCount = existing.hitCount; // preserve hit count
121
238
  return;
122
239
  }
123
- this.entries.push({
124
- query,
240
+ const entry = {
241
+ key,
242
+ embedding,
125
243
  response,
126
- metadata,
127
- cachedAt: now,
128
- expiresAt: now + this.ttl,
244
+ provider: metadata.provider,
245
+ model: metadata.model,
246
+ cost: metadata.cost,
247
+ createdAt: now,
248
+ ttl: (metadata.ttl !== undefined ? metadata.ttl : this.ttlMs / 1000) * 1000,
129
249
  hitCount: 0,
130
- trigrams: extractTrigrams(query),
131
- });
250
+ lastAccessedAt: now,
251
+ };
252
+ this.entries.set(key, entry);
253
+ this.accessOrder.push(key);
254
+ }
255
+ /**
256
+ * Delete a specific query from the cache.
257
+ */
258
+ async delete(query) {
259
+ const key = hashKey(query);
260
+ if (this.entries.has(key)) {
261
+ this.entries.delete(key);
262
+ this.accessOrder = this.accessOrder.filter(k => k !== key);
263
+ }
132
264
  }
133
265
  /**
134
266
  * Clear all cache entries.
135
267
  */
136
268
  clear() {
137
- this.entries = [];
269
+ this.entries.clear();
270
+ this.accessOrder = [];
138
271
  }
139
272
  /**
140
273
  * Get cache statistics.
@@ -142,35 +275,46 @@ class SemanticCache {
142
275
  getStats() {
143
276
  const total = this.hits + this.misses;
144
277
  return {
278
+ size: this.entries.size,
145
279
  hits: this.hits,
146
280
  misses: this.misses,
147
281
  hitRate: total > 0 ? this.hits / total : 0,
148
- size: this.entries.length,
149
282
  };
150
283
  }
284
+ /**
285
+ * Update access order for LRU tracking.
286
+ */
287
+ updateAccessOrder(key) {
288
+ this.accessOrder = this.accessOrder.filter(k => k !== key);
289
+ this.accessOrder.push(key);
290
+ }
151
291
  /**
152
292
  * Purge expired entries.
153
293
  */
154
294
  evictExpired() {
155
295
  const now = Date.now();
156
- this.entries = this.entries.filter((e) => now <= e.expiresAt);
296
+ for (const [key, entry] of this.entries.entries()) {
297
+ if (now > entry.createdAt + entry.ttl) {
298
+ this.entries.delete(key);
299
+ this.accessOrder = this.accessOrder.filter(k => k !== key);
300
+ }
301
+ }
157
302
  }
158
303
  /**
159
- * Evict the oldest (by cachedAt) entry.
304
+ * Evict the least recently used entry.
160
305
  */
161
- evictOldest() {
162
- if (this.entries.length === 0)
306
+ evictLRU() {
307
+ if (this.accessOrder.length === 0)
163
308
  return;
164
- let oldestIdx = 0;
165
- let oldestTime = Infinity;
166
- for (let i = 0; i < this.entries.length; i++) {
167
- if (this.entries[i].cachedAt < oldestTime) {
168
- oldestTime = this.entries[i].cachedAt;
169
- oldestIdx = i;
170
- }
309
+ const lruKey = this.accessOrder.shift();
310
+ if (lruKey && this.entries.has(lruKey)) {
311
+ this.entries.delete(lruKey);
171
312
  }
172
- this.entries.splice(oldestIdx, 1);
173
313
  }
174
314
  }
175
315
  exports.SemanticCache = SemanticCache;
316
+ // ============================================================
317
+ // Exports
318
+ // ============================================================
319
+ exports.default = SemanticCache;
176
320
  //# sourceMappingURL=semanticCache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"semanticCache.js","sourceRoot":"","sources":["../../src/cache/semanticCache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"semanticCache.js","sourceRoot":"","sources":["../../src/cache/semanticCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * A3M Router - Budget Enforcer
3
+ *
4
+ * Hard budget enforcement for API key spend management:
5
+ * - Track spend per API key with monthly reset
6
+ * - Check budget before each request
7
+ * - Emit alerts at configurable thresholds (50%, 80%, 100%)
8
+ * - Support hard cap (reject requests) or soft cap (warn only)
9
+ * - In-memory storage (Redis backup can be added later)
10
+ */
11
+ import { EventEmitter } from 'events';
12
+ export interface BudgetConfig {
13
+ apiKey: string;
14
+ monthlyLimit: number;
15
+ alertThresholds?: number[];
16
+ hardCap?: boolean;
17
+ }
18
+ export interface SpendRecord {
19
+ apiKey: string;
20
+ spent: number;
21
+ budget: number;
22
+ remaining: number;
23
+ resetDate: Date;
24
+ alertEmitted: Set<number>;
25
+ }
26
+ export interface BudgetCheckResult {
27
+ allowed: boolean;
28
+ reason?: string;
29
+ remaining: number;
30
+ }
31
+ export declare class BudgetEnforcer extends EventEmitter {
32
+ private budgets;
33
+ private spend;
34
+ private static readonly DEFAULT_THRESHOLDS;
35
+ constructor();
36
+ /**
37
+ * Set budget for an API key
38
+ */
39
+ setBudget(apiKey: string, monthlyLimit: number, options?: {
40
+ alertThresholds?: number[];
41
+ hardCap?: boolean;
42
+ }): void;
43
+ /**
44
+ * Get current budget config for an API key
45
+ */
46
+ getBudgetConfig(apiKey: string): BudgetConfig | undefined;
47
+ /**
48
+ * Remove budget config (stops tracking)
49
+ */
50
+ removeBudget(apiKey: string): void;
51
+ /**
52
+ * Check if a request is allowed within budget
53
+ * @param apiKey - The API key making the request
54
+ * @param additionalCost - The cost of the request in cents
55
+ * @returns BudgetCheckResult with allowed status and remaining budget
56
+ */
57
+ checkBudget(apiKey: string, additionalCost: number): BudgetCheckResult;
58
+ /**
59
+ * Record spend for an API key
60
+ * @param apiKey - The API key that incurred the cost
61
+ * @param cost - The cost in cents
62
+ */
63
+ recordSpend(apiKey: string, cost: number): void;
64
+ /**
65
+ * Get current spend record for an API key
66
+ */
67
+ getSpend(apiKey: string): SpendRecord | undefined;
68
+ /**
69
+ * Get all spend records
70
+ */
71
+ getAllSpend(): SpendRecord[];
72
+ /**
73
+ * Reset budget for an API key (manual reset)
74
+ */
75
+ resetBudget(apiKey: string): void;
76
+ /**
77
+ * Reset all budgets
78
+ */
79
+ resetAll(): void;
80
+ /**
81
+ * Update monthly limit for an API key
82
+ */
83
+ updateLimit(apiKey: string, monthlyLimit: number): void;
84
+ /**
85
+ * Check if reset is needed and perform it
86
+ */
87
+ private checkAndReset;
88
+ /**
89
+ * Check if monthly reset is due
90
+ */
91
+ private isResetDue;
92
+ /**
93
+ * Get next monthly reset date
94
+ */
95
+ private getNextResetDate;
96
+ /**
97
+ * Get days until next reset
98
+ */
99
+ getDaysUntilReset(apiKey: string): number | undefined;
100
+ }
101
+ export declare function createBudgetEnforcer(): BudgetEnforcer;
102
+ export declare class BudgetExceededError extends Error {
103
+ readonly apiKey: string;
104
+ readonly spent: number;
105
+ readonly budget: number;
106
+ readonly remaining: number;
107
+ constructor(apiKey: string, spent: number, budget: number);
108
+ }