chat-agent-toolkit 1.2.33 → 1.2.35
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/dist/research-agent.cjs.js.map +1 -1
- package/dist/research-agent.es.js.map +1 -1
- package/package.json +1 -1
- package/src/config/config-manager.ts +295 -295
- package/src/config/config-types.ts +65 -65
- package/src/config/environment-variables.ts +16 -16
- package/src/config/index.ts +26 -26
- package/src/config/language-models-database.ts +1434 -1434
- package/src/config/mcp-server-registry.ts +24 -24
- package/src/config/model-registry.ts +271 -271
- package/src/config/model-tester.ts +211 -211
- package/src/config/model-utils.ts +193 -193
- package/src/config/provider-ui-config.ts +196 -196
- package/src/connectors/open-connector.json +130 -130
- package/src/index.ts +26 -26
- package/src/memory/ARCHITECTURE.md +302 -302
- package/src/memory/README.md +224 -224
- package/src/memory/agent-memory-manager.ts +416 -416
- package/src/memory/example.ts +343 -343
- package/src/memory/index.ts +47 -47
- package/src/memory/mastra-integration.ts +604 -604
- package/src/memory/storage/drizzle-storage.ts +236 -236
- package/src/memory/storage/in-memory-storage.ts +551 -551
- package/src/memory/storage/storage-interface.ts +68 -68
- package/src/memory/types.ts +125 -125
- package/src/models/types.ts +4 -4
- package/src/tools/index.ts +13 -13
- package/src/tools/open-connector-mastra.ts +270 -270
- package/src/tools/open-connector-mcp.ts +170 -170
- package/src/tools/qwksearch-api-tools.ts +326 -326
- package/src/tools/search/doc-utils.ts +139 -139
- package/src/tools/search/document.ts +47 -47
- package/src/tools/search/index.ts +14 -14
- package/src/tools/search/link-summarizer.ts +112 -112
- package/src/tools/search/meta-search-types.ts +62 -62
- package/src/tools/search/metaSearchAgent.ts +465 -465
- package/src/tools/search/search-handlers.ts +97 -97
- package/src/tools/search/suggestionGeneratorAgent.ts +56 -56
- package/src/types.d.ts +137 -137
- package/src/utils/index.ts +2 -2
- package/src/utils/markdown-to-html.ts +53 -53
- package/src/utils/outputParser.ts +73 -73
|
@@ -1,416 +1,416 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* Memory Agent
|
|
4
|
-
*
|
|
5
|
-
* Enhanced Memory Agent with:
|
|
6
|
-
* - Rate limiting
|
|
7
|
-
* - Multiple LLM provider support
|
|
8
|
-
* - Health monitoring
|
|
9
|
-
* - Conversation management
|
|
10
|
-
* - Memory analytics
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { SimpleMemory } from "./storage/in-memory-storage";
|
|
14
|
-
import type { IMemoryStorage } from "./storage/storage-interface";
|
|
15
|
-
import type { MemoryType, MemorySearchOptions } from "./types";
|
|
16
|
-
import { MEMORY_CONFIG, MEMORY_TYPES } from "./types";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* LLM provider interface
|
|
20
|
-
*/
|
|
21
|
-
interface LLMProvider {
|
|
22
|
-
invoke: (prompt: string) => Promise<{ content: string; tokensUsed: number }>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Chat options
|
|
27
|
-
*/
|
|
28
|
-
interface ChatOptions {
|
|
29
|
-
provider?: string;
|
|
30
|
-
apiKey?: string;
|
|
31
|
-
model?: string;
|
|
32
|
-
temperature?: number;
|
|
33
|
-
systemPrompt?: string;
|
|
34
|
-
includeHistory?: boolean;
|
|
35
|
-
maxMemories?: number;
|
|
36
|
-
minImportance?: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Chat response
|
|
41
|
-
*/
|
|
42
|
-
interface ChatResponse {
|
|
43
|
-
content?: string;
|
|
44
|
-
memoryContext?: string;
|
|
45
|
-
success: boolean;
|
|
46
|
-
tokensUsed?: number;
|
|
47
|
-
responseTime?: number;
|
|
48
|
-
sessionId?: string;
|
|
49
|
-
timestamp: string;
|
|
50
|
-
error?: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Agent analytics
|
|
55
|
-
*/
|
|
56
|
-
interface AgentAnalytics {
|
|
57
|
-
totalMessages: number;
|
|
58
|
-
totalTokens: number;
|
|
59
|
-
averageResponseTime: number;
|
|
60
|
-
errorCount: number;
|
|
61
|
-
sessionStartTime: number;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Rate limit configuration
|
|
66
|
-
*/
|
|
67
|
-
interface RateLimitConfig {
|
|
68
|
-
requests: number;
|
|
69
|
-
windowMs: number;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Agent options
|
|
74
|
-
*/
|
|
75
|
-
export interface MemoryAgentOptions {
|
|
76
|
-
memoryOptions?: any;
|
|
77
|
-
defaultProvider?: string;
|
|
78
|
-
defaultApiKey?: string;
|
|
79
|
-
defaultModel?: string;
|
|
80
|
-
rateLimit?: RateLimitConfig;
|
|
81
|
-
providers?: Record<string, (apiKey: string, model: string, temperature: number) => LLMProvider>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export class MemoryAgent {
|
|
85
|
-
private memory: SimpleMemory;
|
|
86
|
-
private defaultProvider: string;
|
|
87
|
-
private defaultApiKey?: string;
|
|
88
|
-
private defaultModel?: string;
|
|
89
|
-
private rateLimiter: Map<string, number[]>;
|
|
90
|
-
private rateLimitConfig: RateLimitConfig;
|
|
91
|
-
private providers: Record<string, (apiKey: string, model: string, temperature: number) => LLMProvider>;
|
|
92
|
-
private sessionId: string;
|
|
93
|
-
private conversationHistory: Array<{ role: string; content: string }>;
|
|
94
|
-
private analytics: AgentAnalytics;
|
|
95
|
-
private userId: string;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Initialize memory agent
|
|
99
|
-
*/
|
|
100
|
-
constructor(userId: string, storage: IMemoryStorage, options: MemoryAgentOptions = {}) {
|
|
101
|
-
if (!userId || !storage) {
|
|
102
|
-
throw new Error("userId and storage are required parameters");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
this.userId = userId;
|
|
106
|
-
this.memory = new SimpleMemory(userId, storage, options.memoryOptions || {});
|
|
107
|
-
this.defaultProvider = options.defaultProvider || "groq";
|
|
108
|
-
this.defaultApiKey = options.defaultApiKey;
|
|
109
|
-
this.defaultModel = options.defaultModel;
|
|
110
|
-
|
|
111
|
-
// Rate limiting
|
|
112
|
-
this.rateLimiter = new Map();
|
|
113
|
-
this.rateLimitConfig = {
|
|
114
|
-
...MEMORY_CONFIG.DEFAULT_RATE_LIMIT,
|
|
115
|
-
...options.rateLimit,
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
// LLM providers
|
|
119
|
-
this.providers = options.providers || this.getDefaultProviders();
|
|
120
|
-
|
|
121
|
-
// Session management
|
|
122
|
-
this.sessionId = this.generateSessionId();
|
|
123
|
-
this.conversationHistory = [];
|
|
124
|
-
|
|
125
|
-
// Analytics
|
|
126
|
-
this.analytics = {
|
|
127
|
-
totalMessages: 0,
|
|
128
|
-
totalTokens: 0,
|
|
129
|
-
averageResponseTime: 0,
|
|
130
|
-
errorCount: 0,
|
|
131
|
-
sessionStartTime: Date.now(),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Get default LLM providers
|
|
137
|
-
*/
|
|
138
|
-
private getDefaultProviders(): Record<string, (apiKey: string, model: string, temperature: number) => LLMProvider> {
|
|
139
|
-
return {
|
|
140
|
-
groq: (apiKey, model, temperature) => ({
|
|
141
|
-
invoke: async (prompt) => {
|
|
142
|
-
// Implementation would go here
|
|
143
|
-
return { content: "Default response", tokensUsed: 0 };
|
|
144
|
-
},
|
|
145
|
-
}),
|
|
146
|
-
openai: (apiKey, model, temperature) => ({
|
|
147
|
-
invoke: async (prompt) => {
|
|
148
|
-
// Implementation would go here
|
|
149
|
-
return { content: "Default response", tokensUsed: 0 };
|
|
150
|
-
},
|
|
151
|
-
}),
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Generate unique session ID
|
|
157
|
-
*/
|
|
158
|
-
private generateSessionId(): string {
|
|
159
|
-
return `${this.userId}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Rate limiting check with sliding window
|
|
164
|
-
*/
|
|
165
|
-
private checkRateLimit(key: string, maxRequests?: number, windowMs?: number): boolean {
|
|
166
|
-
const config = {
|
|
167
|
-
maxRequests: maxRequests || this.rateLimitConfig.requests,
|
|
168
|
-
windowMs: windowMs || this.rateLimitConfig.windowMs,
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const now = Date.now();
|
|
172
|
-
const requests = this.rateLimiter.get(key) || [];
|
|
173
|
-
|
|
174
|
-
// Remove old requests outside the window
|
|
175
|
-
const validRequests = requests.filter(
|
|
176
|
-
(time) => now - time < config.windowMs,
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
if (validRequests.length >= config.maxRequests) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
validRequests.push(now);
|
|
184
|
-
this.rateLimiter.set(key, validRequests);
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Main chat method with comprehensive error handling
|
|
190
|
-
*/
|
|
191
|
-
async chat(message: string, options: ChatOptions = {}): Promise<ChatResponse> {
|
|
192
|
-
const startTime = Date.now();
|
|
193
|
-
|
|
194
|
-
// Input validation
|
|
195
|
-
if (!message || typeof message !== "string" || message.trim().length === 0) {
|
|
196
|
-
return {
|
|
197
|
-
error: "Message cannot be empty",
|
|
198
|
-
success: false,
|
|
199
|
-
timestamp: new Date().toISOString(),
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Rate limiting
|
|
204
|
-
const rateLimitKey = `chat-${this.userId}`;
|
|
205
|
-
if (!this.checkRateLimit(rateLimitKey)) {
|
|
206
|
-
return {
|
|
207
|
-
error: "Rate limit exceeded. Please try again later.",
|
|
208
|
-
success: false,
|
|
209
|
-
timestamp: new Date().toISOString(),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
// Add user message to memory
|
|
215
|
-
this.memory.addMessage("user", message, {
|
|
216
|
-
sessionId: this.sessionId,
|
|
217
|
-
timestamp: Date.now(),
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// Get memory context
|
|
221
|
-
const memoryContext = await this.memory.getMemoryContext(message, true, {
|
|
222
|
-
maxMemories: options.maxMemories || 8,
|
|
223
|
-
minImportance: options.minImportance || 0.5,
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
// Build enhanced prompt
|
|
227
|
-
const prompt = this.buildPrompt(message, memoryContext, options);
|
|
228
|
-
|
|
229
|
-
// Generate response
|
|
230
|
-
const response = await this.generateResponse(prompt, options);
|
|
231
|
-
|
|
232
|
-
if (!response || !response.content) {
|
|
233
|
-
throw new Error("Invalid response from LLM");
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Add response to memory
|
|
237
|
-
this.memory.addMessage("assistant", response.content, {
|
|
238
|
-
sessionId: this.sessionId,
|
|
239
|
-
tokensUsed: response.tokensUsed,
|
|
240
|
-
timestamp: Date.now(),
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// Update analytics
|
|
244
|
-
this.updateAnalytics(response.tokensUsed, Date.now() - startTime);
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
content: response.content,
|
|
248
|
-
memoryContext: memoryContext,
|
|
249
|
-
success: true,
|
|
250
|
-
tokensUsed: response.tokensUsed || 0,
|
|
251
|
-
responseTime: Date.now() - startTime,
|
|
252
|
-
sessionId: this.sessionId,
|
|
253
|
-
timestamp: new Date().toISOString(),
|
|
254
|
-
};
|
|
255
|
-
} catch (error) {
|
|
256
|
-
console.error("Chat error:", error);
|
|
257
|
-
this.analytics.errorCount++;
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
error: error.message || "An unexpected error occurred",
|
|
261
|
-
success: false,
|
|
262
|
-
timestamp: new Date().toISOString(),
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Generate LLM response with timeout and error handling
|
|
269
|
-
*/
|
|
270
|
-
private async generateResponse(prompt: string, options: ChatOptions): Promise<{ content: string; tokensUsed: number }> {
|
|
271
|
-
const provider = options.provider || this.defaultProvider;
|
|
272
|
-
const apiKey = options.apiKey || this.defaultApiKey;
|
|
273
|
-
const model = options.model || this.defaultModel;
|
|
274
|
-
const temperature = options.temperature || 0.7;
|
|
275
|
-
|
|
276
|
-
if (!this.providers || !this.providers[provider]) {
|
|
277
|
-
throw new Error(`Provider ${provider} not available`);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const llm = this.providers[provider](apiKey || "", model || "", temperature);
|
|
281
|
-
|
|
282
|
-
// Add timeout to LLM call
|
|
283
|
-
const timeoutPromise = new Promise<never>((_, reject) =>
|
|
284
|
-
setTimeout(
|
|
285
|
-
() => reject(new Error("LLM request timeout")),
|
|
286
|
-
MEMORY_CONFIG.DEFAULT_TIMEOUT,
|
|
287
|
-
),
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
return await Promise.race([llm.invoke(prompt), timeoutPromise]);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Build enhanced prompt with context
|
|
295
|
-
*/
|
|
296
|
-
private buildPrompt(message: string, memoryContext: string, options: ChatOptions): string {
|
|
297
|
-
let prompt = "";
|
|
298
|
-
|
|
299
|
-
// Add system context if provided
|
|
300
|
-
if (options.systemPrompt) {
|
|
301
|
-
prompt += `${options.systemPrompt}\n\n`;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Add memory context
|
|
305
|
-
if (memoryContext) {
|
|
306
|
-
prompt += `${memoryContext}\n\n`;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Add conversation history if requested
|
|
310
|
-
if (options.includeHistory && this.conversationHistory.length > 0) {
|
|
311
|
-
prompt += "Recent conversation history:\n";
|
|
312
|
-
this.conversationHistory.slice(-5).forEach((msg) => {
|
|
313
|
-
prompt += `${msg.role}: ${msg.content}\n`;
|
|
314
|
-
});
|
|
315
|
-
prompt += "\n";
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
prompt += `User: ${message}\n\nAssistant:`;
|
|
319
|
-
|
|
320
|
-
return prompt;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Update analytics
|
|
325
|
-
*/
|
|
326
|
-
private updateAnalytics(tokensUsed: number, responseTime: number): void {
|
|
327
|
-
this.analytics.totalMessages++;
|
|
328
|
-
this.analytics.totalTokens += tokensUsed || 0;
|
|
329
|
-
this.analytics.averageResponseTime =
|
|
330
|
-
(this.analytics.averageResponseTime * (this.analytics.totalMessages - 1) +
|
|
331
|
-
responseTime) /
|
|
332
|
-
this.analytics.totalMessages;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Remember a fact manually
|
|
337
|
-
*/
|
|
338
|
-
async remember(
|
|
339
|
-
fact: string,
|
|
340
|
-
importance: number = 1,
|
|
341
|
-
category: MemoryType = MEMORY_TYPES.MANUAL,
|
|
342
|
-
metadata: Record<string, any> = {},
|
|
343
|
-
): Promise<string> {
|
|
344
|
-
try {
|
|
345
|
-
return await this.memory.storeFact(fact, importance, category, {
|
|
346
|
-
...metadata,
|
|
347
|
-
source: "manual",
|
|
348
|
-
timestamp: Date.now(),
|
|
349
|
-
});
|
|
350
|
-
} catch (error) {
|
|
351
|
-
console.error("Error remembering fact:", error);
|
|
352
|
-
throw error;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Get memories with filtering
|
|
358
|
-
*/
|
|
359
|
-
async getMemories(query: string = "", limit: number = 10, options: MemorySearchOptions = {}): Promise<any[]> {
|
|
360
|
-
return await this.memory.recallRelevantMemories(query, limit, options);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Force store summary of current conversation
|
|
365
|
-
*/
|
|
366
|
-
async forceStoreSummary(): Promise<boolean> {
|
|
367
|
-
return await this.memory.summarizeAndStore();
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Health check for the agent
|
|
372
|
-
*/
|
|
373
|
-
async healthCheck(): Promise<any> {
|
|
374
|
-
try {
|
|
375
|
-
const memoryMetrics = this.memory.getMetrics();
|
|
376
|
-
const rateLimitStatus = this.checkRateLimit("health-check", 1, 1000);
|
|
377
|
-
|
|
378
|
-
return {
|
|
379
|
-
status: "healthy",
|
|
380
|
-
memory: memoryMetrics,
|
|
381
|
-
rateLimit: rateLimitStatus,
|
|
382
|
-
analytics: this.analytics,
|
|
383
|
-
sessionId: this.sessionId,
|
|
384
|
-
uptime: Date.now() - this.analytics.sessionStartTime,
|
|
385
|
-
timestamp: new Date().toISOString(),
|
|
386
|
-
};
|
|
387
|
-
} catch (error) {
|
|
388
|
-
return {
|
|
389
|
-
status: "unhealthy",
|
|
390
|
-
error: error.message,
|
|
391
|
-
timestamp: new Date().toISOString(),
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Get analytics and performance metrics
|
|
398
|
-
*/
|
|
399
|
-
getAnalytics(): any {
|
|
400
|
-
return {
|
|
401
|
-
...this.analytics,
|
|
402
|
-
memory: this.memory.getMetrics(),
|
|
403
|
-
sessionId: this.sessionId,
|
|
404
|
-
uptime: Date.now() - this.analytics.sessionStartTime,
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Reset session and clear conversation history
|
|
410
|
-
*/
|
|
411
|
-
resetSession(): void {
|
|
412
|
-
this.sessionId = this.generateSessionId();
|
|
413
|
-
this.conversationHistory = [];
|
|
414
|
-
this.analytics.sessionStartTime = Date.now();
|
|
415
|
-
}
|
|
416
|
-
}
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Memory Agent
|
|
4
|
+
*
|
|
5
|
+
* Enhanced Memory Agent with:
|
|
6
|
+
* - Rate limiting
|
|
7
|
+
* - Multiple LLM provider support
|
|
8
|
+
* - Health monitoring
|
|
9
|
+
* - Conversation management
|
|
10
|
+
* - Memory analytics
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { SimpleMemory } from "./storage/in-memory-storage";
|
|
14
|
+
import type { IMemoryStorage } from "./storage/storage-interface";
|
|
15
|
+
import type { MemoryType, MemorySearchOptions } from "./types";
|
|
16
|
+
import { MEMORY_CONFIG, MEMORY_TYPES } from "./types";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* LLM provider interface
|
|
20
|
+
*/
|
|
21
|
+
interface LLMProvider {
|
|
22
|
+
invoke: (prompt: string) => Promise<{ content: string; tokensUsed: number }>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Chat options
|
|
27
|
+
*/
|
|
28
|
+
interface ChatOptions {
|
|
29
|
+
provider?: string;
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
model?: string;
|
|
32
|
+
temperature?: number;
|
|
33
|
+
systemPrompt?: string;
|
|
34
|
+
includeHistory?: boolean;
|
|
35
|
+
maxMemories?: number;
|
|
36
|
+
minImportance?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Chat response
|
|
41
|
+
*/
|
|
42
|
+
interface ChatResponse {
|
|
43
|
+
content?: string;
|
|
44
|
+
memoryContext?: string;
|
|
45
|
+
success: boolean;
|
|
46
|
+
tokensUsed?: number;
|
|
47
|
+
responseTime?: number;
|
|
48
|
+
sessionId?: string;
|
|
49
|
+
timestamp: string;
|
|
50
|
+
error?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Agent analytics
|
|
55
|
+
*/
|
|
56
|
+
interface AgentAnalytics {
|
|
57
|
+
totalMessages: number;
|
|
58
|
+
totalTokens: number;
|
|
59
|
+
averageResponseTime: number;
|
|
60
|
+
errorCount: number;
|
|
61
|
+
sessionStartTime: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Rate limit configuration
|
|
66
|
+
*/
|
|
67
|
+
interface RateLimitConfig {
|
|
68
|
+
requests: number;
|
|
69
|
+
windowMs: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Agent options
|
|
74
|
+
*/
|
|
75
|
+
export interface MemoryAgentOptions {
|
|
76
|
+
memoryOptions?: any;
|
|
77
|
+
defaultProvider?: string;
|
|
78
|
+
defaultApiKey?: string;
|
|
79
|
+
defaultModel?: string;
|
|
80
|
+
rateLimit?: RateLimitConfig;
|
|
81
|
+
providers?: Record<string, (apiKey: string, model: string, temperature: number) => LLMProvider>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export class MemoryAgent {
|
|
85
|
+
private memory: SimpleMemory;
|
|
86
|
+
private defaultProvider: string;
|
|
87
|
+
private defaultApiKey?: string;
|
|
88
|
+
private defaultModel?: string;
|
|
89
|
+
private rateLimiter: Map<string, number[]>;
|
|
90
|
+
private rateLimitConfig: RateLimitConfig;
|
|
91
|
+
private providers: Record<string, (apiKey: string, model: string, temperature: number) => LLMProvider>;
|
|
92
|
+
private sessionId: string;
|
|
93
|
+
private conversationHistory: Array<{ role: string; content: string }>;
|
|
94
|
+
private analytics: AgentAnalytics;
|
|
95
|
+
private userId: string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Initialize memory agent
|
|
99
|
+
*/
|
|
100
|
+
constructor(userId: string, storage: IMemoryStorage, options: MemoryAgentOptions = {}) {
|
|
101
|
+
if (!userId || !storage) {
|
|
102
|
+
throw new Error("userId and storage are required parameters");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.userId = userId;
|
|
106
|
+
this.memory = new SimpleMemory(userId, storage, options.memoryOptions || {});
|
|
107
|
+
this.defaultProvider = options.defaultProvider || "groq";
|
|
108
|
+
this.defaultApiKey = options.defaultApiKey;
|
|
109
|
+
this.defaultModel = options.defaultModel;
|
|
110
|
+
|
|
111
|
+
// Rate limiting
|
|
112
|
+
this.rateLimiter = new Map();
|
|
113
|
+
this.rateLimitConfig = {
|
|
114
|
+
...MEMORY_CONFIG.DEFAULT_RATE_LIMIT,
|
|
115
|
+
...options.rateLimit,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// LLM providers
|
|
119
|
+
this.providers = options.providers || this.getDefaultProviders();
|
|
120
|
+
|
|
121
|
+
// Session management
|
|
122
|
+
this.sessionId = this.generateSessionId();
|
|
123
|
+
this.conversationHistory = [];
|
|
124
|
+
|
|
125
|
+
// Analytics
|
|
126
|
+
this.analytics = {
|
|
127
|
+
totalMessages: 0,
|
|
128
|
+
totalTokens: 0,
|
|
129
|
+
averageResponseTime: 0,
|
|
130
|
+
errorCount: 0,
|
|
131
|
+
sessionStartTime: Date.now(),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get default LLM providers
|
|
137
|
+
*/
|
|
138
|
+
private getDefaultProviders(): Record<string, (apiKey: string, model: string, temperature: number) => LLMProvider> {
|
|
139
|
+
return {
|
|
140
|
+
groq: (apiKey, model, temperature) => ({
|
|
141
|
+
invoke: async (prompt) => {
|
|
142
|
+
// Implementation would go here
|
|
143
|
+
return { content: "Default response", tokensUsed: 0 };
|
|
144
|
+
},
|
|
145
|
+
}),
|
|
146
|
+
openai: (apiKey, model, temperature) => ({
|
|
147
|
+
invoke: async (prompt) => {
|
|
148
|
+
// Implementation would go here
|
|
149
|
+
return { content: "Default response", tokensUsed: 0 };
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generate unique session ID
|
|
157
|
+
*/
|
|
158
|
+
private generateSessionId(): string {
|
|
159
|
+
return `${this.userId}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Rate limiting check with sliding window
|
|
164
|
+
*/
|
|
165
|
+
private checkRateLimit(key: string, maxRequests?: number, windowMs?: number): boolean {
|
|
166
|
+
const config = {
|
|
167
|
+
maxRequests: maxRequests || this.rateLimitConfig.requests,
|
|
168
|
+
windowMs: windowMs || this.rateLimitConfig.windowMs,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
const requests = this.rateLimiter.get(key) || [];
|
|
173
|
+
|
|
174
|
+
// Remove old requests outside the window
|
|
175
|
+
const validRequests = requests.filter(
|
|
176
|
+
(time) => now - time < config.windowMs,
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
if (validRequests.length >= config.maxRequests) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
validRequests.push(now);
|
|
184
|
+
this.rateLimiter.set(key, validRequests);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Main chat method with comprehensive error handling
|
|
190
|
+
*/
|
|
191
|
+
async chat(message: string, options: ChatOptions = {}): Promise<ChatResponse> {
|
|
192
|
+
const startTime = Date.now();
|
|
193
|
+
|
|
194
|
+
// Input validation
|
|
195
|
+
if (!message || typeof message !== "string" || message.trim().length === 0) {
|
|
196
|
+
return {
|
|
197
|
+
error: "Message cannot be empty",
|
|
198
|
+
success: false,
|
|
199
|
+
timestamp: new Date().toISOString(),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Rate limiting
|
|
204
|
+
const rateLimitKey = `chat-${this.userId}`;
|
|
205
|
+
if (!this.checkRateLimit(rateLimitKey)) {
|
|
206
|
+
return {
|
|
207
|
+
error: "Rate limit exceeded. Please try again later.",
|
|
208
|
+
success: false,
|
|
209
|
+
timestamp: new Date().toISOString(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
// Add user message to memory
|
|
215
|
+
this.memory.addMessage("user", message, {
|
|
216
|
+
sessionId: this.sessionId,
|
|
217
|
+
timestamp: Date.now(),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Get memory context
|
|
221
|
+
const memoryContext = await this.memory.getMemoryContext(message, true, {
|
|
222
|
+
maxMemories: options.maxMemories || 8,
|
|
223
|
+
minImportance: options.minImportance || 0.5,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Build enhanced prompt
|
|
227
|
+
const prompt = this.buildPrompt(message, memoryContext, options);
|
|
228
|
+
|
|
229
|
+
// Generate response
|
|
230
|
+
const response = await this.generateResponse(prompt, options);
|
|
231
|
+
|
|
232
|
+
if (!response || !response.content) {
|
|
233
|
+
throw new Error("Invalid response from LLM");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Add response to memory
|
|
237
|
+
this.memory.addMessage("assistant", response.content, {
|
|
238
|
+
sessionId: this.sessionId,
|
|
239
|
+
tokensUsed: response.tokensUsed,
|
|
240
|
+
timestamp: Date.now(),
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Update analytics
|
|
244
|
+
this.updateAnalytics(response.tokensUsed, Date.now() - startTime);
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
content: response.content,
|
|
248
|
+
memoryContext: memoryContext,
|
|
249
|
+
success: true,
|
|
250
|
+
tokensUsed: response.tokensUsed || 0,
|
|
251
|
+
responseTime: Date.now() - startTime,
|
|
252
|
+
sessionId: this.sessionId,
|
|
253
|
+
timestamp: new Date().toISOString(),
|
|
254
|
+
};
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.error("Chat error:", error);
|
|
257
|
+
this.analytics.errorCount++;
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
error: error.message || "An unexpected error occurred",
|
|
261
|
+
success: false,
|
|
262
|
+
timestamp: new Date().toISOString(),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Generate LLM response with timeout and error handling
|
|
269
|
+
*/
|
|
270
|
+
private async generateResponse(prompt: string, options: ChatOptions): Promise<{ content: string; tokensUsed: number }> {
|
|
271
|
+
const provider = options.provider || this.defaultProvider;
|
|
272
|
+
const apiKey = options.apiKey || this.defaultApiKey;
|
|
273
|
+
const model = options.model || this.defaultModel;
|
|
274
|
+
const temperature = options.temperature || 0.7;
|
|
275
|
+
|
|
276
|
+
if (!this.providers || !this.providers[provider]) {
|
|
277
|
+
throw new Error(`Provider ${provider} not available`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const llm = this.providers[provider](apiKey || "", model || "", temperature);
|
|
281
|
+
|
|
282
|
+
// Add timeout to LLM call
|
|
283
|
+
const timeoutPromise = new Promise<never>((_, reject) =>
|
|
284
|
+
setTimeout(
|
|
285
|
+
() => reject(new Error("LLM request timeout")),
|
|
286
|
+
MEMORY_CONFIG.DEFAULT_TIMEOUT,
|
|
287
|
+
),
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
return await Promise.race([llm.invoke(prompt), timeoutPromise]);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Build enhanced prompt with context
|
|
295
|
+
*/
|
|
296
|
+
private buildPrompt(message: string, memoryContext: string, options: ChatOptions): string {
|
|
297
|
+
let prompt = "";
|
|
298
|
+
|
|
299
|
+
// Add system context if provided
|
|
300
|
+
if (options.systemPrompt) {
|
|
301
|
+
prompt += `${options.systemPrompt}\n\n`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Add memory context
|
|
305
|
+
if (memoryContext) {
|
|
306
|
+
prompt += `${memoryContext}\n\n`;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Add conversation history if requested
|
|
310
|
+
if (options.includeHistory && this.conversationHistory.length > 0) {
|
|
311
|
+
prompt += "Recent conversation history:\n";
|
|
312
|
+
this.conversationHistory.slice(-5).forEach((msg) => {
|
|
313
|
+
prompt += `${msg.role}: ${msg.content}\n`;
|
|
314
|
+
});
|
|
315
|
+
prompt += "\n";
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
prompt += `User: ${message}\n\nAssistant:`;
|
|
319
|
+
|
|
320
|
+
return prompt;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Update analytics
|
|
325
|
+
*/
|
|
326
|
+
private updateAnalytics(tokensUsed: number, responseTime: number): void {
|
|
327
|
+
this.analytics.totalMessages++;
|
|
328
|
+
this.analytics.totalTokens += tokensUsed || 0;
|
|
329
|
+
this.analytics.averageResponseTime =
|
|
330
|
+
(this.analytics.averageResponseTime * (this.analytics.totalMessages - 1) +
|
|
331
|
+
responseTime) /
|
|
332
|
+
this.analytics.totalMessages;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Remember a fact manually
|
|
337
|
+
*/
|
|
338
|
+
async remember(
|
|
339
|
+
fact: string,
|
|
340
|
+
importance: number = 1,
|
|
341
|
+
category: MemoryType = MEMORY_TYPES.MANUAL,
|
|
342
|
+
metadata: Record<string, any> = {},
|
|
343
|
+
): Promise<string> {
|
|
344
|
+
try {
|
|
345
|
+
return await this.memory.storeFact(fact, importance, category, {
|
|
346
|
+
...metadata,
|
|
347
|
+
source: "manual",
|
|
348
|
+
timestamp: Date.now(),
|
|
349
|
+
});
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error("Error remembering fact:", error);
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Get memories with filtering
|
|
358
|
+
*/
|
|
359
|
+
async getMemories(query: string = "", limit: number = 10, options: MemorySearchOptions = {}): Promise<any[]> {
|
|
360
|
+
return await this.memory.recallRelevantMemories(query, limit, options);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Force store summary of current conversation
|
|
365
|
+
*/
|
|
366
|
+
async forceStoreSummary(): Promise<boolean> {
|
|
367
|
+
return await this.memory.summarizeAndStore();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Health check for the agent
|
|
372
|
+
*/
|
|
373
|
+
async healthCheck(): Promise<any> {
|
|
374
|
+
try {
|
|
375
|
+
const memoryMetrics = this.memory.getMetrics();
|
|
376
|
+
const rateLimitStatus = this.checkRateLimit("health-check", 1, 1000);
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
status: "healthy",
|
|
380
|
+
memory: memoryMetrics,
|
|
381
|
+
rateLimit: rateLimitStatus,
|
|
382
|
+
analytics: this.analytics,
|
|
383
|
+
sessionId: this.sessionId,
|
|
384
|
+
uptime: Date.now() - this.analytics.sessionStartTime,
|
|
385
|
+
timestamp: new Date().toISOString(),
|
|
386
|
+
};
|
|
387
|
+
} catch (error) {
|
|
388
|
+
return {
|
|
389
|
+
status: "unhealthy",
|
|
390
|
+
error: error.message,
|
|
391
|
+
timestamp: new Date().toISOString(),
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Get analytics and performance metrics
|
|
398
|
+
*/
|
|
399
|
+
getAnalytics(): any {
|
|
400
|
+
return {
|
|
401
|
+
...this.analytics,
|
|
402
|
+
memory: this.memory.getMetrics(),
|
|
403
|
+
sessionId: this.sessionId,
|
|
404
|
+
uptime: Date.now() - this.analytics.sessionStartTime,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Reset session and clear conversation history
|
|
410
|
+
*/
|
|
411
|
+
resetSession(): void {
|
|
412
|
+
this.sessionId = this.generateSessionId();
|
|
413
|
+
this.conversationHistory = [];
|
|
414
|
+
this.analytics.sessionStartTime = Date.now();
|
|
415
|
+
}
|
|
416
|
+
}
|