@aj-archipelago/cortex 1.4.26 → 1.4.27
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/package.json +1 -1
- package/pathways/system/entity/tools/sys_tool_analyzefile.js +17 -1
- package/pathways/system/entity/tools/sys_tool_image.js +65 -10
- package/pathways/system/entity/tools/sys_tool_image_gemini.js +33 -5
- package/pathways/system/entity/tools/sys_tool_slides_gemini.js +31 -4
- package/pathways/system/entity/tools/sys_tool_video_veo.js +34 -7
- package/tests/integration/features/tools/fileCollection.test.js +88 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aj-archipelago/cortex",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.27",
|
|
4
4
|
"description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -163,7 +163,23 @@ export default {
|
|
|
163
163
|
|
|
164
164
|
// Generate file message content if provided
|
|
165
165
|
if (args.file) {
|
|
166
|
-
|
|
166
|
+
// Use agentContext if available, otherwise fall back to creating it from contextId/contextKey
|
|
167
|
+
const agentContext = args.agentContext || (args.contextId ? [{
|
|
168
|
+
contextId: args.contextId,
|
|
169
|
+
contextKey: args.contextKey || null,
|
|
170
|
+
default: true
|
|
171
|
+
}] : null);
|
|
172
|
+
|
|
173
|
+
if (!agentContext || !Array.isArray(agentContext) || agentContext.length === 0) {
|
|
174
|
+
const errorMessage = `File not found: "${args.file}". agentContext is required to look up files in the collection.`;
|
|
175
|
+
resolver.tool = JSON.stringify({ toolUsed: "vision" });
|
|
176
|
+
return JSON.stringify({
|
|
177
|
+
error: errorMessage,
|
|
178
|
+
recoveryMessage: "The file was not found. Please verify the file exists in the collection or provide a valid file reference."
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const fileContent = await generateFileMessageContent(args.file, agentContext);
|
|
167
183
|
if (!fileContent) {
|
|
168
184
|
const errorMessage = `File not found: "${args.file}". Use ListFileCollection or SearchFileCollection to find available files.`;
|
|
169
185
|
resolver.tool = JSON.stringify({ toolUsed: "vision" });
|
|
@@ -88,6 +88,7 @@ export default {
|
|
|
88
88
|
|
|
89
89
|
executePathway: async ({args, runAllPrompts, resolver}) => {
|
|
90
90
|
const pathwayResolver = resolver;
|
|
91
|
+
const chatId = args.chatId || null;
|
|
91
92
|
|
|
92
93
|
try {
|
|
93
94
|
let model = "replicate-seedream-4";
|
|
@@ -104,8 +105,8 @@ export default {
|
|
|
104
105
|
// Fail early if any provided image cannot be resolved
|
|
105
106
|
const resolvedInputImages = [];
|
|
106
107
|
if (args.inputImages && Array.isArray(args.inputImages)) {
|
|
107
|
-
if (!args.
|
|
108
|
-
throw new Error("
|
|
108
|
+
if (!args.agentContext || !Array.isArray(args.agentContext) || args.agentContext.length === 0) {
|
|
109
|
+
throw new Error("agentContext is required when using the 'inputImages' parameter. Use ListFileCollection or SearchFileCollection to find available files.");
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
// Limit to 3 images maximum
|
|
@@ -175,13 +176,13 @@ export default {
|
|
|
175
176
|
const uploadedGcs = uploadResult.gcs || null;
|
|
176
177
|
const uploadedHash = uploadResult.hash || null;
|
|
177
178
|
|
|
178
|
-
|
|
179
|
+
const imageData = {
|
|
179
180
|
type: 'image',
|
|
180
181
|
url: uploadedUrl,
|
|
181
182
|
gcs: uploadedGcs,
|
|
182
183
|
hash: uploadedHash,
|
|
183
184
|
mimeType: mimeType
|
|
184
|
-
}
|
|
185
|
+
};
|
|
185
186
|
|
|
186
187
|
// Add uploaded image to file collection if contextId is available
|
|
187
188
|
if (args.contextId && uploadedUrl) {
|
|
@@ -205,8 +206,8 @@ export default {
|
|
|
205
206
|
const providedTags = Array.isArray(args.tags) ? args.tags : [];
|
|
206
207
|
const allTags = [...defaultTags, ...providedTags.filter(tag => !defaultTags.includes(tag))];
|
|
207
208
|
|
|
208
|
-
// Use the centralized utility function to add to collection
|
|
209
|
-
await addFileToCollection(
|
|
209
|
+
// Use the centralized utility function to add to collection - capture returned entry
|
|
210
|
+
const fileEntry = await addFileToCollection(
|
|
210
211
|
args.contextId,
|
|
211
212
|
args.contextKey || '',
|
|
212
213
|
uploadedUrl,
|
|
@@ -219,13 +220,19 @@ export default {
|
|
|
219
220
|
uploadedHash,
|
|
220
221
|
null, // fileUrl - not needed since we already uploaded
|
|
221
222
|
pathwayResolver,
|
|
222
|
-
true // permanent => retention=permanent
|
|
223
|
+
true, // permanent => retention=permanent
|
|
224
|
+
chatId
|
|
223
225
|
);
|
|
226
|
+
|
|
227
|
+
// Use the file entry data for the return message
|
|
228
|
+
imageData.fileEntry = fileEntry;
|
|
224
229
|
} catch (collectionError) {
|
|
225
230
|
// Log but don't fail - file collection is optional
|
|
226
231
|
pathwayResolver.logWarning(`Failed to add image to file collection: ${collectionError.message}`);
|
|
227
232
|
}
|
|
228
233
|
}
|
|
234
|
+
|
|
235
|
+
uploadedImages.push(imageData);
|
|
229
236
|
} catch (uploadError) {
|
|
230
237
|
pathwayResolver.logError(`Failed to upload image from Replicate: ${uploadError.message}`);
|
|
231
238
|
// Keep original URL as fallback
|
|
@@ -241,11 +248,59 @@ export default {
|
|
|
241
248
|
}
|
|
242
249
|
}
|
|
243
250
|
|
|
244
|
-
// Return the URLs of the uploaded images
|
|
251
|
+
// Return the URLs of the uploaded images in structured format
|
|
245
252
|
// Replace the result with uploaded cloud URLs (not the original Replicate URLs)
|
|
246
253
|
if (uploadedImages.length > 0) {
|
|
247
|
-
const
|
|
248
|
-
|
|
254
|
+
const successfulImages = uploadedImages.filter(img => img.url);
|
|
255
|
+
if (successfulImages.length > 0) {
|
|
256
|
+
// Build imageUrls array in the format expected by pathwayTools.js for toolImages injection
|
|
257
|
+
// This format matches ViewImages tool so images get properly injected into chat history
|
|
258
|
+
const imageUrls = successfulImages.map((img) => {
|
|
259
|
+
const url = img.fileEntry?.url || img.url;
|
|
260
|
+
const gcs = img.fileEntry?.gcs || img.gcs;
|
|
261
|
+
const hash = img.fileEntry?.hash || img.hash;
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
type: "image_url",
|
|
265
|
+
url: url,
|
|
266
|
+
gcs: gcs || null,
|
|
267
|
+
image_url: { url: url },
|
|
268
|
+
hash: hash || null
|
|
269
|
+
};
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Return image info in the same format as availableFiles for the text message
|
|
273
|
+
// Format: hash | filename | url | date | tags
|
|
274
|
+
const imageList = successfulImages.map((img) => {
|
|
275
|
+
if (img.fileEntry) {
|
|
276
|
+
// Use the file entry data from addFileToCollection
|
|
277
|
+
const fe = img.fileEntry;
|
|
278
|
+
const dateStr = fe.addedDate
|
|
279
|
+
? new Date(fe.addedDate).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
|
|
280
|
+
: '';
|
|
281
|
+
const tagsStr = Array.isArray(fe.tags) ? fe.tags.join(',') : '';
|
|
282
|
+
return `${fe.hash || ''} | ${fe.displayFilename || ''} | ${fe.url || img.url} | ${dateStr} | ${tagsStr}`;
|
|
283
|
+
} else {
|
|
284
|
+
// Fallback if file collection wasn't available
|
|
285
|
+
return `${img.hash || 'unknown'} | | ${img.url} | |`;
|
|
286
|
+
}
|
|
287
|
+
}).join('\n');
|
|
288
|
+
|
|
289
|
+
const count = successfulImages.length;
|
|
290
|
+
const isModification = args.inputImages && Array.isArray(args.inputImages) && args.inputImages.length > 0;
|
|
291
|
+
|
|
292
|
+
// Make the success message very explicit so the agent knows files were created and added to collection
|
|
293
|
+
// This format matches availableFiles so the agent can reference them by hash/filename
|
|
294
|
+
const action = isModification ? 'Image modification' : 'Image generation';
|
|
295
|
+
const message = `${action} completed successfully. ${count} image${count > 1 ? 's have' : ' has'} been generated, uploaded to cloud storage, and added to your file collection. The image${count > 1 ? 's are' : ' is'} now available in your file collection:\n\n${imageList}\n\nYou can reference these images by their hash, filename, or URL in future tool calls.`;
|
|
296
|
+
|
|
297
|
+
// Return JSON object with imageUrls (kept for backward compatibility, but explicit message should prevent looping)
|
|
298
|
+
result = JSON.stringify({
|
|
299
|
+
success: true,
|
|
300
|
+
message: message,
|
|
301
|
+
imageUrls: imageUrls
|
|
302
|
+
});
|
|
303
|
+
}
|
|
249
304
|
}
|
|
250
305
|
}
|
|
251
306
|
}
|
|
@@ -90,6 +90,7 @@ export default {
|
|
|
90
90
|
}],
|
|
91
91
|
executePathway: async ({args, runAllPrompts, resolver}) => {
|
|
92
92
|
const pathwayResolver = resolver;
|
|
93
|
+
const chatId = args.chatId || null;
|
|
93
94
|
|
|
94
95
|
try {
|
|
95
96
|
let model = "gemini-flash-25-image";
|
|
@@ -100,8 +101,8 @@ export default {
|
|
|
100
101
|
// Fail early if any provided image cannot be resolved
|
|
101
102
|
const resolvedInputImages = [];
|
|
102
103
|
if (args.inputImages && Array.isArray(args.inputImages)) {
|
|
103
|
-
if (!args.
|
|
104
|
-
throw new Error("
|
|
104
|
+
if (!args.agentContext || !Array.isArray(args.agentContext) || args.agentContext.length === 0) {
|
|
105
|
+
throw new Error("agentContext is required when using the 'inputImages' parameter. Use ListFileCollection or SearchFileCollection to find available files.");
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
// Limit to 3 images maximum
|
|
@@ -203,7 +204,8 @@ export default {
|
|
|
203
204
|
imageHash,
|
|
204
205
|
null,
|
|
205
206
|
pathwayResolver,
|
|
206
|
-
true // permanent => retention=permanent
|
|
207
|
+
true, // permanent => retention=permanent
|
|
208
|
+
chatId
|
|
207
209
|
);
|
|
208
210
|
|
|
209
211
|
// Use the file entry data for the return message
|
|
@@ -229,7 +231,23 @@ export default {
|
|
|
229
231
|
// Check if we successfully uploaded any images
|
|
230
232
|
const successfulImages = uploadedImages.filter(img => img.url);
|
|
231
233
|
if (successfulImages.length > 0) {
|
|
232
|
-
//
|
|
234
|
+
// Build imageUrls array in the format expected by pathwayTools.js for toolImages injection
|
|
235
|
+
// This format matches ViewImages tool so images get properly injected into chat history
|
|
236
|
+
const imageUrls = successfulImages.map((img) => {
|
|
237
|
+
const url = img.fileEntry?.url || img.url;
|
|
238
|
+
const gcs = img.fileEntry?.gcs || img.gcs;
|
|
239
|
+
const hash = img.fileEntry?.hash || img.hash;
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
type: "image_url",
|
|
243
|
+
url: url,
|
|
244
|
+
gcs: gcs || null,
|
|
245
|
+
image_url: { url: url },
|
|
246
|
+
hash: hash || null
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Return image info in the same format as availableFiles for the text message
|
|
233
251
|
// Format: hash | filename | url | date | tags
|
|
234
252
|
const imageList = successfulImages.map((img) => {
|
|
235
253
|
if (img.fileEntry) {
|
|
@@ -247,7 +265,17 @@ export default {
|
|
|
247
265
|
}).join('\n');
|
|
248
266
|
|
|
249
267
|
const count = successfulImages.length;
|
|
250
|
-
|
|
268
|
+
|
|
269
|
+
// Make the success message very explicit so the agent knows files were created and added to collection
|
|
270
|
+
// This format matches availableFiles so the agent can reference them by hash/filename
|
|
271
|
+
const message = `Image generation completed successfully. ${count} image${count > 1 ? 's have' : ' has'} been generated, uploaded to cloud storage, and added to your file collection. The image${count > 1 ? 's are' : ' is'} now available in your file collection:\n\n${imageList}\n\nYou can reference these images by their hash, filename, or URL in future tool calls.`;
|
|
272
|
+
|
|
273
|
+
// Return JSON object with imageUrls (kept for backward compatibility, but explicit message should prevent looping)
|
|
274
|
+
return JSON.stringify({
|
|
275
|
+
success: true,
|
|
276
|
+
message: message,
|
|
277
|
+
imageUrls: imageUrls
|
|
278
|
+
});
|
|
251
279
|
} else {
|
|
252
280
|
throw new Error('Image generation failed: Images were generated but could not be uploaded to storage');
|
|
253
281
|
}
|
|
@@ -71,8 +71,8 @@ export default {
|
|
|
71
71
|
// Fail early if any provided image cannot be resolved
|
|
72
72
|
const resolvedInputImages = [];
|
|
73
73
|
if (args.inputImages && Array.isArray(args.inputImages)) {
|
|
74
|
-
if (!args.
|
|
75
|
-
throw new Error("
|
|
74
|
+
if (!args.agentContext || !Array.isArray(args.agentContext) || args.agentContext.length === 0) {
|
|
75
|
+
throw new Error("agentContext is required when using the 'inputImages' parameter. Use ListFileCollection or SearchFileCollection to find available files.");
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
// Limit to 3 images maximum
|
|
@@ -210,7 +210,23 @@ export default {
|
|
|
210
210
|
// Check if we successfully uploaded any images
|
|
211
211
|
const successfulImages = uploadedImages.filter(img => img.url);
|
|
212
212
|
if (successfulImages.length > 0) {
|
|
213
|
-
//
|
|
213
|
+
// Build imageUrls array in the format expected by pathwayTools.js for toolImages injection
|
|
214
|
+
// This format matches ViewImages tool so images get properly injected into chat history
|
|
215
|
+
const imageUrls = successfulImages.map((img) => {
|
|
216
|
+
const url = img.fileEntry?.url || img.url;
|
|
217
|
+
const gcs = img.fileEntry?.gcs || img.gcs;
|
|
218
|
+
const hash = img.fileEntry?.hash || img.hash;
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
type: "image_url",
|
|
222
|
+
url: url,
|
|
223
|
+
gcs: gcs || null,
|
|
224
|
+
image_url: { url: url },
|
|
225
|
+
hash: hash || null
|
|
226
|
+
};
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Return image info in the same format as availableFiles for the text message
|
|
214
230
|
// Format: hash | filename | url | date | tags
|
|
215
231
|
const imageList = successfulImages.map((img) => {
|
|
216
232
|
if (img.fileEntry) {
|
|
@@ -228,7 +244,18 @@ export default {
|
|
|
228
244
|
}).join('\n');
|
|
229
245
|
|
|
230
246
|
const count = successfulImages.length;
|
|
231
|
-
|
|
247
|
+
|
|
248
|
+
// Make the success message very explicit so the agent knows files were created and added to collection
|
|
249
|
+
// This format matches availableFiles so the agent can reference them by hash/filename
|
|
250
|
+
const message = `Slide/infographic generation completed successfully. ${count} image${count > 1 ? 's have' : ' has'} been generated, uploaded to cloud storage, and added to your file collection. The image${count > 1 ? 's are' : ' is'} now available in your file collection:\n\n${imageList}\n\nYou can reference these images by their hash, filename, or URL in future tool calls.`;
|
|
251
|
+
|
|
252
|
+
// Return JSON object with imageUrls (kept for backward compatibility, but explicit message should prevent looping)
|
|
253
|
+
// This prevents the agent from looping because it can't see the generated images
|
|
254
|
+
return JSON.stringify({
|
|
255
|
+
success: true,
|
|
256
|
+
message: message,
|
|
257
|
+
imageUrls: imageUrls
|
|
258
|
+
});
|
|
232
259
|
} else {
|
|
233
260
|
throw new Error('Slide generation failed: Content was generated but could not be uploaded to storage');
|
|
234
261
|
}
|
|
@@ -115,6 +115,7 @@ export default {
|
|
|
115
115
|
}],
|
|
116
116
|
executePathway: async ({args, runAllPrompts, resolver}) => {
|
|
117
117
|
const pathwayResolver = resolver;
|
|
118
|
+
const chatId = args.chatId || null;
|
|
118
119
|
|
|
119
120
|
try {
|
|
120
121
|
const model = "veo-3.1-fast-generate";
|
|
@@ -124,8 +125,8 @@ export default {
|
|
|
124
125
|
// Veo requires GCS URLs for input images
|
|
125
126
|
let imageParam = undefined;
|
|
126
127
|
if (args.inputImage) {
|
|
127
|
-
if (!args.
|
|
128
|
-
throw new Error("
|
|
128
|
+
if (!args.agentContext || !Array.isArray(args.agentContext) || args.agentContext.length === 0) {
|
|
129
|
+
throw new Error("agentContext is required when using the 'inputImage' parameter. Use ListFileCollection or SearchFileCollection to find available files.");
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
const resolved = await resolveFileParameter(args.inputImage, args.agentContext, { preferGcs: true });
|
|
@@ -297,7 +298,8 @@ export default {
|
|
|
297
298
|
uploadedHash,
|
|
298
299
|
null,
|
|
299
300
|
pathwayResolver,
|
|
300
|
-
true // permanent => retention=permanent
|
|
301
|
+
true, // permanent => retention=permanent
|
|
302
|
+
chatId
|
|
301
303
|
);
|
|
302
304
|
|
|
303
305
|
// Use the file entry data for the return message
|
|
@@ -323,11 +325,27 @@ export default {
|
|
|
323
325
|
}
|
|
324
326
|
}
|
|
325
327
|
|
|
326
|
-
// Return the URLs of the uploaded videos
|
|
328
|
+
// Return the URLs of the uploaded videos in structured format
|
|
327
329
|
if (uploadedVideos.length > 0) {
|
|
328
330
|
const successfulVideos = uploadedVideos.filter(v => v.url);
|
|
329
331
|
if (successfulVideos.length > 0) {
|
|
330
|
-
//
|
|
332
|
+
// Build imageUrls array in the format expected by pathwayTools.js for toolImages injection
|
|
333
|
+
// Videos can use image_url type since they can be displayed with markdown image syntax
|
|
334
|
+
const imageUrls = successfulVideos.map((vid) => {
|
|
335
|
+
const url = vid.fileEntry?.url || vid.url;
|
|
336
|
+
const gcs = vid.fileEntry?.gcs || vid.gcs;
|
|
337
|
+
const hash = vid.fileEntry?.hash || vid.hash;
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
type: "image_url",
|
|
341
|
+
url: url,
|
|
342
|
+
gcs: gcs || null,
|
|
343
|
+
image_url: { url: url },
|
|
344
|
+
hash: hash || null
|
|
345
|
+
};
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Return video info in the same format as availableFiles for the text message
|
|
331
349
|
// Format: hash | filename | url | date | tags
|
|
332
350
|
const videoList = successfulVideos.map((vid) => {
|
|
333
351
|
if (vid.fileEntry) {
|
|
@@ -345,8 +363,17 @@ export default {
|
|
|
345
363
|
}).join('\n');
|
|
346
364
|
|
|
347
365
|
const count = successfulVideos.length;
|
|
348
|
-
|
|
349
|
-
|
|
366
|
+
|
|
367
|
+
// Make the success message very explicit so the agent knows files were created and added to collection
|
|
368
|
+
// This format matches availableFiles so the agent can reference them by hash/filename
|
|
369
|
+
const message = `Video generation completed successfully. ${count} video${count > 1 ? 's have' : ' has'} been generated, uploaded to cloud storage, and added to your file collection. The video${count > 1 ? 's are' : ' is'} now available in your file collection:\n\n${videoList}\n\nYou can reference these videos by their hash, filename, or URL in future tool calls. Videos can be displayed using markdown image syntax, e.g. `;
|
|
370
|
+
|
|
371
|
+
// Return JSON object with imageUrls (kept for backward compatibility, but explicit message should prevent looping)
|
|
372
|
+
return JSON.stringify({
|
|
373
|
+
success: true,
|
|
374
|
+
message: message,
|
|
375
|
+
imageUrls: imageUrls
|
|
376
|
+
});
|
|
350
377
|
} else {
|
|
351
378
|
// All videos failed to upload
|
|
352
379
|
const errors = uploadedVideos.map(v => v.error).filter(Boolean);
|
|
@@ -1996,6 +1996,94 @@ test('Analyzer tool: Returns error JSON format when file not found', async t =>
|
|
|
1996
1996
|
}
|
|
1997
1997
|
});
|
|
1998
1998
|
|
|
1999
|
+
test('Analyzer tool: Works with legacy contextId/contextKey parameters (backward compatibility)', async t => {
|
|
2000
|
+
const contextId = createTestContext();
|
|
2001
|
+
|
|
2002
|
+
try {
|
|
2003
|
+
// First add a file to the collection
|
|
2004
|
+
await callPathway('sys_tool_file_collection', {
|
|
2005
|
+
agentContext: [{ contextId, contextKey: null, default: true }],
|
|
2006
|
+
url: 'https://example.com/test-document.pdf',
|
|
2007
|
+
filename: 'test-document.pdf',
|
|
2008
|
+
userMessage: 'Add test file for analyzer'
|
|
2009
|
+
});
|
|
2010
|
+
|
|
2011
|
+
// Get the file ID from the collection
|
|
2012
|
+
const collection = await loadFileCollection(contextId, null, false);
|
|
2013
|
+
const fileId = collection[0].id;
|
|
2014
|
+
|
|
2015
|
+
// Test analyzer tool with legacy contextId/contextKey (without agentContext)
|
|
2016
|
+
// This tests that the tool correctly handles backward compatibility
|
|
2017
|
+
const result = await callPathway('sys_tool_analyzefile', {
|
|
2018
|
+
contextId, // Legacy format - no agentContext
|
|
2019
|
+
contextKey: null,
|
|
2020
|
+
file: fileId,
|
|
2021
|
+
detailedInstructions: 'What is this file?',
|
|
2022
|
+
userMessage: 'Testing backward compatibility'
|
|
2023
|
+
});
|
|
2024
|
+
|
|
2025
|
+
t.truthy(result, 'Should have a result');
|
|
2026
|
+
|
|
2027
|
+
// The result should be a string (not an error JSON)
|
|
2028
|
+
// If it's an error, it should be properly formatted
|
|
2029
|
+
let parsedResult;
|
|
2030
|
+
try {
|
|
2031
|
+
parsedResult = JSON.parse(result);
|
|
2032
|
+
// If it parsed as JSON, check if it's an error
|
|
2033
|
+
if (parsedResult.error) {
|
|
2034
|
+
t.fail(`Tool returned error when it should have worked: ${parsedResult.error}`);
|
|
2035
|
+
}
|
|
2036
|
+
} catch (error) {
|
|
2037
|
+
// If it doesn't parse as JSON, that's fine - it's likely the model response
|
|
2038
|
+
t.truthy(typeof result === 'string', 'Result should be a string');
|
|
2039
|
+
}
|
|
2040
|
+
} finally {
|
|
2041
|
+
await cleanup(contextId);
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
2044
|
+
|
|
2045
|
+
test('Analyzer tool: File resolution works with agentContext', async t => {
|
|
2046
|
+
const contextId = createTestContext();
|
|
2047
|
+
|
|
2048
|
+
try {
|
|
2049
|
+
// Add a file to the collection
|
|
2050
|
+
await callPathway('sys_tool_file_collection', {
|
|
2051
|
+
agentContext: [{ contextId, contextKey: null, default: true }],
|
|
2052
|
+
url: 'https://example.com/test-file.pdf',
|
|
2053
|
+
filename: 'test-file.pdf',
|
|
2054
|
+
userMessage: 'Add test file'
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
// Get the file ID from the collection
|
|
2058
|
+
const collection = await loadFileCollection(contextId, null, false);
|
|
2059
|
+
const fileId = collection[0].id;
|
|
2060
|
+
|
|
2061
|
+
// Test analyzer tool with agentContext (modern format)
|
|
2062
|
+
const result = await callPathway('sys_tool_analyzefile', {
|
|
2063
|
+
agentContext: [{ contextId, contextKey: null, default: true }],
|
|
2064
|
+
file: fileId,
|
|
2065
|
+
detailedInstructions: 'What is this file?',
|
|
2066
|
+
userMessage: 'Testing with agentContext'
|
|
2067
|
+
});
|
|
2068
|
+
|
|
2069
|
+
t.truthy(result, 'Should have a result');
|
|
2070
|
+
|
|
2071
|
+
// The result should not be an error
|
|
2072
|
+
let parsedResult;
|
|
2073
|
+
try {
|
|
2074
|
+
parsedResult = JSON.parse(result);
|
|
2075
|
+
if (parsedResult.error) {
|
|
2076
|
+
t.fail(`Tool returned error: ${parsedResult.error}`);
|
|
2077
|
+
}
|
|
2078
|
+
} catch (error) {
|
|
2079
|
+
// If it doesn't parse as JSON, that's fine - it's likely the model response
|
|
2080
|
+
t.truthy(typeof result === 'string', 'Result should be a string');
|
|
2081
|
+
}
|
|
2082
|
+
} finally {
|
|
2083
|
+
await cleanup(contextId);
|
|
2084
|
+
}
|
|
2085
|
+
});
|
|
2086
|
+
|
|
1999
2087
|
// ============================================
|
|
2000
2088
|
// Converted Files Tests (displayFilename != URL extension)
|
|
2001
2089
|
// ============================================
|