@lov3kaizen/agentsea-cache 0.5.1

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.
@@ -0,0 +1,275 @@
1
+ import 'nanoid';
2
+
3
+ // src/core/utils.ts
4
+ function percentile(values, p) {
5
+ if (values.length === 0) return 0;
6
+ const sorted = [...values].sort((a, b) => a - b);
7
+ const index = Math.ceil(p / 100 * sorted.length) - 1;
8
+ return sorted[Math.max(0, index)];
9
+ }
10
+ function mean(values) {
11
+ if (values.length === 0) return 0;
12
+ return values.reduce((a, b) => a + b, 0) / values.length;
13
+ }
14
+
15
+ // src/analytics/CacheAnalytics.ts
16
+ var DEFAULT_MODEL_PRICING = {
17
+ "gpt-4o": { inputPer1K: 25e-4, outputPer1K: 0.01 },
18
+ "gpt-4o-mini": { inputPer1K: 15e-5, outputPer1K: 6e-4 },
19
+ "gpt-4-turbo": { inputPer1K: 0.01, outputPer1K: 0.03 },
20
+ "gpt-4": { inputPer1K: 0.03, outputPer1K: 0.06 },
21
+ "gpt-3.5-turbo": { inputPer1K: 5e-4, outputPer1K: 15e-4 },
22
+ "claude-3-opus": { inputPer1K: 0.015, outputPer1K: 0.075 },
23
+ "claude-sonnet-4-20250514": { inputPer1K: 3e-3, outputPer1K: 0.015 },
24
+ "claude-3-5-sonnet": { inputPer1K: 3e-3, outputPer1K: 0.015 },
25
+ "claude-3-haiku": { inputPer1K: 25e-5, outputPer1K: 125e-5 },
26
+ default: { inputPer1K: 5e-3, outputPer1K: 0.015 }
27
+ };
28
+ var DEFAULT_CONFIG = {
29
+ enabled: true,
30
+ sampleRate: 1,
31
+ retentionSeconds: 86400 * 7,
32
+ // 7 days
33
+ flushIntervalMs: 6e4,
34
+ // 1 minute
35
+ modelPricing: DEFAULT_MODEL_PRICING
36
+ };
37
+ var CacheAnalytics = class {
38
+ config;
39
+ hits = 0;
40
+ misses = 0;
41
+ exactHits = 0;
42
+ semanticHits = 0;
43
+ tokensSaved = 0;
44
+ inputTokensSaved = 0;
45
+ outputTokensSaved = 0;
46
+ latencies = [];
47
+ modelHits = /* @__PURE__ */ new Map();
48
+ namespaceHits = /* @__PURE__ */ new Map();
49
+ hitEvents = [];
50
+ missEvents = [];
51
+ setCount = 0;
52
+ constructor(config) {
53
+ this.config = { ...DEFAULT_CONFIG, ...config };
54
+ }
55
+ /**
56
+ * Record a cache hit
57
+ */
58
+ recordHit(entry, type, latencyMs) {
59
+ if (!this.config.enabled) return;
60
+ if (Math.random() > this.config.sampleRate) return;
61
+ this.hits++;
62
+ if (type === "exact") {
63
+ this.exactHits++;
64
+ } else {
65
+ this.semanticHits++;
66
+ }
67
+ this.latencies.push(latencyMs);
68
+ const usage = entry.response.usage;
69
+ this.tokensSaved += usage.totalTokens;
70
+ this.inputTokensSaved += usage.promptTokens;
71
+ this.outputTokensSaved += usage.completionTokens;
72
+ const modelCount = this.modelHits.get(entry.request.model) ?? 0;
73
+ this.modelHits.set(entry.request.model, modelCount + 1);
74
+ if (entry.metadata.namespace) {
75
+ const nsCount = this.namespaceHits.get(entry.metadata.namespace) ?? 0;
76
+ this.namespaceHits.set(entry.metadata.namespace, nsCount + 1);
77
+ }
78
+ this.hitEvents.push({
79
+ timestamp: Date.now(),
80
+ type,
81
+ model: entry.request.model,
82
+ namespace: entry.metadata.namespace,
83
+ similarity: entry.metadata.similarity,
84
+ latencyMs,
85
+ tokensSaved: usage.totalTokens
86
+ });
87
+ this.trimEvents();
88
+ }
89
+ /**
90
+ * Record a cache miss
91
+ */
92
+ recordMiss(latencyMs, reason = "not_found") {
93
+ if (!this.config.enabled) return;
94
+ if (Math.random() > this.config.sampleRate) return;
95
+ this.misses++;
96
+ this.latencies.push(latencyMs);
97
+ this.missEvents.push({
98
+ timestamp: Date.now(),
99
+ model: "unknown",
100
+ latencyMs,
101
+ reason
102
+ });
103
+ this.trimEvents();
104
+ }
105
+ /**
106
+ * Record a cache set operation
107
+ */
108
+ recordSet(_entry) {
109
+ if (!this.config.enabled) return;
110
+ this.setCount++;
111
+ }
112
+ /**
113
+ * Get analytics summary
114
+ */
115
+ getSummary() {
116
+ const total = this.hits + this.misses;
117
+ return {
118
+ totalHits: this.hits,
119
+ totalMisses: this.misses,
120
+ exactHits: this.exactHits,
121
+ semanticHits: this.semanticHits,
122
+ hitRate: total > 0 ? this.hits / total : 0,
123
+ avgLatencyMs: mean(this.latencies),
124
+ p50LatencyMs: percentile(this.latencies, 50),
125
+ p95LatencyMs: percentile(this.latencies, 95),
126
+ p99LatencyMs: percentile(this.latencies, 99),
127
+ totalTokensSaved: this.tokensSaved,
128
+ estimatedCostSavingsUSD: this.calculateCostSavings(),
129
+ topModels: this.getTopModels(5),
130
+ topNamespaces: this.getTopNamespaces(5),
131
+ hourlyStats: this.getHourlyStats()
132
+ };
133
+ }
134
+ /**
135
+ * Get cost savings report
136
+ */
137
+ getCostSavingsReport(periodLabel = "all-time") {
138
+ const total = this.hits + this.misses;
139
+ const costSaved = this.calculateCostSavings();
140
+ const avgCostPerRequest = costSaved / (this.hits || 1);
141
+ const estimatedCostWithoutCache = avgCostPerRequest * total;
142
+ return {
143
+ period: periodLabel,
144
+ totalRequests: total,
145
+ cachedRequests: this.hits,
146
+ hitRate: total > 0 ? this.hits / total : 0,
147
+ inputTokensSaved: this.inputTokensSaved,
148
+ outputTokensSaved: this.outputTokensSaved,
149
+ totalTokensSaved: this.tokensSaved,
150
+ estimatedCostWithoutCache,
151
+ actualCostWithCache: estimatedCostWithoutCache - costSaved,
152
+ costSaved,
153
+ reductionPercent: estimatedCostWithoutCache > 0 ? costSaved / estimatedCostWithoutCache * 100 : 0
154
+ };
155
+ }
156
+ /**
157
+ * Get performance metrics
158
+ */
159
+ getPerformanceMetrics() {
160
+ const total = this.hits + this.misses;
161
+ return {
162
+ avgLookupMs: mean(this.latencies),
163
+ avgEmbeddingMs: 0,
164
+ // Would need to track separately
165
+ avgStoreReadMs: mean(this.latencies),
166
+ avgStoreWriteMs: 0,
167
+ // Would need to track separately
168
+ p50LatencyMs: percentile(this.latencies, 50),
169
+ p95LatencyMs: percentile(this.latencies, 95),
170
+ p99LatencyMs: percentile(this.latencies, 99),
171
+ totalOperations: total + this.setCount,
172
+ failedOperations: 0,
173
+ // Would need to track separately
174
+ errorRate: 0
175
+ };
176
+ }
177
+ /**
178
+ * Reset all analytics
179
+ */
180
+ reset() {
181
+ this.hits = 0;
182
+ this.misses = 0;
183
+ this.exactHits = 0;
184
+ this.semanticHits = 0;
185
+ this.tokensSaved = 0;
186
+ this.inputTokensSaved = 0;
187
+ this.outputTokensSaved = 0;
188
+ this.latencies = [];
189
+ this.modelHits.clear();
190
+ this.namespaceHits.clear();
191
+ this.hitEvents = [];
192
+ this.missEvents = [];
193
+ this.setCount = 0;
194
+ }
195
+ /**
196
+ * Export analytics data
197
+ */
198
+ export(format = "json") {
199
+ const data = this.getSummary();
200
+ if (format === "csv") {
201
+ const headers = Object.keys(data).filter(
202
+ (k) => typeof data[k] !== "object"
203
+ );
204
+ const values = headers.map((h) => data[h]);
205
+ return `${headers.join(",")}
206
+ ${values.join(",")}`;
207
+ }
208
+ return JSON.stringify(data, null, 2);
209
+ }
210
+ calculateCostSavings() {
211
+ let savings = 0;
212
+ for (const [model, hits] of this.modelHits) {
213
+ const pricing = this.config.modelPricing[model] ?? this.config.modelPricing["default"];
214
+ const avgInputTokens = this.inputTokensSaved / (this.hits || 1);
215
+ const avgOutputTokens = this.outputTokensSaved / (this.hits || 1);
216
+ const inputCost = avgInputTokens / 1e3 * pricing.inputPer1K * hits;
217
+ const outputCost = avgOutputTokens / 1e3 * pricing.outputPer1K * hits;
218
+ savings += inputCost + outputCost;
219
+ }
220
+ if (savings === 0 && this.tokensSaved > 0) {
221
+ const defaultPricing = this.config.modelPricing["default"];
222
+ savings = this.inputTokensSaved / 1e3 * defaultPricing.inputPer1K + this.outputTokensSaved / 1e3 * defaultPricing.outputPer1K;
223
+ }
224
+ return savings;
225
+ }
226
+ getTopModels(n) {
227
+ return Array.from(this.modelHits.entries()).map(([model, hits]) => ({ model, hits })).sort((a, b) => b.hits - a.hits).slice(0, n);
228
+ }
229
+ getTopNamespaces(n) {
230
+ return Array.from(this.namespaceHits.entries()).map(([namespace, hits]) => ({ namespace, hits })).sort((a, b) => b.hits - a.hits).slice(0, n);
231
+ }
232
+ getHourlyStats() {
233
+ const hourlyData = /* @__PURE__ */ new Map();
234
+ for (const event of this.hitEvents) {
235
+ const hour = new Date(event.timestamp).getHours();
236
+ const data = hourlyData.get(hour) ?? {
237
+ hits: 0,
238
+ misses: 0,
239
+ latencies: []
240
+ };
241
+ data.hits++;
242
+ data.latencies.push(event.latencyMs);
243
+ hourlyData.set(hour, data);
244
+ }
245
+ for (const event of this.missEvents) {
246
+ const hour = new Date(event.timestamp).getHours();
247
+ const data = hourlyData.get(hour) ?? {
248
+ hits: 0,
249
+ misses: 0,
250
+ latencies: []
251
+ };
252
+ data.misses++;
253
+ data.latencies.push(event.latencyMs);
254
+ hourlyData.set(hour, data);
255
+ }
256
+ return Array.from(hourlyData.entries()).map(([hour, data]) => ({
257
+ hour,
258
+ hits: data.hits,
259
+ misses: data.misses,
260
+ avgLatencyMs: mean(data.latencies)
261
+ })).sort((a, b) => a.hour - b.hour);
262
+ }
263
+ trimEvents() {
264
+ const cutoff = Date.now() - this.config.retentionSeconds * 1e3;
265
+ this.hitEvents = this.hitEvents.filter((e) => e.timestamp > cutoff);
266
+ this.missEvents = this.missEvents.filter((e) => e.timestamp > cutoff);
267
+ }
268
+ };
269
+ function createCacheAnalytics(config) {
270
+ return new CacheAnalytics(config);
271
+ }
272
+
273
+ export { CacheAnalytics, createCacheAnalytics };
274
+ //# sourceMappingURL=index.js.map
275
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/utils.ts","../../src/analytics/CacheAnalytics.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Core Utilities\n *\n * Helper functions for the semantic cache.\n */\n\nimport { nanoid } from 'nanoid';\n\n/**\n * Generate a unique ID with optional prefix\n */\nexport function generateId(prefix?: string): string {\n const id = nanoid(16);\n return prefix ? `${prefix}_${id}` : id;\n}\n\n/**\n * Get current timestamp in milliseconds\n */\nexport function now(): number {\n return Date.now();\n}\n\n/**\n * Check if an entry has expired based on TTL\n */\nexport function isExpired(createdAt: number, ttlSeconds: number): boolean {\n if (ttlSeconds <= 0) return false;\n return now() > createdAt + ttlSeconds * 1000;\n}\n\n/**\n * Estimate the size of an object in bytes\n */\nexport function estimateSize(obj: unknown): number {\n const str = JSON.stringify(obj);\n // Rough estimate: 2 bytes per character for UTF-16\n return str.length * 2;\n}\n\n/**\n * Estimate size of a cache entry\n */\nexport function estimateEntrySize(entry: {\n embedding?: number[];\n request: { messages: Array<{ content: string }> };\n response: { content: string };\n}): number {\n // Vector: 4 bytes per float32\n const vectorSize = (entry.embedding?.length ?? 0) * 4;\n\n // Content: roughly 2 bytes per character\n const messageSize = entry.request.messages.reduce(\n (acc, m) => acc + (m.content?.length ?? 0) * 2,\n 0,\n );\n const responseSize = (entry.response.content?.length ?? 0) * 2;\n\n // Metadata overhead\n const overheadSize = 500;\n\n return vectorSize + messageSize + responseSize + overheadSize;\n}\n\n/**\n * Sleep for a specified duration\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n options: {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n backoffMultiplier?: number;\n } = {},\n): Promise<T> {\n const {\n maxAttempts = 3,\n initialDelayMs = 100,\n maxDelayMs = 5000,\n backoffMultiplier = 2,\n } = options;\n\n let lastError: Error | undefined;\n let delay = initialDelayMs;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n\n if (attempt < maxAttempts) {\n await sleep(delay);\n delay = Math.min(delay * backoffMultiplier, maxDelayMs);\n }\n }\n }\n\n throw lastError;\n}\n\n/**\n * Chunk an array into smaller arrays\n */\nexport function chunk<T>(array: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size));\n }\n return chunks;\n}\n\n/**\n * Deep clone an object\n */\nexport function deepClone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Calculate percentile from an array of numbers\n */\nexport function percentile(values: number[], p: number): number {\n if (values.length === 0) return 0;\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.ceil((p / 100) * sorted.length) - 1;\n return sorted[Math.max(0, index)];\n}\n\n/**\n * Calculate mean of an array of numbers\n */\nexport function mean(values: number[]): number {\n if (values.length === 0) return 0;\n return values.reduce((a, b) => a + b, 0) / values.length;\n}\n","/**\n * CacheAnalytics\n *\n * Analytics and metrics tracking for cache operations.\n */\n\nimport type {\n CacheEntry,\n AnalyticsData,\n CostSavingsReport,\n PerformanceMetrics,\n HitEvent,\n MissEvent,\n ModelPricing,\n AnalyticsConfig,\n} from '../types/index.js';\nimport { percentile, mean } from '../core/utils.js';\n\n/**\n * Default model pricing (per 1K tokens)\n */\nconst DEFAULT_MODEL_PRICING: Record<string, ModelPricing> = {\n 'gpt-4o': { inputPer1K: 0.0025, outputPer1K: 0.01 },\n 'gpt-4o-mini': { inputPer1K: 0.00015, outputPer1K: 0.0006 },\n 'gpt-4-turbo': { inputPer1K: 0.01, outputPer1K: 0.03 },\n 'gpt-4': { inputPer1K: 0.03, outputPer1K: 0.06 },\n 'gpt-3.5-turbo': { inputPer1K: 0.0005, outputPer1K: 0.0015 },\n 'claude-3-opus': { inputPer1K: 0.015, outputPer1K: 0.075 },\n 'claude-sonnet-4-20250514': { inputPer1K: 0.003, outputPer1K: 0.015 },\n 'claude-3-5-sonnet': { inputPer1K: 0.003, outputPer1K: 0.015 },\n 'claude-3-haiku': { inputPer1K: 0.00025, outputPer1K: 0.00125 },\n default: { inputPer1K: 0.005, outputPer1K: 0.015 },\n};\n\n/**\n * Default analytics configuration\n */\nconst DEFAULT_CONFIG: Required<AnalyticsConfig> = {\n enabled: true,\n sampleRate: 1.0,\n retentionSeconds: 86400 * 7, // 7 days\n flushIntervalMs: 60000, // 1 minute\n modelPricing: DEFAULT_MODEL_PRICING,\n};\n\n/**\n * CacheAnalytics\n *\n * Tracks cache performance metrics, hit rates, and cost savings.\n *\n * @example\n * ```typescript\n * const analytics = new CacheAnalytics({ enabled: true });\n *\n * // Record events\n * analytics.recordHit(entry, 'exact', 5.2);\n * analytics.recordMiss(12.3);\n *\n * // Get summary\n * const summary = analytics.getSummary();\n * console.log(`Hit rate: ${(summary.hitRate * 100).toFixed(1)}%`);\n * ```\n */\nexport class CacheAnalytics {\n private config: Required<AnalyticsConfig>;\n private hits = 0;\n private misses = 0;\n private exactHits = 0;\n private semanticHits = 0;\n private tokensSaved = 0;\n private inputTokensSaved = 0;\n private outputTokensSaved = 0;\n private latencies: number[] = [];\n private modelHits = new Map<string, number>();\n private namespaceHits = new Map<string, number>();\n private hitEvents: HitEvent[] = [];\n private missEvents: MissEvent[] = [];\n private setCount = 0;\n\n constructor(config?: Partial<AnalyticsConfig>) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Record a cache hit\n */\n recordHit(\n entry: CacheEntry,\n type: 'exact' | 'semantic',\n latencyMs: number,\n ): void {\n if (!this.config.enabled) return;\n if (Math.random() > this.config.sampleRate) return;\n\n this.hits++;\n if (type === 'exact') {\n this.exactHits++;\n } else {\n this.semanticHits++;\n }\n\n this.latencies.push(latencyMs);\n\n // Track tokens saved\n const usage = entry.response.usage;\n this.tokensSaved += usage.totalTokens;\n this.inputTokensSaved += usage.promptTokens;\n this.outputTokensSaved += usage.completionTokens;\n\n // Track by model\n const modelCount = this.modelHits.get(entry.request.model) ?? 0;\n this.modelHits.set(entry.request.model, modelCount + 1);\n\n // Track by namespace\n if (entry.metadata.namespace) {\n const nsCount = this.namespaceHits.get(entry.metadata.namespace) ?? 0;\n this.namespaceHits.set(entry.metadata.namespace, nsCount + 1);\n }\n\n // Record event\n this.hitEvents.push({\n timestamp: Date.now(),\n type,\n model: entry.request.model,\n namespace: entry.metadata.namespace,\n similarity: entry.metadata.similarity,\n latencyMs,\n tokensSaved: usage.totalTokens,\n });\n\n // Trim old events\n this.trimEvents();\n }\n\n /**\n * Record a cache miss\n */\n recordMiss(\n latencyMs: number,\n reason: MissEvent['reason'] = 'not_found',\n ): void {\n if (!this.config.enabled) return;\n if (Math.random() > this.config.sampleRate) return;\n\n this.misses++;\n this.latencies.push(latencyMs);\n\n // Record event\n this.missEvents.push({\n timestamp: Date.now(),\n model: 'unknown',\n latencyMs,\n reason,\n });\n\n // Trim old events\n this.trimEvents();\n }\n\n /**\n * Record a cache set operation\n */\n recordSet(_entry: CacheEntry): void {\n if (!this.config.enabled) return;\n this.setCount++;\n }\n\n /**\n * Get analytics summary\n */\n getSummary(): AnalyticsData {\n const total = this.hits + this.misses;\n\n return {\n totalHits: this.hits,\n totalMisses: this.misses,\n exactHits: this.exactHits,\n semanticHits: this.semanticHits,\n hitRate: total > 0 ? this.hits / total : 0,\n avgLatencyMs: mean(this.latencies),\n p50LatencyMs: percentile(this.latencies, 50),\n p95LatencyMs: percentile(this.latencies, 95),\n p99LatencyMs: percentile(this.latencies, 99),\n totalTokensSaved: this.tokensSaved,\n estimatedCostSavingsUSD: this.calculateCostSavings(),\n topModels: this.getTopModels(5),\n topNamespaces: this.getTopNamespaces(5),\n hourlyStats: this.getHourlyStats(),\n };\n }\n\n /**\n * Get cost savings report\n */\n getCostSavingsReport(periodLabel = 'all-time'): CostSavingsReport {\n const total = this.hits + this.misses;\n const costSaved = this.calculateCostSavings();\n\n // Estimate what cost would have been without cache\n const avgCostPerRequest = costSaved / (this.hits || 1);\n const estimatedCostWithoutCache = avgCostPerRequest * total;\n\n return {\n period: periodLabel,\n totalRequests: total,\n cachedRequests: this.hits,\n hitRate: total > 0 ? this.hits / total : 0,\n inputTokensSaved: this.inputTokensSaved,\n outputTokensSaved: this.outputTokensSaved,\n totalTokensSaved: this.tokensSaved,\n estimatedCostWithoutCache,\n actualCostWithCache: estimatedCostWithoutCache - costSaved,\n costSaved,\n reductionPercent:\n estimatedCostWithoutCache > 0\n ? (costSaved / estimatedCostWithoutCache) * 100\n : 0,\n };\n }\n\n /**\n * Get performance metrics\n */\n getPerformanceMetrics(): PerformanceMetrics {\n const total = this.hits + this.misses;\n\n return {\n avgLookupMs: mean(this.latencies),\n avgEmbeddingMs: 0, // Would need to track separately\n avgStoreReadMs: mean(this.latencies),\n avgStoreWriteMs: 0, // Would need to track separately\n p50LatencyMs: percentile(this.latencies, 50),\n p95LatencyMs: percentile(this.latencies, 95),\n p99LatencyMs: percentile(this.latencies, 99),\n totalOperations: total + this.setCount,\n failedOperations: 0, // Would need to track separately\n errorRate: 0,\n };\n }\n\n /**\n * Reset all analytics\n */\n reset(): void {\n this.hits = 0;\n this.misses = 0;\n this.exactHits = 0;\n this.semanticHits = 0;\n this.tokensSaved = 0;\n this.inputTokensSaved = 0;\n this.outputTokensSaved = 0;\n this.latencies = [];\n this.modelHits.clear();\n this.namespaceHits.clear();\n this.hitEvents = [];\n this.missEvents = [];\n this.setCount = 0;\n }\n\n /**\n * Export analytics data\n */\n export(format: 'json' | 'csv' = 'json'): string {\n const data = this.getSummary();\n\n if (format === 'csv') {\n const headers = Object.keys(data).filter(\n (k) => typeof data[k as keyof AnalyticsData] !== 'object',\n );\n const values = headers.map((h) => data[h as keyof AnalyticsData]);\n return `${headers.join(',')}\\n${values.join(',')}`;\n }\n\n return JSON.stringify(data, null, 2);\n }\n\n private calculateCostSavings(): number {\n let savings = 0;\n\n for (const [model, hits] of this.modelHits) {\n const pricing =\n this.config.modelPricing[model] ?? this.config.modelPricing['default'];\n\n // Estimate average tokens per request based on total\n const avgInputTokens = this.inputTokensSaved / (this.hits || 1);\n const avgOutputTokens = this.outputTokensSaved / (this.hits || 1);\n\n const inputCost = (avgInputTokens / 1000) * pricing.inputPer1K * hits;\n const outputCost = (avgOutputTokens / 1000) * pricing.outputPer1K * hits;\n\n savings += inputCost + outputCost;\n }\n\n // If no model-specific data, use default pricing\n if (savings === 0 && this.tokensSaved > 0) {\n const defaultPricing = this.config.modelPricing['default'];\n savings =\n (this.inputTokensSaved / 1000) * defaultPricing.inputPer1K +\n (this.outputTokensSaved / 1000) * defaultPricing.outputPer1K;\n }\n\n return savings;\n }\n\n private getTopModels(n: number): Array<{ model: string; hits: number }> {\n return Array.from(this.modelHits.entries())\n .map(([model, hits]) => ({ model, hits }))\n .sort((a, b) => b.hits - a.hits)\n .slice(0, n);\n }\n\n private getTopNamespaces(\n n: number,\n ): Array<{ namespace: string; hits: number }> {\n return Array.from(this.namespaceHits.entries())\n .map(([namespace, hits]) => ({ namespace, hits }))\n .sort((a, b) => b.hits - a.hits)\n .slice(0, n);\n }\n\n private getHourlyStats(): Array<{\n hour: number;\n hits: number;\n misses: number;\n avgLatencyMs: number;\n }> {\n const hourlyData = new Map<\n number,\n { hits: number; misses: number; latencies: number[] }\n >();\n\n // Process hit events\n for (const event of this.hitEvents) {\n const hour = new Date(event.timestamp).getHours();\n const data = hourlyData.get(hour) ?? {\n hits: 0,\n misses: 0,\n latencies: [],\n };\n data.hits++;\n data.latencies.push(event.latencyMs);\n hourlyData.set(hour, data);\n }\n\n // Process miss events\n for (const event of this.missEvents) {\n const hour = new Date(event.timestamp).getHours();\n const data = hourlyData.get(hour) ?? {\n hits: 0,\n misses: 0,\n latencies: [],\n };\n data.misses++;\n data.latencies.push(event.latencyMs);\n hourlyData.set(hour, data);\n }\n\n return Array.from(hourlyData.entries())\n .map(([hour, data]) => ({\n hour,\n hits: data.hits,\n misses: data.misses,\n avgLatencyMs: mean(data.latencies),\n }))\n .sort((a, b) => a.hour - b.hour);\n }\n\n private trimEvents(): void {\n const cutoff = Date.now() - this.config.retentionSeconds * 1000;\n this.hitEvents = this.hitEvents.filter((e) => e.timestamp > cutoff);\n this.missEvents = this.missEvents.filter((e) => e.timestamp > cutoff);\n }\n}\n\n/**\n * Create a CacheAnalytics instance\n */\nexport function createCacheAnalytics(\n config?: Partial<AnalyticsConfig>,\n): CacheAnalytics {\n return new CacheAnalytics(config);\n}\n"]}
@@ -0,0 +1,99 @@
1
+ type CacheBackendType = 'memory' | 'redis' | 'sqlite' | 'pinecone' | 'tiered';
2
+ interface CacheMessage {
3
+ role: 'system' | 'user' | 'assistant' | 'tool';
4
+ content: string;
5
+ name?: string;
6
+ toolCallId?: string;
7
+ }
8
+ interface CacheEntry {
9
+ id: string;
10
+ key: string;
11
+ embedding?: number[];
12
+ request: CacheRequest;
13
+ response: CacheResponse;
14
+ metadata: CacheEntryMetadata;
15
+ }
16
+ interface CacheRequest {
17
+ model: string;
18
+ messages: CacheMessage[];
19
+ temperature?: number;
20
+ maxTokens?: number;
21
+ tools?: unknown[];
22
+ systemPrompt?: string;
23
+ }
24
+ interface CacheResponse {
25
+ content: string;
26
+ model: string;
27
+ usage: TokenUsage;
28
+ finishReason: string;
29
+ toolCalls?: unknown[];
30
+ streamChunks?: unknown[];
31
+ }
32
+ interface TokenUsage {
33
+ promptTokens: number;
34
+ completionTokens: number;
35
+ totalTokens: number;
36
+ }
37
+ interface CacheEntryMetadata {
38
+ createdAt: number;
39
+ accessedAt: number;
40
+ accessCount: number;
41
+ ttl: number;
42
+ hitCount: number;
43
+ tier?: string;
44
+ similarity?: number;
45
+ tags?: string[];
46
+ namespace?: string;
47
+ userId?: string;
48
+ agentId?: string;
49
+ }
50
+ interface SemanticCacheConfig {
51
+ defaultTTL?: number;
52
+ similarityThreshold?: number;
53
+ maxEntries?: number;
54
+ maxSizeBytes?: number;
55
+ keyPrefix?: string;
56
+ matchStrategy?: 'exact' | 'semantic' | 'hybrid' | 'fuzzy';
57
+ analyticsEnabled?: boolean;
58
+ namespace?: string;
59
+ cacheKeyFields?: Array<'model' | 'messages' | 'temperature' | 'systemPrompt'>;
60
+ normalizeWhitespace?: boolean;
61
+ }
62
+ interface CacheLookupResult {
63
+ hit: boolean;
64
+ entry?: CacheEntry;
65
+ similarity?: number;
66
+ tier?: string;
67
+ latencyMs: number;
68
+ source: 'exact' | 'semantic' | 'miss';
69
+ }
70
+ interface CacheStats {
71
+ entries: number;
72
+ sizeBytes: number;
73
+ hits: number;
74
+ misses: number;
75
+ hitRate: number;
76
+ exactHits: number;
77
+ semanticHits: number;
78
+ avgSimilarity: number;
79
+ avgLatencyMs: number;
80
+ costSavingsUSD: number;
81
+ tokensSaved: number;
82
+ }
83
+ interface WrapOptions {
84
+ ttl?: number;
85
+ tags?: string[];
86
+ namespace?: string;
87
+ skipCache?: boolean;
88
+ forceRefresh?: boolean;
89
+ userId?: string;
90
+ agentId?: string;
91
+ }
92
+ interface CacheKeyOptions {
93
+ includeTemperature?: boolean;
94
+ includeTools?: boolean;
95
+ normalizeWhitespace?: boolean;
96
+ extractUserMessage?: boolean;
97
+ }
98
+
99
+ export type { CacheMessage as C, SemanticCacheConfig as S, TokenUsage as T, WrapOptions as W, CacheLookupResult as a, CacheEntry as b, CacheStats as c, CacheBackendType as d, CacheKeyOptions as e, CacheResponse as f, CacheEntryMetadata as g };
@@ -0,0 +1,47 @@
1
+ export { C as CacheRequest, b as CacheResponseInput, S as SemanticCache, a as SemanticCacheEvents, c as createSemanticCache } from './SemanticCache-vysguwUQ.js';
2
+ import { C as CacheMessage, e as CacheKeyOptions } from './cache.types-DMuyQseO.js';
3
+ export { d as CacheBackendType, b as CacheEntry, g as CacheEntryMetadata, a as CacheLookupResult, f as CacheResponse, c as CacheStats, S as SemanticCacheConfig, T as TokenUsage, W as WrapOptions } from './cache.types-DMuyQseO.js';
4
+ export { B as BaseCacheStore, M as MemoryStoreConfig, P as PineconeStoreConfig, R as RedisStoreConfig, b as SQLiteStoreConfig, a as StoreConfig, S as StoreHealth, f as StoreMetrics, d as StoreQueryOptions, e as StoreQueryResult, c as TierConfig, T as TieredStoreConfig, U as UpsertResult } from './store.types-BQy5Yyz9.js';
5
+ export { MemoryCacheStore, PineconeCacheStore, RedisCacheStore, SQLiteCacheStore, TieredCacheStore, createMemoryCacheStore, createPineconeCacheStore, createRedisCacheStore, createSQLiteCacheStore, createTieredCacheStore } from './stores/index.js';
6
+ export { B as BaseMatchStrategy, E as ExactMatchConfig, H as HybridMatchConfig, a as MatchOptions, b as MatchRequest, c as MatchResult, M as MatchStrategyType, S as SemanticMatchConfig } from './BaseMatchStrategy-1E1SHaUt.js';
7
+ export { ExactMatchStrategy, HybridMatchStrategy, SemanticMatchStrategy, createExactMatchStrategy, createHybridMatchStrategy, createSemanticMatchStrategy } from './strategies/index.js';
8
+ export { E as EmbeddingProvider, S as SimilarityEngine, b as SimilarityEngineConfig, a as SimilarityMetric, c as createSimilarityEngine } from './SimilarityEngine-Cwv_mF9a.js';
9
+ export { AnalyticsConfig, AnalyticsData, CacheAnalytics, CostSavingsReport, ModelPricing, PerformanceMetrics, createCacheAnalytics } from './analytics/index.js';
10
+ export { ChunkBuffer, ChunkBufferConfig, RecordedStream, StreamCache, StreamCacheConfig, StreamCacheEvents, StreamCacheLookupResult, StreamCacheStats, StreamChunk, StreamChunkType, StreamRecorder, StreamRecorderConfig, StreamReplayer, StreamReplayerConfig, createChunkBuffer, createStreamCache, createStreamRecorder, createStreamReplayer } from './streaming/index.js';
11
+ export { InvalidationEvent, InvalidationManager, InvalidationManagerConfig, InvalidationManagerEvents, InvalidationResult, InvalidationStats, InvalidationStrategyType, createInvalidationManager } from './invalidation/index.js';
12
+ import 'eventemitter3';
13
+
14
+ declare function generateCacheKey(model: string, messages: CacheMessage[], options?: CacheKeyOptions): string;
15
+ declare function normalizeWhitespace(text: string): string;
16
+ declare function extractUserMessage(messages: CacheMessage[] | Array<{
17
+ role: string;
18
+ content: string;
19
+ }>): string;
20
+ declare function extractSystemPrompt(messages: CacheMessage[]): string | undefined;
21
+ declare function generateSemanticKey(model: string, messages: CacheMessage[]): string;
22
+ declare function generateConversationFingerprint(messages: CacheMessage[]): string;
23
+
24
+ declare function generateId(prefix?: string): string;
25
+ declare function now(): number;
26
+ declare function isExpired(createdAt: number, ttlSeconds: number): boolean;
27
+ declare function estimateEntrySize(entry: {
28
+ embedding?: number[];
29
+ request: {
30
+ messages: Array<{
31
+ content: string;
32
+ }>;
33
+ };
34
+ response: {
35
+ content: string;
36
+ };
37
+ }): number;
38
+
39
+ declare function cosineSimilarity(a: number[], b: number[]): number;
40
+ declare function euclideanDistance(a: number[], b: number[]): number;
41
+ declare function dotProduct(a: number[], b: number[]): number;
42
+ declare function manhattanDistance(a: number[], b: number[]): number;
43
+ declare function distanceToSimilarity(distance: number): number;
44
+ declare function normalize(vector: number[]): number[];
45
+ declare function magnitude(vector: number[]): number;
46
+
47
+ export { CacheKeyOptions, CacheMessage, cosineSimilarity, distanceToSimilarity, dotProduct, estimateEntrySize, euclideanDistance, extractSystemPrompt, extractUserMessage, generateCacheKey, generateConversationFingerprint, generateId, generateSemanticKey, isExpired, magnitude, manhattanDistance, normalize, normalizeWhitespace, now };