@hashgraphonline/conversational-agent 0.1.207 → 0.1.208
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/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/langchain/ContentAwareAgentExecutor.d.ts +4 -6
- package/dist/esm/index12.js +1 -1
- package/dist/esm/index14.js +1 -1
- package/dist/esm/index15.js +1 -62
- package/dist/esm/index15.js.map +1 -1
- package/dist/esm/index16.js +1 -1
- package/dist/esm/index18.js +3 -3
- package/dist/esm/index19.js +653 -85
- package/dist/esm/index19.js.map +1 -1
- package/dist/esm/index20.js +194 -624
- package/dist/esm/index20.js.map +1 -1
- package/dist/esm/index21.js +163 -214
- package/dist/esm/index21.js.map +1 -1
- package/dist/esm/index22.js +90 -146
- package/dist/esm/index22.js.map +1 -1
- package/dist/esm/index23.js +84 -115
- package/dist/esm/index23.js.map +1 -1
- package/dist/types/langchain/ContentAwareAgentExecutor.d.ts +4 -6
- package/package.json +1 -1
- package/src/langchain/ContentAwareAgentExecutor.ts +4 -96
package/dist/esm/index20.js
CHANGED
|
@@ -1,663 +1,233 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
this.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
storageUtilization: 0,
|
|
18
|
-
performanceMetrics: {
|
|
19
|
-
averageCreationTimeMs: 0,
|
|
20
|
-
averageResolutionTimeMs: 0,
|
|
21
|
-
averageCleanupTimeMs: 0,
|
|
22
|
-
creationTimes: [],
|
|
23
|
-
resolutionTimes: [],
|
|
24
|
-
cleanupTimes: []
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
if (this.referenceConfig.enableAutoCleanup) {
|
|
28
|
-
this.startReferenceCleanupTimer();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Store messages in the content storage
|
|
33
|
-
* Automatically drops oldest messages if storage limit is exceeded
|
|
34
|
-
* @param messages - Messages to store
|
|
35
|
-
* @returns Result indicating how many messages were stored and dropped
|
|
36
|
-
*/
|
|
37
|
-
storeMessages(messages) {
|
|
38
|
-
if (messages.length === 0) {
|
|
39
|
-
return { stored: 0, dropped: 0 };
|
|
40
|
-
}
|
|
41
|
-
const now = /* @__PURE__ */ new Date();
|
|
42
|
-
let dropped = 0;
|
|
43
|
-
const storedMessages = messages.map((message) => ({
|
|
44
|
-
message,
|
|
45
|
-
storedAt: now,
|
|
46
|
-
id: this.generateId()
|
|
47
|
-
}));
|
|
48
|
-
this.messages.push(...storedMessages);
|
|
49
|
-
while (this.messages.length > this.maxStorage) {
|
|
50
|
-
this.messages.shift();
|
|
51
|
-
dropped++;
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
stored: storedMessages.length,
|
|
55
|
-
dropped
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Get the most recent messages from storage
|
|
60
|
-
* @param count - Number of recent messages to retrieve
|
|
61
|
-
* @returns Array of recent messages in chronological order
|
|
62
|
-
*/
|
|
63
|
-
getRecentMessages(count) {
|
|
64
|
-
if (count <= 0 || this.messages.length === 0) {
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
const startIndex = Math.max(0, this.messages.length - count);
|
|
68
|
-
return this.messages.slice(startIndex).map((stored) => stored.message);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Search for messages containing specific text or patterns
|
|
72
|
-
* @param query - Search term or regex pattern
|
|
73
|
-
* @param options - Search configuration options
|
|
74
|
-
* @returns Array of matching messages
|
|
75
|
-
*/
|
|
76
|
-
searchMessages(query, options = {}) {
|
|
77
|
-
if (!query || this.messages.length === 0) {
|
|
78
|
-
return [];
|
|
79
|
-
}
|
|
80
|
-
const {
|
|
81
|
-
caseSensitive = false,
|
|
82
|
-
limit,
|
|
83
|
-
useRegex = false
|
|
84
|
-
} = options;
|
|
85
|
-
let matches = [];
|
|
86
|
-
if (useRegex) {
|
|
87
|
-
try {
|
|
88
|
-
const regex = new RegExp(query, caseSensitive ? "g" : "gi");
|
|
89
|
-
matches = this.messages.filter((stored) => regex.test(stored.message.content)).map((stored) => stored.message);
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.warn("Invalid regex pattern:", query, error);
|
|
92
|
-
return [];
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
const searchTerm = caseSensitive ? query : query.toLowerCase();
|
|
96
|
-
matches = this.messages.filter((stored) => {
|
|
97
|
-
const content = stored.message.content;
|
|
98
|
-
const searchContent = caseSensitive ? content : content.toLowerCase();
|
|
99
|
-
return searchContent.includes(searchTerm);
|
|
100
|
-
}).map((stored) => stored.message);
|
|
101
|
-
}
|
|
102
|
-
return limit ? matches.slice(0, limit) : matches;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Get messages from a specific time range
|
|
106
|
-
* @param startTime - Start of time range (inclusive)
|
|
107
|
-
* @param endTime - End of time range (inclusive)
|
|
108
|
-
* @returns Array of messages within the time range
|
|
109
|
-
*/
|
|
110
|
-
getMessagesFromTimeRange(startTime, endTime) {
|
|
111
|
-
if (startTime > endTime || this.messages.length === 0) {
|
|
112
|
-
return [];
|
|
113
|
-
}
|
|
114
|
-
return this.messages.filter(
|
|
115
|
-
(stored) => stored.storedAt >= startTime && stored.storedAt <= endTime
|
|
116
|
-
).map((stored) => stored.message);
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Get storage statistics and usage information
|
|
120
|
-
* @returns Current storage statistics
|
|
121
|
-
*/
|
|
122
|
-
getStorageStats() {
|
|
123
|
-
const totalMessages = this.messages.length;
|
|
124
|
-
const usagePercentage = totalMessages > 0 ? Math.round(totalMessages / this.maxStorage * 100) : 0;
|
|
125
|
-
let oldestMessageTime;
|
|
126
|
-
let newestMessageTime;
|
|
127
|
-
if (totalMessages > 0) {
|
|
128
|
-
oldestMessageTime = this.messages[0].storedAt;
|
|
129
|
-
newestMessageTime = this.messages[totalMessages - 1].storedAt;
|
|
130
|
-
}
|
|
131
|
-
return {
|
|
132
|
-
totalMessages,
|
|
133
|
-
maxStorageLimit: this.maxStorage,
|
|
134
|
-
usagePercentage,
|
|
135
|
-
oldestMessageTime,
|
|
136
|
-
newestMessageTime
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Clear all stored messages
|
|
141
|
-
*/
|
|
142
|
-
clear() {
|
|
143
|
-
this.messages = [];
|
|
144
|
-
this.idCounter = 0;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Get total number of stored messages
|
|
148
|
-
* @returns Number of messages currently in storage
|
|
149
|
-
*/
|
|
150
|
-
getTotalStoredMessages() {
|
|
151
|
-
return this.messages.length;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Update the maximum storage limit
|
|
155
|
-
* @param newLimit - New maximum storage limit
|
|
156
|
-
*/
|
|
157
|
-
updateStorageLimit(newLimit) {
|
|
158
|
-
if (newLimit <= 0) {
|
|
159
|
-
throw new Error("Storage limit must be greater than 0");
|
|
160
|
-
}
|
|
161
|
-
this.maxStorage = newLimit;
|
|
162
|
-
while (this.messages.length > this.maxStorage) {
|
|
163
|
-
this.messages.shift();
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Get messages by message type
|
|
168
|
-
* @param messageType - Type of messages to retrieve ('human', 'ai', 'system', etc.)
|
|
169
|
-
* @param limit - Maximum number of messages to return
|
|
170
|
-
* @returns Array of messages of the specified type
|
|
171
|
-
*/
|
|
172
|
-
getMessagesByType(messageType, limit) {
|
|
173
|
-
const filtered = this.messages.filter((stored) => stored.message._getType() === messageType).map((stored) => stored.message);
|
|
174
|
-
return limit ? filtered.slice(0, limit) : filtered;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Get the current storage configuration
|
|
178
|
-
* @returns Storage configuration object
|
|
179
|
-
*/
|
|
180
|
-
getConfig() {
|
|
1
|
+
class MCPContentProcessor {
|
|
2
|
+
constructor(contentStorage, logger) {
|
|
3
|
+
this.contentStorage = contentStorage;
|
|
4
|
+
this.logger = logger;
|
|
5
|
+
}
|
|
6
|
+
analyzeResponse(response) {
|
|
7
|
+
const contents = [];
|
|
8
|
+
let totalSize = 0;
|
|
9
|
+
this.extractContentFromResponse(response, contents);
|
|
10
|
+
totalSize = contents.reduce((sum, content) => sum + content.sizeBytes, 0);
|
|
11
|
+
const largestContentSize = contents.reduce((max, content) => Math.max(max, content.sizeBytes), 0);
|
|
12
|
+
const shouldProcess = contents.some(
|
|
13
|
+
(content) => this.contentStorage.shouldUseReference(
|
|
14
|
+
typeof content.content === "string" ? content.content : JSON.stringify(content.content)
|
|
15
|
+
)
|
|
16
|
+
);
|
|
181
17
|
return {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
18
|
+
shouldProcess,
|
|
19
|
+
contents,
|
|
20
|
+
totalSize,
|
|
21
|
+
largestContentSize
|
|
185
22
|
};
|
|
186
23
|
}
|
|
187
|
-
|
|
188
|
-
* Generate a unique ID for stored messages
|
|
189
|
-
* @returns Unique string identifier
|
|
190
|
-
*/
|
|
191
|
-
generateId() {
|
|
192
|
-
return `msg_${++this.idCounter}_${Date.now()}`;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Get messages stored within the last N minutes
|
|
196
|
-
* @param minutes - Number of minutes to look back
|
|
197
|
-
* @returns Array of messages from the last N minutes
|
|
198
|
-
*/
|
|
199
|
-
getRecentMessagesByTime(minutes) {
|
|
200
|
-
if (minutes <= 0 || this.messages.length === 0) {
|
|
201
|
-
return [];
|
|
202
|
-
}
|
|
203
|
-
const cutoffTime = new Date(Date.now() - minutes * 60 * 1e3);
|
|
204
|
-
return this.messages.filter((stored) => stored.storedAt >= cutoffTime).map((stored) => stored.message);
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Export messages to a JSON-serializable format
|
|
208
|
-
* @returns Serializable representation of stored messages
|
|
209
|
-
*/
|
|
210
|
-
exportMessages() {
|
|
211
|
-
return this.messages.map((stored) => ({
|
|
212
|
-
content: stored.message.content,
|
|
213
|
-
type: stored.message._getType(),
|
|
214
|
-
storedAt: stored.storedAt.toISOString(),
|
|
215
|
-
id: stored.id
|
|
216
|
-
}));
|
|
217
|
-
}
|
|
218
|
-
// ========== Reference-Based Content Storage Methods ==========
|
|
219
|
-
/**
|
|
220
|
-
* Determine if content should be stored as a reference based on size
|
|
221
|
-
*/
|
|
222
|
-
shouldUseReference(content) {
|
|
223
|
-
const size = Buffer.isBuffer(content) ? content.length : Buffer.byteLength(content, "utf8");
|
|
224
|
-
return size > this.referenceConfig.sizeThresholdBytes;
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Store content and return a reference if it exceeds the size threshold
|
|
228
|
-
* Otherwise returns null to indicate direct content should be used
|
|
229
|
-
*/
|
|
230
|
-
async storeContentIfLarge(content, metadata) {
|
|
231
|
-
const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content, "utf8");
|
|
232
|
-
if (!this.shouldUseReference(buffer)) {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
const storeMetadata = {
|
|
236
|
-
contentType: metadata.contentType || this.detectContentType(buffer, metadata.mimeType),
|
|
237
|
-
sizeBytes: buffer.length,
|
|
238
|
-
source: metadata.source,
|
|
239
|
-
tags: []
|
|
240
|
-
};
|
|
241
|
-
if (metadata.mimeType !== void 0) {
|
|
242
|
-
storeMetadata.mimeType = metadata.mimeType;
|
|
243
|
-
}
|
|
244
|
-
if (metadata.mcpToolName !== void 0) {
|
|
245
|
-
storeMetadata.mcpToolName = metadata.mcpToolName;
|
|
246
|
-
}
|
|
247
|
-
if (metadata.fileName !== void 0) {
|
|
248
|
-
storeMetadata.fileName = metadata.fileName;
|
|
249
|
-
}
|
|
250
|
-
if (metadata.tags !== void 0) {
|
|
251
|
-
storeMetadata.tags = metadata.tags;
|
|
252
|
-
}
|
|
253
|
-
if (metadata.customMetadata !== void 0) {
|
|
254
|
-
storeMetadata.customMetadata = metadata.customMetadata;
|
|
255
|
-
}
|
|
256
|
-
return await this.storeContent(buffer, storeMetadata);
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Store content and return a reference (implements ContentReferenceStore)
|
|
260
|
-
*/
|
|
261
|
-
async storeContent(content, metadata) {
|
|
262
|
-
const startTime = Date.now();
|
|
24
|
+
async processResponse(response, serverName, toolName) {
|
|
263
25
|
try {
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
const fullMetadata = {
|
|
267
|
-
...metadata,
|
|
268
|
-
createdAt: now,
|
|
269
|
-
lastAccessedAt: now,
|
|
270
|
-
accessCount: 0
|
|
271
|
-
};
|
|
272
|
-
const storedContent = {
|
|
273
|
-
content,
|
|
274
|
-
metadata: fullMetadata,
|
|
275
|
-
state: "active"
|
|
276
|
-
};
|
|
277
|
-
const expirationTime = this.calculateExpirationTime(metadata.source);
|
|
278
|
-
if (expirationTime !== void 0) {
|
|
279
|
-
storedContent.expiresAt = expirationTime;
|
|
280
|
-
}
|
|
281
|
-
this.contentStore.set(referenceId, storedContent);
|
|
282
|
-
this.updateStatsAfterStore(content.length);
|
|
283
|
-
await this.enforceReferenceStorageLimits();
|
|
284
|
-
const preview = this.createContentPreview(content, fullMetadata.contentType);
|
|
285
|
-
const referenceMetadata = {
|
|
286
|
-
contentType: fullMetadata.contentType,
|
|
287
|
-
sizeBytes: fullMetadata.sizeBytes,
|
|
288
|
-
source: fullMetadata.source
|
|
289
|
-
};
|
|
290
|
-
if (fullMetadata.fileName !== void 0) {
|
|
291
|
-
referenceMetadata.fileName = fullMetadata.fileName;
|
|
292
|
-
}
|
|
293
|
-
if (fullMetadata.mimeType !== void 0) {
|
|
294
|
-
referenceMetadata.mimeType = fullMetadata.mimeType;
|
|
295
|
-
}
|
|
296
|
-
const reference = {
|
|
297
|
-
referenceId,
|
|
298
|
-
state: "active",
|
|
299
|
-
preview,
|
|
300
|
-
metadata: referenceMetadata,
|
|
301
|
-
createdAt: now,
|
|
302
|
-
format: "ref://{id}"
|
|
303
|
-
};
|
|
304
|
-
const duration = Date.now() - startTime;
|
|
305
|
-
this.recordPerformanceMetric("creation", duration);
|
|
306
|
-
console.log(`[ContentStorage] Stored content with reference ID: ${referenceId} (${content.length} bytes)`);
|
|
307
|
-
return reference;
|
|
308
|
-
} catch (error) {
|
|
309
|
-
const duration = Date.now() - startTime;
|
|
310
|
-
this.recordPerformanceMetric("creation", duration);
|
|
311
|
-
console.error("[ContentStorage] Failed to store content:", error);
|
|
312
|
-
throw new ContentReferenceError(
|
|
313
|
-
`Failed to store content: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
314
|
-
"system_error",
|
|
315
|
-
void 0,
|
|
316
|
-
["Try again", "Check storage limits", "Contact administrator"]
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Resolve a reference to its content (implements ContentReferenceStore)
|
|
322
|
-
*/
|
|
323
|
-
async resolveReference(referenceId) {
|
|
324
|
-
const startTime = Date.now();
|
|
325
|
-
try {
|
|
326
|
-
if (!ReferenceIdGenerator.isValidReferenceId(referenceId)) {
|
|
327
|
-
this.referenceStats.failedResolutions++;
|
|
328
|
-
return {
|
|
329
|
-
success: false,
|
|
330
|
-
error: "Invalid reference ID format",
|
|
331
|
-
errorType: "not_found",
|
|
332
|
-
suggestedActions: ["Check the reference ID format", "Ensure the reference ID is complete"]
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
const storedContent = this.contentStore.get(referenceId);
|
|
336
|
-
if (!storedContent) {
|
|
337
|
-
this.referenceStats.failedResolutions++;
|
|
26
|
+
const analysis = this.analyzeResponse(response);
|
|
27
|
+
if (!analysis.shouldProcess) {
|
|
338
28
|
return {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
errorType: "not_found",
|
|
342
|
-
suggestedActions: ["Verify the reference ID", "Check if the content has expired", "Request fresh content"]
|
|
29
|
+
content: response,
|
|
30
|
+
wasProcessed: false
|
|
343
31
|
};
|
|
344
32
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
suggestedActions: ["Request fresh content", "Use alternative content source"]
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
if (storedContent.state !== "active") {
|
|
356
|
-
this.referenceStats.failedResolutions++;
|
|
357
|
-
return {
|
|
358
|
-
success: false,
|
|
359
|
-
error: `Reference is ${storedContent.state}`,
|
|
360
|
-
errorType: storedContent.state === "expired" ? "expired" : "corrupted",
|
|
361
|
-
suggestedActions: ["Request fresh content", "Check reference validity"]
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
storedContent.metadata.lastAccessedAt = /* @__PURE__ */ new Date();
|
|
365
|
-
storedContent.metadata.accessCount++;
|
|
366
|
-
this.referenceStats.totalResolutions++;
|
|
367
|
-
const duration = Date.now() - startTime;
|
|
368
|
-
this.recordPerformanceMetric("resolution", duration);
|
|
369
|
-
console.log(`[ContentStorage] Resolved reference ${referenceId} (${storedContent.content.length} bytes, access count: ${storedContent.metadata.accessCount})`);
|
|
370
|
-
return {
|
|
371
|
-
success: true,
|
|
372
|
-
content: storedContent.content,
|
|
373
|
-
metadata: storedContent.metadata
|
|
374
|
-
};
|
|
33
|
+
const processedResponse = await this.createReferencedResponse(
|
|
34
|
+
response,
|
|
35
|
+
analysis,
|
|
36
|
+
serverName,
|
|
37
|
+
toolName
|
|
38
|
+
);
|
|
39
|
+
return processedResponse;
|
|
375
40
|
} catch (error) {
|
|
376
|
-
|
|
377
|
-
this.recordPerformanceMetric("resolution", duration);
|
|
378
|
-
this.referenceStats.failedResolutions++;
|
|
379
|
-
console.error(`[ContentStorage] Error resolving reference ${referenceId}:`, error);
|
|
41
|
+
this.logger.error("Error processing MCP response:", error);
|
|
380
42
|
return {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
suggestedActions: ["Try again", "Contact administrator"]
|
|
43
|
+
content: response,
|
|
44
|
+
wasProcessed: false,
|
|
45
|
+
errors: [error instanceof Error ? error.message : "Unknown processing error"]
|
|
385
46
|
};
|
|
386
47
|
}
|
|
387
48
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
if (this.referenceConfig.enableAutoCleanup) {
|
|
444
|
-
this.startReferenceCleanupTimer();
|
|
445
|
-
}
|
|
446
|
-
console.log("[ContentStorage] Reference configuration updated");
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Perform cleanup based on current policies (implements ContentReferenceStore)
|
|
450
|
-
*/
|
|
451
|
-
async performCleanup() {
|
|
452
|
-
const startTime = Date.now();
|
|
49
|
+
extractContentFromResponse(obj, contents) {
|
|
50
|
+
if (obj === null || obj === void 0) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(obj)) {
|
|
54
|
+
obj.forEach((item) => this.extractContentFromResponse(item, contents));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (typeof obj === "object") {
|
|
58
|
+
const record = obj;
|
|
59
|
+
if (record.type === "text" && typeof record.text === "string") {
|
|
60
|
+
contents.push({
|
|
61
|
+
content: record.text,
|
|
62
|
+
type: "text",
|
|
63
|
+
sizeBytes: Buffer.byteLength(record.text, "utf8"),
|
|
64
|
+
mimeType: "text/plain"
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (record.type === "image" && typeof record.data === "string") {
|
|
69
|
+
contents.push({
|
|
70
|
+
content: record.data,
|
|
71
|
+
type: "image",
|
|
72
|
+
sizeBytes: Math.ceil(record.data.length * 0.75),
|
|
73
|
+
mimeType: record.mimeType || "image/jpeg"
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (record.type === "resource" && record.resource) {
|
|
78
|
+
const resourceStr = JSON.stringify(record.resource);
|
|
79
|
+
contents.push({
|
|
80
|
+
content: resourceStr,
|
|
81
|
+
type: "resource",
|
|
82
|
+
sizeBytes: Buffer.byteLength(resourceStr, "utf8"),
|
|
83
|
+
mimeType: "application/json"
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
Object.values(record).forEach((value) => this.extractContentFromResponse(value, contents));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (typeof obj === "string") {
|
|
91
|
+
if (obj.length > 1e3) {
|
|
92
|
+
contents.push({
|
|
93
|
+
content: obj,
|
|
94
|
+
type: "text",
|
|
95
|
+
sizeBytes: Buffer.byteLength(obj, "utf8"),
|
|
96
|
+
mimeType: this.detectMimeType(obj)
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async createReferencedResponse(originalResponse, analysis, serverName, toolName) {
|
|
102
|
+
const processedResponse = this.deepClone(originalResponse);
|
|
453
103
|
const errors = [];
|
|
454
|
-
let
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
let shouldCleanup = false;
|
|
461
|
-
if (storedContent.expiresAt && storedContent.expiresAt < now) {
|
|
462
|
-
shouldCleanup = true;
|
|
463
|
-
storedContent.state = "expired";
|
|
464
|
-
}
|
|
465
|
-
const ageMs = now.getTime() - storedContent.metadata.createdAt.getTime();
|
|
466
|
-
const policy = this.getCleanupPolicy(storedContent.metadata.source);
|
|
467
|
-
if (ageMs > policy.maxAgeMs) {
|
|
468
|
-
shouldCleanup = true;
|
|
469
|
-
}
|
|
470
|
-
if (storedContent.state === "cleanup_pending") {
|
|
471
|
-
shouldCleanup = true;
|
|
472
|
-
}
|
|
473
|
-
if (shouldCleanup) {
|
|
474
|
-
toCleanup.push(referenceId);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
toCleanup.sort((a, b) => {
|
|
478
|
-
const aContent = this.contentStore.get(a);
|
|
479
|
-
const bContent = this.contentStore.get(b);
|
|
480
|
-
const aPriority = this.getCleanupPolicy(aContent.metadata.source).priority;
|
|
481
|
-
const bPriority = this.getCleanupPolicy(bContent.metadata.source).priority;
|
|
482
|
-
return bPriority - aPriority;
|
|
483
|
-
});
|
|
484
|
-
for (const referenceId of toCleanup) {
|
|
104
|
+
let referenceCreated = false;
|
|
105
|
+
let totalReferenceSize = 0;
|
|
106
|
+
for (const contentInfo of analysis.contents) {
|
|
107
|
+
if (this.contentStorage.shouldUseReference(
|
|
108
|
+
typeof contentInfo.content === "string" ? contentInfo.content : JSON.stringify(contentInfo.content)
|
|
109
|
+
)) {
|
|
485
110
|
try {
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
111
|
+
const contentBuffer = Buffer.from(
|
|
112
|
+
typeof contentInfo.content === "string" ? contentInfo.content : JSON.stringify(contentInfo.content),
|
|
113
|
+
"utf8"
|
|
114
|
+
);
|
|
115
|
+
const contentType = this.mapMimeTypeToContentType(contentInfo.mimeType);
|
|
116
|
+
const metadata = {
|
|
117
|
+
contentType,
|
|
118
|
+
source: "mcp_tool",
|
|
119
|
+
mcpToolName: `${serverName}::${toolName}`,
|
|
120
|
+
tags: ["mcp_response", serverName, toolName]
|
|
121
|
+
};
|
|
122
|
+
if (contentInfo.mimeType !== void 0) {
|
|
123
|
+
metadata.mimeType = contentInfo.mimeType;
|
|
489
124
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
cleanedUp++;
|
|
503
|
-
}
|
|
504
|
-
} catch (error) {
|
|
505
|
-
errors.push(`Failed to cleanup excess reference ${referenceId}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
125
|
+
const reference = await this.contentStorage.storeContentIfLarge(
|
|
126
|
+
contentBuffer,
|
|
127
|
+
metadata
|
|
128
|
+
);
|
|
129
|
+
if (reference) {
|
|
130
|
+
this.replaceContentInResponse(
|
|
131
|
+
processedResponse,
|
|
132
|
+
contentInfo.content,
|
|
133
|
+
this.createLightweightReference(reference)
|
|
134
|
+
);
|
|
135
|
+
referenceCreated = true;
|
|
136
|
+
totalReferenceSize += contentBuffer.length;
|
|
506
137
|
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
errors.push(`Failed to create reference: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
507
140
|
}
|
|
508
141
|
}
|
|
509
|
-
const duration = Date.now() - startTime;
|
|
510
|
-
this.recordPerformanceMetric("cleanup", duration);
|
|
511
|
-
console.log(`[ContentStorage] Reference cleanup completed: ${cleanedUp} references cleaned up, ${errors.length} errors`);
|
|
512
|
-
return { cleanedUp, errors };
|
|
513
|
-
} catch (error) {
|
|
514
|
-
const duration = Date.now() - startTime;
|
|
515
|
-
this.recordPerformanceMetric("cleanup", duration);
|
|
516
|
-
const errorMessage = `Cleanup process failed: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
517
|
-
console.error("[ContentStorage]", errorMessage);
|
|
518
|
-
errors.push(errorMessage);
|
|
519
|
-
return { cleanedUp, errors };
|
|
520
142
|
}
|
|
143
|
+
const result = {
|
|
144
|
+
content: processedResponse,
|
|
145
|
+
wasProcessed: true,
|
|
146
|
+
referenceCreated,
|
|
147
|
+
originalSize: totalReferenceSize
|
|
148
|
+
};
|
|
149
|
+
if (errors.length > 0) {
|
|
150
|
+
result.errors = errors;
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
521
153
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
154
|
+
createLightweightReference(reference) {
|
|
155
|
+
return {
|
|
156
|
+
type: "content_reference",
|
|
157
|
+
referenceId: reference.referenceId,
|
|
158
|
+
preview: reference.preview,
|
|
159
|
+
size: reference.metadata.sizeBytes,
|
|
160
|
+
contentType: reference.metadata.contentType,
|
|
161
|
+
format: "ref://{id}",
|
|
162
|
+
_isReference: true
|
|
163
|
+
};
|
|
527
164
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
await this.performCleanup();
|
|
165
|
+
replaceContentInResponse(obj, oldContent, newContent) {
|
|
166
|
+
if (obj === null || obj === void 0) {
|
|
167
|
+
return;
|
|
532
168
|
}
|
|
533
|
-
if (
|
|
534
|
-
|
|
169
|
+
if (Array.isArray(obj)) {
|
|
170
|
+
for (let i = 0; i < obj.length; i++) {
|
|
171
|
+
if (obj[i] === oldContent) {
|
|
172
|
+
obj[i] = newContent;
|
|
173
|
+
} else {
|
|
174
|
+
this.replaceContentInResponse(obj[i], oldContent, newContent);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
535
178
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
case "user_upload":
|
|
546
|
-
return this.referenceConfig.cleanupPolicies.userContent;
|
|
547
|
-
case "agent_generated":
|
|
548
|
-
return this.referenceConfig.cleanupPolicies.agentGenerated;
|
|
549
|
-
default:
|
|
550
|
-
return this.referenceConfig.cleanupPolicies.default;
|
|
179
|
+
if (typeof obj === "object") {
|
|
180
|
+
const record = obj;
|
|
181
|
+
for (const key in record) {
|
|
182
|
+
if (record[key] === oldContent) {
|
|
183
|
+
record[key] = newContent;
|
|
184
|
+
} else {
|
|
185
|
+
this.replaceContentInResponse(record[key], oldContent, newContent);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
551
188
|
}
|
|
552
189
|
}
|
|
553
|
-
|
|
554
|
-
if (
|
|
555
|
-
|
|
556
|
-
if (mimeType === "text/markdown") return "markdown";
|
|
557
|
-
if (mimeType === "application/json") return "json";
|
|
558
|
-
if (mimeType.startsWith("text/")) return "text";
|
|
559
|
-
return "binary";
|
|
190
|
+
detectMimeType(content) {
|
|
191
|
+
if (content.trim().startsWith("{") || content.trim().startsWith("[")) {
|
|
192
|
+
return "application/json";
|
|
560
193
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
if (contentStr.includes("<html>") || contentStr.includes("<!DOCTYPE")) return "html";
|
|
564
|
-
if (contentStr.includes("#") && contentStr.includes("\n")) return "markdown";
|
|
565
|
-
return "text";
|
|
566
|
-
}
|
|
567
|
-
createContentPreview(content, contentType) {
|
|
568
|
-
const maxLength = 200;
|
|
569
|
-
let preview = content.toString("utf8", 0, Math.min(content.length, maxLength * 2));
|
|
570
|
-
if (contentType === "html") {
|
|
571
|
-
preview = preview.replace(/<[^>]*>/g, "").replace(/\s+/g, " ").trim();
|
|
572
|
-
} else if (contentType === "json") {
|
|
573
|
-
try {
|
|
574
|
-
const parsed = JSON.parse(preview);
|
|
575
|
-
preview = JSON.stringify(parsed, null, 0);
|
|
576
|
-
} catch {
|
|
577
|
-
}
|
|
194
|
+
if (content.includes("<html>") || content.includes("<!DOCTYPE")) {
|
|
195
|
+
return "text/html";
|
|
578
196
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
preview = preview.substring(0, maxLength) + "...";
|
|
197
|
+
if (content.includes("# ") || content.includes("## ")) {
|
|
198
|
+
return "text/markdown";
|
|
582
199
|
}
|
|
583
|
-
return
|
|
200
|
+
return "text/plain";
|
|
584
201
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
202
|
+
mapMimeTypeToContentType(mimeType) {
|
|
203
|
+
if (!mimeType) return "text";
|
|
204
|
+
if (mimeType.startsWith("text/plain")) return "text";
|
|
205
|
+
if (mimeType === "application/json") return "json";
|
|
206
|
+
if (mimeType === "text/html") return "html";
|
|
207
|
+
if (mimeType === "text/markdown") return "markdown";
|
|
208
|
+
if (mimeType.startsWith("text/")) return "text";
|
|
209
|
+
return "binary";
|
|
589
210
|
}
|
|
590
|
-
|
|
591
|
-
if (
|
|
592
|
-
|
|
211
|
+
deepClone(obj) {
|
|
212
|
+
if (obj === null || typeof obj !== "object") {
|
|
213
|
+
return obj;
|
|
593
214
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
let maxAccess = 0;
|
|
597
|
-
for (const [referenceId, storedContent] of this.contentStore.entries()) {
|
|
598
|
-
if (storedContent.metadata.accessCount > maxAccess) {
|
|
599
|
-
maxAccess = storedContent.metadata.accessCount;
|
|
600
|
-
mostAccessedId = referenceId;
|
|
601
|
-
}
|
|
215
|
+
if (obj instanceof Date) {
|
|
216
|
+
return new Date(obj.getTime());
|
|
602
217
|
}
|
|
603
|
-
if (
|
|
604
|
-
|
|
605
|
-
} else {
|
|
606
|
-
delete this.referenceStats.mostAccessedReferenceId;
|
|
218
|
+
if (Array.isArray(obj)) {
|
|
219
|
+
return obj.map((item) => this.deepClone(item));
|
|
607
220
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
switch (type) {
|
|
613
|
-
case "creation":
|
|
614
|
-
metrics.creationTimes.push(timeMs);
|
|
615
|
-
if (metrics.creationTimes.length > maxRecords) {
|
|
616
|
-
metrics.creationTimes.shift();
|
|
617
|
-
}
|
|
618
|
-
break;
|
|
619
|
-
case "resolution":
|
|
620
|
-
metrics.resolutionTimes.push(timeMs);
|
|
621
|
-
if (metrics.resolutionTimes.length > maxRecords) {
|
|
622
|
-
metrics.resolutionTimes.shift();
|
|
623
|
-
}
|
|
624
|
-
break;
|
|
625
|
-
case "cleanup":
|
|
626
|
-
metrics.cleanupTimes.push(timeMs);
|
|
627
|
-
if (metrics.cleanupTimes.length > maxRecords) {
|
|
628
|
-
metrics.cleanupTimes.shift();
|
|
629
|
-
}
|
|
630
|
-
break;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
calculateAverage(times) {
|
|
634
|
-
if (times.length === 0) return 0;
|
|
635
|
-
return times.reduce((sum, time) => sum + time, 0) / times.length;
|
|
636
|
-
}
|
|
637
|
-
startReferenceCleanupTimer() {
|
|
638
|
-
this.cleanupTimer = setInterval(async () => {
|
|
639
|
-
try {
|
|
640
|
-
await this.performCleanup();
|
|
641
|
-
} catch (error) {
|
|
642
|
-
console.error("[ContentStorage] Error in scheduled reference cleanup:", error);
|
|
221
|
+
const cloned = {};
|
|
222
|
+
for (const key in obj) {
|
|
223
|
+
if (obj.hasOwnProperty(key)) {
|
|
224
|
+
cloned[key] = this.deepClone(obj[key]);
|
|
643
225
|
}
|
|
644
|
-
}, this.referenceConfig.cleanupIntervalMs);
|
|
645
|
-
}
|
|
646
|
-
/**
|
|
647
|
-
* Clean up resources (enhanced to include reference cleanup)
|
|
648
|
-
*/
|
|
649
|
-
async dispose() {
|
|
650
|
-
if (this.cleanupTimer) {
|
|
651
|
-
clearInterval(this.cleanupTimer);
|
|
652
|
-
delete this.cleanupTimer;
|
|
653
226
|
}
|
|
654
|
-
|
|
655
|
-
this.clear();
|
|
227
|
+
return cloned;
|
|
656
228
|
}
|
|
657
|
-
}
|
|
658
|
-
_ContentStorage.DEFAULT_MAX_STORAGE = 1e3;
|
|
659
|
-
let ContentStorage = _ContentStorage;
|
|
229
|
+
}
|
|
660
230
|
export {
|
|
661
|
-
|
|
231
|
+
MCPContentProcessor
|
|
662
232
|
};
|
|
663
233
|
//# sourceMappingURL=index20.js.map
|