@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.
- package/LICENSE +21 -0
- package/README.md +323 -0
- package/dist/BaseMatchStrategy-1E1SHaUt.d.ts +60 -0
- package/dist/SemanticCache-vysguwUQ.d.ts +65 -0
- package/dist/SimilarityEngine-Cwv_mF9a.d.ts +41 -0
- package/dist/analytics/index.d.ts +123 -0
- package/dist/analytics/index.js +275 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/cache.types-DMuyQseO.d.ts +99 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +3301 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/agentsea/index.d.ts +103 -0
- package/dist/integrations/agentsea/index.js +201 -0
- package/dist/integrations/agentsea/index.js.map +1 -0
- package/dist/integrations/gateway/index.d.ts +98 -0
- package/dist/integrations/gateway/index.js +205 -0
- package/dist/integrations/gateway/index.js.map +1 -0
- package/dist/invalidation/index.d.ts +113 -0
- package/dist/invalidation/index.js +360 -0
- package/dist/invalidation/index.js.map +1 -0
- package/dist/store.types-BQy5Yyz9.d.ts +111 -0
- package/dist/stores/index.d.ts +138 -0
- package/dist/stores/index.js +1147 -0
- package/dist/stores/index.js.map +1 -0
- package/dist/strategies/index.d.ts +36 -0
- package/dist/strategies/index.js +280 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/streaming/index.d.ts +206 -0
- package/dist/streaming/index.js +794 -0
- package/dist/streaming/index.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { S as SemanticCache } from '../../SemanticCache-vysguwUQ.js';
|
|
2
|
+
import { C as CacheMessage, W as WrapOptions, c as CacheStats } from '../../cache.types-DMuyQseO.js';
|
|
3
|
+
import 'eventemitter3';
|
|
4
|
+
import '../../store.types-BQy5Yyz9.js';
|
|
5
|
+
import '../../BaseMatchStrategy-1E1SHaUt.js';
|
|
6
|
+
import '../../SimilarityEngine-Cwv_mF9a.js';
|
|
7
|
+
import '../../analytics/index.js';
|
|
8
|
+
|
|
9
|
+
interface MiddlewareRequest {
|
|
10
|
+
model: string;
|
|
11
|
+
messages: CacheMessage[];
|
|
12
|
+
temperature?: number;
|
|
13
|
+
maxTokens?: number;
|
|
14
|
+
tools?: unknown[];
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface MiddlewareResponse {
|
|
18
|
+
content: string;
|
|
19
|
+
model: string;
|
|
20
|
+
finishReason?: string;
|
|
21
|
+
usage?: {
|
|
22
|
+
promptTokens: number;
|
|
23
|
+
completionTokens: number;
|
|
24
|
+
totalTokens: number;
|
|
25
|
+
};
|
|
26
|
+
toolCalls?: unknown[];
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
type MiddlewareNext = (request: MiddlewareRequest) => Promise<MiddlewareResponse>;
|
|
30
|
+
interface CacheMiddlewareConfig {
|
|
31
|
+
cache: SemanticCache;
|
|
32
|
+
skipModels?: string[];
|
|
33
|
+
skipToolRequests?: boolean;
|
|
34
|
+
defaultTTL?: number;
|
|
35
|
+
tagPrefix?: string;
|
|
36
|
+
getUserId?: (request: MiddlewareRequest) => string | undefined;
|
|
37
|
+
getAgentId?: (request: MiddlewareRequest) => string | undefined;
|
|
38
|
+
keyGenerator?: (request: MiddlewareRequest) => string;
|
|
39
|
+
}
|
|
40
|
+
declare class CacheMiddleware {
|
|
41
|
+
private config;
|
|
42
|
+
constructor(config: CacheMiddlewareConfig);
|
|
43
|
+
handle(request: MiddlewareRequest, next: MiddlewareNext): Promise<MiddlewareResponse>;
|
|
44
|
+
middleware(): (request: MiddlewareRequest, next: MiddlewareNext) => Promise<MiddlewareResponse>;
|
|
45
|
+
configure(config: Partial<CacheMiddlewareConfig>): void;
|
|
46
|
+
getCache(): SemanticCache;
|
|
47
|
+
private shouldSkip;
|
|
48
|
+
private buildOptions;
|
|
49
|
+
}
|
|
50
|
+
declare function createCacheMiddleware(config: CacheMiddlewareConfig): CacheMiddleware;
|
|
51
|
+
|
|
52
|
+
interface LLMProvider {
|
|
53
|
+
complete(request: CompletionRequest): Promise<CompletionResponse>;
|
|
54
|
+
stream?(request: CompletionRequest): AsyncGenerator<StreamChunk>;
|
|
55
|
+
}
|
|
56
|
+
interface CompletionRequest {
|
|
57
|
+
model: string;
|
|
58
|
+
messages: CacheMessage[];
|
|
59
|
+
temperature?: number;
|
|
60
|
+
maxTokens?: number;
|
|
61
|
+
tools?: unknown[];
|
|
62
|
+
stream?: boolean;
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
interface CompletionResponse {
|
|
66
|
+
content: string;
|
|
67
|
+
model: string;
|
|
68
|
+
finishReason: string;
|
|
69
|
+
usage?: {
|
|
70
|
+
promptTokens: number;
|
|
71
|
+
completionTokens: number;
|
|
72
|
+
totalTokens: number;
|
|
73
|
+
};
|
|
74
|
+
toolCalls?: unknown[];
|
|
75
|
+
}
|
|
76
|
+
interface StreamChunk {
|
|
77
|
+
content?: string;
|
|
78
|
+
finishReason?: string;
|
|
79
|
+
toolCall?: unknown;
|
|
80
|
+
}
|
|
81
|
+
interface CachedProviderConfig {
|
|
82
|
+
provider: LLMProvider;
|
|
83
|
+
cache: SemanticCache;
|
|
84
|
+
skipModels?: string[];
|
|
85
|
+
defaultOptions?: WrapOptions;
|
|
86
|
+
enableStreamingCache?: boolean;
|
|
87
|
+
}
|
|
88
|
+
declare class CachedProvider implements LLMProvider {
|
|
89
|
+
private provider;
|
|
90
|
+
private cache;
|
|
91
|
+
private config;
|
|
92
|
+
constructor(config: CachedProviderConfig);
|
|
93
|
+
complete(request: CompletionRequest): Promise<CompletionResponse>;
|
|
94
|
+
stream(request: CompletionRequest): AsyncGenerator<StreamChunk>;
|
|
95
|
+
getProvider(): LLMProvider;
|
|
96
|
+
getCache(): SemanticCache;
|
|
97
|
+
clearCache(): Promise<void>;
|
|
98
|
+
getCacheStats(): CacheStats;
|
|
99
|
+
}
|
|
100
|
+
declare function createCachedProvider(config: CachedProviderConfig): CachedProvider;
|
|
101
|
+
declare function withCache(provider: LLMProvider, cache: SemanticCache, options?: Partial<CachedProviderConfig>): CachedProvider;
|
|
102
|
+
|
|
103
|
+
export { CacheMiddleware, type CacheMiddlewareConfig, CachedProvider, type CachedProviderConfig, type CompletionRequest, type CompletionResponse, type LLMProvider, type MiddlewareNext, type MiddlewareRequest, type MiddlewareResponse, type StreamChunk, createCacheMiddleware, createCachedProvider, withCache };
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// src/integrations/agentsea/CacheMiddleware.ts
|
|
2
|
+
var CacheMiddleware = class {
|
|
3
|
+
config;
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Handle a request with caching
|
|
9
|
+
*/
|
|
10
|
+
async handle(request, next) {
|
|
11
|
+
if (this.shouldSkip(request)) {
|
|
12
|
+
return next(request);
|
|
13
|
+
}
|
|
14
|
+
const options = this.buildOptions(request);
|
|
15
|
+
return this.config.cache.wrap(
|
|
16
|
+
{
|
|
17
|
+
model: request.model,
|
|
18
|
+
messages: request.messages,
|
|
19
|
+
temperature: request.temperature,
|
|
20
|
+
maxTokens: request.maxTokens
|
|
21
|
+
},
|
|
22
|
+
async () => {
|
|
23
|
+
const response = await next(request);
|
|
24
|
+
return {
|
|
25
|
+
content: response.content,
|
|
26
|
+
model: response.model,
|
|
27
|
+
finishReason: response.finishReason ?? "stop",
|
|
28
|
+
usage: response.usage
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
options
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create express-style middleware function
|
|
36
|
+
*/
|
|
37
|
+
middleware() {
|
|
38
|
+
return (request, next) => this.handle(request, next);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Update configuration
|
|
42
|
+
*/
|
|
43
|
+
configure(config) {
|
|
44
|
+
this.config = { ...this.config, ...config };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the underlying cache instance
|
|
48
|
+
*/
|
|
49
|
+
getCache() {
|
|
50
|
+
return this.config.cache;
|
|
51
|
+
}
|
|
52
|
+
shouldSkip(request) {
|
|
53
|
+
if (this.config.skipModels?.includes(request.model)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (this.config.skipToolRequests && request.tools?.length) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
buildOptions(request) {
|
|
62
|
+
const options = {};
|
|
63
|
+
if (this.config.defaultTTL !== void 0) {
|
|
64
|
+
options.ttl = this.config.defaultTTL;
|
|
65
|
+
}
|
|
66
|
+
if (this.config.tagPrefix) {
|
|
67
|
+
options.tags = [`${this.config.tagPrefix}:${request.model}`];
|
|
68
|
+
}
|
|
69
|
+
if (this.config.getUserId) {
|
|
70
|
+
options.userId = this.config.getUserId(request);
|
|
71
|
+
}
|
|
72
|
+
if (this.config.getAgentId) {
|
|
73
|
+
options.agentId = this.config.getAgentId(request);
|
|
74
|
+
}
|
|
75
|
+
return options;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
function createCacheMiddleware(config) {
|
|
79
|
+
return new CacheMiddleware(config);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/integrations/agentsea/CachedProvider.ts
|
|
83
|
+
var CachedProvider = class {
|
|
84
|
+
provider;
|
|
85
|
+
cache;
|
|
86
|
+
config;
|
|
87
|
+
constructor(config) {
|
|
88
|
+
this.provider = config.provider;
|
|
89
|
+
this.cache = config.cache;
|
|
90
|
+
this.config = config;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generate a completion with caching
|
|
94
|
+
*/
|
|
95
|
+
async complete(request) {
|
|
96
|
+
if (this.config.skipModels?.includes(request.model)) {
|
|
97
|
+
return this.provider.complete(request);
|
|
98
|
+
}
|
|
99
|
+
const options = {
|
|
100
|
+
...this.config.defaultOptions
|
|
101
|
+
};
|
|
102
|
+
return this.cache.wrap(
|
|
103
|
+
{
|
|
104
|
+
model: request.model,
|
|
105
|
+
messages: request.messages,
|
|
106
|
+
temperature: request.temperature,
|
|
107
|
+
maxTokens: request.maxTokens
|
|
108
|
+
},
|
|
109
|
+
async () => {
|
|
110
|
+
const response = await this.provider.complete(request);
|
|
111
|
+
return {
|
|
112
|
+
content: response.content,
|
|
113
|
+
model: response.model,
|
|
114
|
+
finishReason: response.finishReason,
|
|
115
|
+
usage: response.usage
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
options
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Generate a streaming completion
|
|
123
|
+
*
|
|
124
|
+
* Note: Streaming responses are passed through without caching by default.
|
|
125
|
+
* Set enableStreamingCache to true for experimental streaming cache support.
|
|
126
|
+
*/
|
|
127
|
+
async *stream(request) {
|
|
128
|
+
if (!this.provider.stream) {
|
|
129
|
+
throw new Error("Provider does not support streaming");
|
|
130
|
+
}
|
|
131
|
+
if (!this.config.enableStreamingCache) {
|
|
132
|
+
yield* this.provider.stream(request);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const chunks = [];
|
|
136
|
+
let finishReason = "";
|
|
137
|
+
for await (const chunk of this.provider.stream(request)) {
|
|
138
|
+
if (chunk.content) {
|
|
139
|
+
chunks.push(chunk.content);
|
|
140
|
+
}
|
|
141
|
+
if (chunk.finishReason) {
|
|
142
|
+
finishReason = chunk.finishReason;
|
|
143
|
+
}
|
|
144
|
+
yield chunk;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
await this.cache.set(
|
|
148
|
+
{
|
|
149
|
+
model: request.model,
|
|
150
|
+
messages: request.messages,
|
|
151
|
+
temperature: request.temperature,
|
|
152
|
+
maxTokens: request.maxTokens
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
content: chunks.join(""),
|
|
156
|
+
model: request.model,
|
|
157
|
+
finishReason
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get the underlying provider
|
|
165
|
+
*/
|
|
166
|
+
getProvider() {
|
|
167
|
+
return this.provider;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get the cache instance
|
|
171
|
+
*/
|
|
172
|
+
getCache() {
|
|
173
|
+
return this.cache;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Clear cache entries for this provider
|
|
177
|
+
*/
|
|
178
|
+
async clearCache() {
|
|
179
|
+
await this.cache.clear();
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get cache statistics
|
|
183
|
+
*/
|
|
184
|
+
getCacheStats() {
|
|
185
|
+
return this.cache.getStats();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
function createCachedProvider(config) {
|
|
189
|
+
return new CachedProvider(config);
|
|
190
|
+
}
|
|
191
|
+
function withCache(provider, cache, options) {
|
|
192
|
+
return new CachedProvider({
|
|
193
|
+
provider,
|
|
194
|
+
cache,
|
|
195
|
+
...options
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { CacheMiddleware, CachedProvider, createCacheMiddleware, createCachedProvider, withCache };
|
|
200
|
+
//# sourceMappingURL=index.js.map
|
|
201
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/integrations/agentsea/CacheMiddleware.ts","../../../src/integrations/agentsea/CachedProvider.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * CacheMiddleware\n *\n * Middleware for integrating semantic cache with AgentSea agents.\n */\n\nimport type { SemanticCache } from '../../core/SemanticCache.js';\nimport type { CacheMessage, WrapOptions } from '../../types/index.js';\n\n/**\n * Middleware request\n */\nexport interface MiddlewareRequest {\n model: string;\n messages: CacheMessage[];\n temperature?: number;\n maxTokens?: number;\n tools?: unknown[];\n [key: string]: unknown;\n}\n\n/**\n * Middleware response\n */\nexport interface MiddlewareResponse {\n content: string;\n model: string;\n finishReason?: string;\n usage?: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n toolCalls?: unknown[];\n [key: string]: unknown;\n}\n\n/**\n * Next function in middleware chain\n */\nexport type MiddlewareNext = (\n request: MiddlewareRequest,\n) => Promise<MiddlewareResponse>;\n\n/**\n * Middleware configuration\n */\nexport interface CacheMiddlewareConfig {\n /** Cache instance */\n cache: SemanticCache;\n /** Skip cache for specific models */\n skipModels?: string[];\n /** Skip cache for tool-using requests */\n skipToolRequests?: boolean;\n /** Default TTL for cached entries */\n defaultTTL?: number;\n /** Tag prefix for cached entries */\n tagPrefix?: string;\n /** User ID extractor */\n getUserId?: (request: MiddlewareRequest) => string | undefined;\n /** Agent ID extractor */\n getAgentId?: (request: MiddlewareRequest) => string | undefined;\n /** Custom key generator */\n keyGenerator?: (request: MiddlewareRequest) => string;\n}\n\n/**\n * CacheMiddleware\n *\n * Middleware that adds semantic caching to LLM requests.\n *\n * @example\n * ```typescript\n * const middleware = new CacheMiddleware({\n * cache: semanticCache,\n * skipToolRequests: true\n * });\n *\n * // Use in agent pipeline\n * const response = await middleware.handle(request, next);\n * ```\n */\nexport class CacheMiddleware {\n private config: CacheMiddlewareConfig;\n\n constructor(config: CacheMiddlewareConfig) {\n this.config = config;\n }\n\n /**\n * Handle a request with caching\n */\n async handle(\n request: MiddlewareRequest,\n next: MiddlewareNext,\n ): Promise<MiddlewareResponse> {\n // Check if we should skip caching\n if (this.shouldSkip(request)) {\n return next(request);\n }\n\n const options = this.buildOptions(request);\n\n // Use cache.wrap to handle caching transparently\n return this.config.cache.wrap(\n {\n model: request.model,\n messages: request.messages,\n temperature: request.temperature,\n maxTokens: request.maxTokens,\n },\n async () => {\n const response = await next(request);\n return {\n content: response.content,\n model: response.model,\n finishReason: response.finishReason ?? 'stop',\n usage: response.usage,\n };\n },\n options,\n );\n }\n\n /**\n * Create express-style middleware function\n */\n middleware(): (\n request: MiddlewareRequest,\n next: MiddlewareNext,\n ) => Promise<MiddlewareResponse> {\n return (request, next) => this.handle(request, next);\n }\n\n /**\n * Update configuration\n */\n configure(config: Partial<CacheMiddlewareConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Get the underlying cache instance\n */\n getCache(): SemanticCache {\n return this.config.cache;\n }\n\n private shouldSkip(request: MiddlewareRequest): boolean {\n // Skip if model is in skip list\n if (this.config.skipModels?.includes(request.model)) {\n return true;\n }\n\n // Skip if request has tools and skipToolRequests is enabled\n if (this.config.skipToolRequests && request.tools?.length) {\n return true;\n }\n\n return false;\n }\n\n private buildOptions(request: MiddlewareRequest): WrapOptions {\n const options: WrapOptions = {};\n\n if (this.config.defaultTTL !== undefined) {\n options.ttl = this.config.defaultTTL;\n }\n\n if (this.config.tagPrefix) {\n options.tags = [`${this.config.tagPrefix}:${request.model}`];\n }\n\n if (this.config.getUserId) {\n options.userId = this.config.getUserId(request);\n }\n\n if (this.config.getAgentId) {\n options.agentId = this.config.getAgentId(request);\n }\n\n return options;\n }\n}\n\n/**\n * Create a CacheMiddleware instance\n */\nexport function createCacheMiddleware(\n config: CacheMiddlewareConfig,\n): CacheMiddleware {\n return new CacheMiddleware(config);\n}\n","/**\n * CachedProvider\n *\n * Wrapper for LLM providers that adds semantic caching.\n */\n\nimport type { SemanticCache } from '../../core/SemanticCache.js';\nimport type { CacheMessage, WrapOptions } from '../../types/index.js';\n\n/**\n * LLM Provider interface (compatible with AgentSea providers)\n */\nexport interface LLMProvider {\n /**\n * Generate a completion\n */\n complete(request: CompletionRequest): Promise<CompletionResponse>;\n\n /**\n * Generate a streaming completion\n */\n stream?(request: CompletionRequest): AsyncGenerator<StreamChunk>;\n}\n\n/**\n * Completion request\n */\nexport interface CompletionRequest {\n model: string;\n messages: CacheMessage[];\n temperature?: number;\n maxTokens?: number;\n tools?: unknown[];\n stream?: boolean;\n [key: string]: unknown;\n}\n\n/**\n * Completion response\n */\nexport interface CompletionResponse {\n content: string;\n model: string;\n finishReason: string;\n usage?: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n toolCalls?: unknown[];\n}\n\n/**\n * Stream chunk\n */\nexport interface StreamChunk {\n content?: string;\n finishReason?: string;\n toolCall?: unknown;\n}\n\n/**\n * Cached provider configuration\n */\nexport interface CachedProviderConfig {\n /** Underlying LLM provider */\n provider: LLMProvider;\n /** Semantic cache instance */\n cache: SemanticCache;\n /** Skip caching for certain models */\n skipModels?: string[];\n /** Default cache options */\n defaultOptions?: WrapOptions;\n /** Enable streaming cache */\n enableStreamingCache?: boolean;\n}\n\n/**\n * CachedProvider\n *\n * Wraps an LLM provider with semantic caching.\n *\n * @example\n * ```typescript\n * const cachedProvider = new CachedProvider({\n * provider: anthropicProvider,\n * cache: semanticCache\n * });\n *\n * // Uses cache transparently\n * const response = await cachedProvider.complete({\n * model: 'claude-3-sonnet',\n * messages: [{ role: 'user', content: 'Hello' }]\n * });\n * ```\n */\nexport class CachedProvider implements LLMProvider {\n private provider: LLMProvider;\n private cache: SemanticCache;\n private config: CachedProviderConfig;\n\n constructor(config: CachedProviderConfig) {\n this.provider = config.provider;\n this.cache = config.cache;\n this.config = config;\n }\n\n /**\n * Generate a completion with caching\n */\n async complete(request: CompletionRequest): Promise<CompletionResponse> {\n // Skip cache if model is in skip list\n if (this.config.skipModels?.includes(request.model)) {\n return this.provider.complete(request);\n }\n\n // Build cache options\n const options: WrapOptions = {\n ...this.config.defaultOptions,\n };\n\n // Use cache.wrap to handle caching\n return this.cache.wrap(\n {\n model: request.model,\n messages: request.messages,\n temperature: request.temperature,\n maxTokens: request.maxTokens,\n },\n async () => {\n const response = await this.provider.complete(request);\n return {\n content: response.content,\n model: response.model,\n finishReason: response.finishReason,\n usage: response.usage,\n };\n },\n options,\n );\n }\n\n /**\n * Generate a streaming completion\n *\n * Note: Streaming responses are passed through without caching by default.\n * Set enableStreamingCache to true for experimental streaming cache support.\n */\n async *stream(request: CompletionRequest): AsyncGenerator<StreamChunk> {\n // Check if provider supports streaming\n if (!this.provider.stream) {\n throw new Error('Provider does not support streaming');\n }\n\n // For now, pass through streaming without caching\n // Streaming cache support would require StreamCache integration\n if (!this.config.enableStreamingCache) {\n yield* this.provider.stream(request);\n return;\n }\n\n // Experimental: Collect stream for caching\n const chunks: string[] = [];\n let finishReason = '';\n\n for await (const chunk of this.provider.stream(request)) {\n if (chunk.content) {\n chunks.push(chunk.content);\n }\n if (chunk.finishReason) {\n finishReason = chunk.finishReason;\n }\n yield chunk;\n }\n\n // Cache the complete response after stream ends\n try {\n await this.cache.set(\n {\n model: request.model,\n messages: request.messages,\n temperature: request.temperature,\n maxTokens: request.maxTokens,\n },\n {\n content: chunks.join(''),\n model: request.model,\n finishReason,\n },\n );\n } catch {\n // Silently ignore cache errors during streaming\n }\n }\n\n /**\n * Get the underlying provider\n */\n getProvider(): LLMProvider {\n return this.provider;\n }\n\n /**\n * Get the cache instance\n */\n getCache(): SemanticCache {\n return this.cache;\n }\n\n /**\n * Clear cache entries for this provider\n */\n async clearCache(): Promise<void> {\n await this.cache.clear();\n }\n\n /**\n * Get cache statistics\n */\n getCacheStats() {\n return this.cache.getStats();\n }\n}\n\n/**\n * Create a CachedProvider instance\n */\nexport function createCachedProvider(\n config: CachedProviderConfig,\n): CachedProvider {\n return new CachedProvider(config);\n}\n\n/**\n * Helper to wrap any LLM provider with caching\n */\nexport function withCache(\n provider: LLMProvider,\n cache: SemanticCache,\n options?: Partial<CachedProviderConfig>,\n): CachedProvider {\n return new CachedProvider({\n provider,\n cache,\n ...options,\n });\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import EventEmitter from 'eventemitter3';
|
|
2
|
+
import { S as SemanticCache } from '../../SemanticCache-vysguwUQ.js';
|
|
3
|
+
import { C as CacheMessage, a as CacheLookupResult } from '../../cache.types-DMuyQseO.js';
|
|
4
|
+
import '../../store.types-BQy5Yyz9.js';
|
|
5
|
+
import '../../BaseMatchStrategy-1E1SHaUt.js';
|
|
6
|
+
import '../../SimilarityEngine-Cwv_mF9a.js';
|
|
7
|
+
import '../../analytics/index.js';
|
|
8
|
+
|
|
9
|
+
interface GatewayRequest {
|
|
10
|
+
id: string;
|
|
11
|
+
provider: string;
|
|
12
|
+
model: string;
|
|
13
|
+
messages: CacheMessage[];
|
|
14
|
+
temperature?: number;
|
|
15
|
+
maxTokens?: number;
|
|
16
|
+
stream?: boolean;
|
|
17
|
+
parameters?: Record<string, unknown>;
|
|
18
|
+
metadata?: {
|
|
19
|
+
userId?: string;
|
|
20
|
+
agentId?: string;
|
|
21
|
+
namespace?: string;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
interface GatewayResponse {
|
|
26
|
+
id: string;
|
|
27
|
+
provider: string;
|
|
28
|
+
model: string;
|
|
29
|
+
content: string;
|
|
30
|
+
finishReason: string;
|
|
31
|
+
usage?: {
|
|
32
|
+
promptTokens: number;
|
|
33
|
+
completionTokens: number;
|
|
34
|
+
totalTokens: number;
|
|
35
|
+
};
|
|
36
|
+
toolCalls?: unknown[];
|
|
37
|
+
metadata?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
interface GatewayCacheEvents {
|
|
40
|
+
'cache:hit': (request: GatewayRequest, result: CacheLookupResult) => void;
|
|
41
|
+
'cache:miss': (request: GatewayRequest) => void;
|
|
42
|
+
'cache:set': (request: GatewayRequest, response: GatewayResponse) => void;
|
|
43
|
+
'cache:error': (error: Error, request: GatewayRequest) => void;
|
|
44
|
+
}
|
|
45
|
+
interface GatewayCacheConfig {
|
|
46
|
+
cache: SemanticCache;
|
|
47
|
+
enabled?: boolean;
|
|
48
|
+
skipStreaming?: boolean;
|
|
49
|
+
skipProviders?: string[];
|
|
50
|
+
skipModels?: string[];
|
|
51
|
+
defaultTTL?: number;
|
|
52
|
+
namespace?: string;
|
|
53
|
+
keyGenerator?: (request: GatewayRequest) => string;
|
|
54
|
+
}
|
|
55
|
+
interface GatewayCacheStats {
|
|
56
|
+
totalRequests: number;
|
|
57
|
+
cacheHits: number;
|
|
58
|
+
cacheMisses: number;
|
|
59
|
+
hitRate: number;
|
|
60
|
+
avgLatencyMs: number;
|
|
61
|
+
byProvider: Record<string, {
|
|
62
|
+
hits: number;
|
|
63
|
+
misses: number;
|
|
64
|
+
}>;
|
|
65
|
+
byModel: Record<string, {
|
|
66
|
+
hits: number;
|
|
67
|
+
misses: number;
|
|
68
|
+
}>;
|
|
69
|
+
}
|
|
70
|
+
declare class GatewayCache extends EventEmitter<GatewayCacheEvents> {
|
|
71
|
+
private cache;
|
|
72
|
+
private config;
|
|
73
|
+
private stats;
|
|
74
|
+
private latencies;
|
|
75
|
+
constructor(config: GatewayCacheConfig);
|
|
76
|
+
get(request: GatewayRequest): Promise<{
|
|
77
|
+
hit: boolean;
|
|
78
|
+
response?: GatewayResponse;
|
|
79
|
+
similarity?: number;
|
|
80
|
+
}>;
|
|
81
|
+
set(request: GatewayRequest, response: GatewayResponse): Promise<void>;
|
|
82
|
+
invalidate(criteria: {
|
|
83
|
+
provider?: string;
|
|
84
|
+
model?: string;
|
|
85
|
+
namespace?: string;
|
|
86
|
+
olderThan?: number;
|
|
87
|
+
}): Promise<number>;
|
|
88
|
+
getStats(): GatewayCacheStats;
|
|
89
|
+
resetStats(): void;
|
|
90
|
+
isEnabled(): boolean;
|
|
91
|
+
setEnabled(enabled: boolean): void;
|
|
92
|
+
getCache(): SemanticCache;
|
|
93
|
+
private shouldCache;
|
|
94
|
+
private updateStats;
|
|
95
|
+
}
|
|
96
|
+
declare function createGatewayCache(config: GatewayCacheConfig): GatewayCache;
|
|
97
|
+
|
|
98
|
+
export { GatewayCache, type GatewayCacheConfig, type GatewayCacheEvents, type GatewayCacheStats, type GatewayRequest, type GatewayResponse, createGatewayCache };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import EventEmitter from 'eventemitter3';
|
|
2
|
+
|
|
3
|
+
// src/integrations/gateway/GatewayCache.ts
|
|
4
|
+
var GatewayCache = class extends EventEmitter {
|
|
5
|
+
cache;
|
|
6
|
+
config;
|
|
7
|
+
stats = {
|
|
8
|
+
totalRequests: 0,
|
|
9
|
+
cacheHits: 0,
|
|
10
|
+
cacheMisses: 0,
|
|
11
|
+
hitRate: 0,
|
|
12
|
+
avgLatencyMs: 0,
|
|
13
|
+
byProvider: {},
|
|
14
|
+
byModel: {}
|
|
15
|
+
};
|
|
16
|
+
latencies = [];
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super();
|
|
19
|
+
this.cache = config.cache;
|
|
20
|
+
this.config = {
|
|
21
|
+
enabled: true,
|
|
22
|
+
skipStreaming: true,
|
|
23
|
+
...config
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get cached response for a request
|
|
28
|
+
*/
|
|
29
|
+
async get(request) {
|
|
30
|
+
const startTime = performance.now();
|
|
31
|
+
this.stats.totalRequests++;
|
|
32
|
+
if (!this.shouldCache(request)) {
|
|
33
|
+
this.stats.cacheMisses++;
|
|
34
|
+
this.updateStats(request, false);
|
|
35
|
+
return { hit: false };
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const result = await this.cache.get({
|
|
39
|
+
model: request.model,
|
|
40
|
+
messages: request.messages,
|
|
41
|
+
temperature: request.temperature,
|
|
42
|
+
maxTokens: request.maxTokens
|
|
43
|
+
});
|
|
44
|
+
const latency = performance.now() - startTime;
|
|
45
|
+
this.latencies.push(latency);
|
|
46
|
+
if (result.hit && result.entry) {
|
|
47
|
+
this.stats.cacheHits++;
|
|
48
|
+
this.updateStats(request, true);
|
|
49
|
+
const response = {
|
|
50
|
+
id: request.id,
|
|
51
|
+
provider: request.provider,
|
|
52
|
+
model: result.entry.response.model,
|
|
53
|
+
content: result.entry.response.content,
|
|
54
|
+
finishReason: result.entry.response.finishReason,
|
|
55
|
+
usage: result.entry.response.usage,
|
|
56
|
+
metadata: {
|
|
57
|
+
cached: true,
|
|
58
|
+
cacheHit: result.source,
|
|
59
|
+
similarity: result.similarity,
|
|
60
|
+
cachedAt: result.entry.metadata.createdAt
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
this.emit("cache:hit", request, result);
|
|
64
|
+
return { hit: true, response, similarity: result.similarity };
|
|
65
|
+
}
|
|
66
|
+
this.stats.cacheMisses++;
|
|
67
|
+
this.updateStats(request, false);
|
|
68
|
+
this.emit("cache:miss", request);
|
|
69
|
+
return { hit: false };
|
|
70
|
+
} catch (error) {
|
|
71
|
+
this.emit("cache:error", error, request);
|
|
72
|
+
return { hit: false };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Cache a response
|
|
77
|
+
*/
|
|
78
|
+
async set(request, response) {
|
|
79
|
+
if (!this.shouldCache(request)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
await this.cache.set(
|
|
84
|
+
{
|
|
85
|
+
model: request.model,
|
|
86
|
+
messages: request.messages,
|
|
87
|
+
temperature: request.temperature,
|
|
88
|
+
maxTokens: request.maxTokens
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
content: response.content,
|
|
92
|
+
model: response.model,
|
|
93
|
+
finishReason: response.finishReason,
|
|
94
|
+
usage: response.usage
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
ttl: this.config.defaultTTL,
|
|
98
|
+
namespace: this.config.namespace ?? request.metadata?.namespace,
|
|
99
|
+
userId: request.metadata?.userId,
|
|
100
|
+
agentId: request.metadata?.agentId
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
this.emit("cache:set", request, response);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
this.emit("cache:error", error, request);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Invalidate cache entries matching criteria
|
|
110
|
+
*/
|
|
111
|
+
async invalidate(criteria) {
|
|
112
|
+
if (!criteria.provider && !criteria.model && !criteria.namespace) {
|
|
113
|
+
await this.cache.clear();
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
return 0;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get cache statistics
|
|
120
|
+
*/
|
|
121
|
+
getStats() {
|
|
122
|
+
return {
|
|
123
|
+
...this.stats,
|
|
124
|
+
hitRate: this.stats.totalRequests > 0 ? this.stats.cacheHits / this.stats.totalRequests * 100 : 0,
|
|
125
|
+
avgLatencyMs: this.latencies.length > 0 ? this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length : 0
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Reset statistics
|
|
130
|
+
*/
|
|
131
|
+
resetStats() {
|
|
132
|
+
this.stats = {
|
|
133
|
+
totalRequests: 0,
|
|
134
|
+
cacheHits: 0,
|
|
135
|
+
cacheMisses: 0,
|
|
136
|
+
hitRate: 0,
|
|
137
|
+
avgLatencyMs: 0,
|
|
138
|
+
byProvider: {},
|
|
139
|
+
byModel: {}
|
|
140
|
+
};
|
|
141
|
+
this.latencies = [];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Check if caching is enabled
|
|
145
|
+
*/
|
|
146
|
+
isEnabled() {
|
|
147
|
+
return this.config.enabled ?? true;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Enable or disable caching
|
|
151
|
+
*/
|
|
152
|
+
setEnabled(enabled) {
|
|
153
|
+
this.config.enabled = enabled;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get the underlying cache
|
|
157
|
+
*/
|
|
158
|
+
getCache() {
|
|
159
|
+
return this.cache;
|
|
160
|
+
}
|
|
161
|
+
shouldCache(request) {
|
|
162
|
+
if (!this.config.enabled) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
if (this.config.skipStreaming && request.stream) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (this.config.skipProviders?.includes(request.provider)) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
if (this.config.skipModels?.includes(request.model)) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
updateStats(request, hit) {
|
|
177
|
+
if (!this.stats.byProvider[request.provider]) {
|
|
178
|
+
this.stats.byProvider[request.provider] = { hits: 0, misses: 0 };
|
|
179
|
+
}
|
|
180
|
+
if (hit) {
|
|
181
|
+
this.stats.byProvider[request.provider].hits++;
|
|
182
|
+
} else {
|
|
183
|
+
this.stats.byProvider[request.provider].misses++;
|
|
184
|
+
}
|
|
185
|
+
if (!this.stats.byModel[request.model]) {
|
|
186
|
+
this.stats.byModel[request.model] = { hits: 0, misses: 0 };
|
|
187
|
+
}
|
|
188
|
+
if (hit) {
|
|
189
|
+
this.stats.byModel[request.model].hits++;
|
|
190
|
+
} else {
|
|
191
|
+
this.stats.byModel[request.model].misses++;
|
|
192
|
+
}
|
|
193
|
+
this.stats.hitRate = this.stats.totalRequests > 0 ? this.stats.cacheHits / this.stats.totalRequests * 100 : 0;
|
|
194
|
+
if (this.latencies.length > 0) {
|
|
195
|
+
this.stats.avgLatencyMs = this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
function createGatewayCache(config) {
|
|
200
|
+
return new GatewayCache(config);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export { GatewayCache, createGatewayCache };
|
|
204
|
+
//# sourceMappingURL=index.js.map
|
|
205
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/integrations/gateway/GatewayCache.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * GatewayCache\n *\n * Cache layer for LLM Gateway integration.\n */\n\nimport EventEmitter from 'eventemitter3';\nimport type { SemanticCache } from '../../core/SemanticCache.js';\nimport type { CacheMessage, CacheLookupResult } from '../../types/index.js';\n\n/**\n * Gateway request format\n */\nexport interface GatewayRequest {\n /** Request ID */\n id: string;\n /** Target provider (e.g., 'openai', 'anthropic') */\n provider: string;\n /** Model name */\n model: string;\n /** Messages */\n messages: CacheMessage[];\n /** Temperature */\n temperature?: number;\n /** Max tokens */\n maxTokens?: number;\n /** Stream mode */\n stream?: boolean;\n /** Additional parameters */\n parameters?: Record<string, unknown>;\n /** Request metadata */\n metadata?: {\n userId?: string;\n agentId?: string;\n namespace?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Gateway response format\n */\nexport interface GatewayResponse {\n /** Request ID */\n id: string;\n /** Provider used */\n provider: string;\n /** Model used */\n model: string;\n /** Response content */\n content: string;\n /** Finish reason */\n finishReason: string;\n /** Token usage */\n usage?: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n /** Tool calls */\n toolCalls?: unknown[];\n /** Response metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Gateway cache events\n */\nexport interface GatewayCacheEvents {\n 'cache:hit': (request: GatewayRequest, result: CacheLookupResult) => void;\n 'cache:miss': (request: GatewayRequest) => void;\n 'cache:set': (request: GatewayRequest, response: GatewayResponse) => void;\n 'cache:error': (error: Error, request: GatewayRequest) => void;\n}\n\n/**\n * Gateway cache configuration\n */\nexport interface GatewayCacheConfig {\n /** Semantic cache instance */\n cache: SemanticCache;\n /** Enable caching */\n enabled?: boolean;\n /** Skip caching for streaming requests */\n skipStreaming?: boolean;\n /** Skip caching for specific providers */\n skipProviders?: string[];\n /** Skip caching for specific models */\n skipModels?: string[];\n /** Default TTL in seconds */\n defaultTTL?: number;\n /** Namespace for cache isolation */\n namespace?: string;\n /** Custom key generator */\n keyGenerator?: (request: GatewayRequest) => string;\n}\n\n/**\n * Gateway cache statistics\n */\nexport interface GatewayCacheStats {\n totalRequests: number;\n cacheHits: number;\n cacheMisses: number;\n hitRate: number;\n avgLatencyMs: number;\n byProvider: Record<string, { hits: number; misses: number }>;\n byModel: Record<string, { hits: number; misses: number }>;\n}\n\n/**\n * GatewayCache\n *\n * Cache layer for LLM Gateway requests.\n *\n * @example\n * ```typescript\n * const gatewayCache = new GatewayCache({\n * cache: semanticCache,\n * skipStreaming: true\n * });\n *\n * // Check cache before routing\n * const cached = await gatewayCache.get(request);\n * if (cached.hit) {\n * return cached.response;\n * }\n *\n * // After getting response from provider\n * await gatewayCache.set(request, response);\n * ```\n */\nexport class GatewayCache extends EventEmitter<GatewayCacheEvents> {\n private cache: SemanticCache;\n private config: GatewayCacheConfig;\n private stats: GatewayCacheStats = {\n totalRequests: 0,\n cacheHits: 0,\n cacheMisses: 0,\n hitRate: 0,\n avgLatencyMs: 0,\n byProvider: {},\n byModel: {},\n };\n private latencies: number[] = [];\n\n constructor(config: GatewayCacheConfig) {\n super();\n this.cache = config.cache;\n this.config = {\n enabled: true,\n skipStreaming: true,\n ...config,\n };\n }\n\n /**\n * Get cached response for a request\n */\n async get(request: GatewayRequest): Promise<{\n hit: boolean;\n response?: GatewayResponse;\n similarity?: number;\n }> {\n const startTime = performance.now();\n this.stats.totalRequests++;\n\n // Check if caching is disabled or should be skipped\n if (!this.shouldCache(request)) {\n this.stats.cacheMisses++;\n this.updateStats(request, false);\n return { hit: false };\n }\n\n try {\n const result = await this.cache.get({\n model: request.model,\n messages: request.messages,\n temperature: request.temperature,\n maxTokens: request.maxTokens,\n });\n\n const latency = performance.now() - startTime;\n this.latencies.push(latency);\n\n if (result.hit && result.entry) {\n this.stats.cacheHits++;\n this.updateStats(request, true);\n\n const response: GatewayResponse = {\n id: request.id,\n provider: request.provider,\n model: result.entry.response.model,\n content: result.entry.response.content,\n finishReason: result.entry.response.finishReason,\n usage: result.entry.response.usage,\n metadata: {\n cached: true,\n cacheHit: result.source,\n similarity: result.similarity,\n cachedAt: result.entry.metadata.createdAt,\n },\n };\n\n this.emit('cache:hit', request, result);\n return { hit: true, response, similarity: result.similarity };\n }\n\n this.stats.cacheMisses++;\n this.updateStats(request, false);\n this.emit('cache:miss', request);\n return { hit: false };\n } catch (error) {\n this.emit('cache:error', error as Error, request);\n return { hit: false };\n }\n }\n\n /**\n * Cache a response\n */\n async set(request: GatewayRequest, response: GatewayResponse): Promise<void> {\n if (!this.shouldCache(request)) {\n return;\n }\n\n try {\n await this.cache.set(\n {\n model: request.model,\n messages: request.messages,\n temperature: request.temperature,\n maxTokens: request.maxTokens,\n },\n {\n content: response.content,\n model: response.model,\n finishReason: response.finishReason,\n usage: response.usage,\n },\n {\n ttl: this.config.defaultTTL,\n namespace: this.config.namespace ?? request.metadata?.namespace,\n userId: request.metadata?.userId,\n agentId: request.metadata?.agentId,\n },\n );\n\n this.emit('cache:set', request, response);\n } catch (error) {\n this.emit('cache:error', error as Error, request);\n }\n }\n\n /**\n * Invalidate cache entries matching criteria\n */\n async invalidate(criteria: {\n provider?: string;\n model?: string;\n namespace?: string;\n olderThan?: number;\n }): Promise<number> {\n // For now, just clear all if criteria is empty\n // A more sophisticated implementation would filter entries\n if (!criteria.provider && !criteria.model && !criteria.namespace) {\n await this.cache.clear();\n return 0;\n }\n\n // This would need store-level support for filtered deletion\n // For now, return 0 indicating no entries removed\n return 0;\n }\n\n /**\n * Get cache statistics\n */\n getStats(): GatewayCacheStats {\n return {\n ...this.stats,\n hitRate:\n this.stats.totalRequests > 0\n ? (this.stats.cacheHits / this.stats.totalRequests) * 100\n : 0,\n avgLatencyMs:\n this.latencies.length > 0\n ? this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length\n : 0,\n };\n }\n\n /**\n * Reset statistics\n */\n resetStats(): void {\n this.stats = {\n totalRequests: 0,\n cacheHits: 0,\n cacheMisses: 0,\n hitRate: 0,\n avgLatencyMs: 0,\n byProvider: {},\n byModel: {},\n };\n this.latencies = [];\n }\n\n /**\n * Check if caching is enabled\n */\n isEnabled(): boolean {\n return this.config.enabled ?? true;\n }\n\n /**\n * Enable or disable caching\n */\n setEnabled(enabled: boolean): void {\n this.config.enabled = enabled;\n }\n\n /**\n * Get the underlying cache\n */\n getCache(): SemanticCache {\n return this.cache;\n }\n\n private shouldCache(request: GatewayRequest): boolean {\n // Check if disabled\n if (!this.config.enabled) {\n return false;\n }\n\n // Skip streaming requests\n if (this.config.skipStreaming && request.stream) {\n return false;\n }\n\n // Skip specific providers\n if (this.config.skipProviders?.includes(request.provider)) {\n return false;\n }\n\n // Skip specific models\n if (this.config.skipModels?.includes(request.model)) {\n return false;\n }\n\n return true;\n }\n\n private updateStats(request: GatewayRequest, hit: boolean): void {\n // Update provider stats\n if (!this.stats.byProvider[request.provider]) {\n this.stats.byProvider[request.provider] = { hits: 0, misses: 0 };\n }\n if (hit) {\n this.stats.byProvider[request.provider].hits++;\n } else {\n this.stats.byProvider[request.provider].misses++;\n }\n\n // Update model stats\n if (!this.stats.byModel[request.model]) {\n this.stats.byModel[request.model] = { hits: 0, misses: 0 };\n }\n if (hit) {\n this.stats.byModel[request.model].hits++;\n } else {\n this.stats.byModel[request.model].misses++;\n }\n\n // Update hit rate\n this.stats.hitRate =\n this.stats.totalRequests > 0\n ? (this.stats.cacheHits / this.stats.totalRequests) * 100\n : 0;\n\n // Update average latency\n if (this.latencies.length > 0) {\n this.stats.avgLatencyMs =\n this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length;\n }\n }\n}\n\n/**\n * Create a GatewayCache instance\n */\nexport function createGatewayCache(config: GatewayCacheConfig): GatewayCache {\n return new GatewayCache(config);\n}\n"]}
|