@aj-archipelago/cortex 1.4.22 → 1.4.23
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/FILE_SYSTEM_DOCUMENTATION.md +116 -48
- package/config.js +9 -0
- package/lib/fileUtils.js +226 -201
- package/package.json +1 -1
- package/pathways/system/entity/files/sys_read_file_collection.js +13 -11
- package/pathways/system/entity/files/sys_update_file_metadata.js +16 -7
- package/pathways/system/entity/sys_entity_agent.js +8 -6
- package/pathways/system/entity/tools/sys_tool_codingagent.js +4 -4
- package/pathways/system/entity/tools/sys_tool_editfile.js +27 -22
- package/pathways/system/entity/tools/sys_tool_file_collection.js +15 -10
- package/pathways/system/entity/tools/sys_tool_image.js +1 -1
- package/pathways/system/entity/tools/sys_tool_image_gemini.js +1 -1
- package/pathways/system/entity/tools/sys_tool_readfile.js +4 -4
- package/pathways/system/entity/tools/sys_tool_slides_gemini.js +1 -1
- package/pathways/system/entity/tools/sys_tool_video_veo.js +1 -1
- package/pathways/system/entity/tools/sys_tool_view_image.js +10 -5
- package/pathways/system/workspaces/run_workspace_agent.js +4 -1
- package/pathways/video_seedance.js +2 -0
- package/server/executeWorkspace.js +45 -2
- package/server/pathwayResolver.js +18 -0
- package/server/plugins/replicateApiPlugin.js +18 -0
- package/server/typeDef.js +10 -1
- package/test.log +39427 -0
- package/tests/integration/features/tools/fileCollection.test.js +254 -248
- package/tests/integration/features/tools/fileOperations.test.js +131 -81
- package/tests/integration/graphql/async/stream/vendors/claude_streaming.test.js +3 -4
- package/tests/integration/graphql/async/stream/vendors/gemini_streaming.test.js +3 -4
- package/tests/integration/graphql/async/stream/vendors/grok_streaming.test.js +3 -4
- package/tests/integration/graphql/async/stream/vendors/openai_streaming.test.js +5 -5
- package/tests/unit/core/fileCollection.test.js +86 -25
- package/pathways/system/workspaces/run_workspace_research_agent.js +0 -27
|
@@ -21,14 +21,17 @@ test.after.always('cleanup', async () => {
|
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
// Helper to create a test context
|
|
24
|
+
// Helper to create a test context (returns agentContext array)
|
|
25
25
|
const createTestContext = () => {
|
|
26
26
|
const contextId = `test-fileops-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
27
|
-
return
|
|
27
|
+
return {
|
|
28
|
+
contextId,
|
|
29
|
+
agentContext: [{ contextId, contextKey: null, default: true }]
|
|
30
|
+
};
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
// Helper to clean up test data
|
|
31
|
-
const cleanup = async (contextId
|
|
34
|
+
const cleanup = async (contextId) => {
|
|
32
35
|
try {
|
|
33
36
|
const { getRedisClient } = await import('../../../../lib/fileUtils.js');
|
|
34
37
|
const redisClient = await getRedisClient();
|
|
@@ -44,14 +47,14 @@ const cleanup = async (contextId, contextKey = null) => {
|
|
|
44
47
|
// ========== WriteFile Tests ==========
|
|
45
48
|
|
|
46
49
|
test('WriteFile: Write and upload text file', async t => {
|
|
47
|
-
const contextId = createTestContext();
|
|
50
|
+
const { contextId, agentContext } = createTestContext();
|
|
48
51
|
|
|
49
52
|
try {
|
|
50
53
|
const content = 'Hello, world!\nThis is a test file.';
|
|
51
54
|
const filename = 'test.txt';
|
|
52
55
|
|
|
53
56
|
const result = await callPathway('sys_tool_writefile', {
|
|
54
|
-
|
|
57
|
+
agentContext,
|
|
55
58
|
content,
|
|
56
59
|
filename,
|
|
57
60
|
userMessage: 'Writing test file'
|
|
@@ -77,14 +80,14 @@ test('WriteFile: Write and upload text file', async t => {
|
|
|
77
80
|
});
|
|
78
81
|
|
|
79
82
|
test('WriteFile: Write JSON file', async t => {
|
|
80
|
-
const contextId = createTestContext();
|
|
83
|
+
const { contextId, agentContext } = createTestContext();
|
|
81
84
|
|
|
82
85
|
try {
|
|
83
86
|
const content = JSON.stringify({ name: 'Test', value: 42 }, null, 2);
|
|
84
87
|
const filename = 'data.json';
|
|
85
88
|
|
|
86
89
|
const result = await callPathway('sys_tool_writefile', {
|
|
87
|
-
|
|
90
|
+
agentContext,
|
|
88
91
|
content,
|
|
89
92
|
filename,
|
|
90
93
|
userMessage: 'Writing JSON file'
|
|
@@ -110,13 +113,13 @@ test('WriteFile: Write JSON file', async t => {
|
|
|
110
113
|
// ========== ReadFile Tests ==========
|
|
111
114
|
|
|
112
115
|
test('ReadFile: Read entire file', async t => {
|
|
113
|
-
const contextId = createTestContext();
|
|
116
|
+
const { contextId, agentContext } = createTestContext();
|
|
114
117
|
|
|
115
118
|
try {
|
|
116
119
|
// First write a file
|
|
117
120
|
const content = 'Line 1\nLine 2\nLine 3\nLine 4\nLine 5';
|
|
118
121
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
119
|
-
|
|
122
|
+
agentContext,
|
|
120
123
|
content,
|
|
121
124
|
filename: 'readtest.txt',
|
|
122
125
|
userMessage: 'Writing file for read test'
|
|
@@ -135,7 +138,7 @@ test('ReadFile: Read entire file', async t => {
|
|
|
135
138
|
|
|
136
139
|
// Now read it
|
|
137
140
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
138
|
-
|
|
141
|
+
agentContext,
|
|
139
142
|
file: writeParsed.fileId || 'readtest.txt',
|
|
140
143
|
userMessage: 'Reading entire file'
|
|
141
144
|
});
|
|
@@ -151,13 +154,13 @@ test('ReadFile: Read entire file', async t => {
|
|
|
151
154
|
});
|
|
152
155
|
|
|
153
156
|
test('ReadFile: Read line range', async t => {
|
|
154
|
-
const contextId = createTestContext();
|
|
157
|
+
const { contextId, agentContext } = createTestContext();
|
|
155
158
|
|
|
156
159
|
try {
|
|
157
160
|
// First write a file
|
|
158
161
|
const content = 'Line 1\nLine 2\nLine 3\nLine 4\nLine 5';
|
|
159
162
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
160
|
-
|
|
163
|
+
agentContext,
|
|
161
164
|
content,
|
|
162
165
|
filename: 'rangetest.txt',
|
|
163
166
|
userMessage: 'Writing file for range read test'
|
|
@@ -175,7 +178,7 @@ test('ReadFile: Read line range', async t => {
|
|
|
175
178
|
|
|
176
179
|
// Read lines 2-4
|
|
177
180
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
178
|
-
|
|
181
|
+
agentContext,
|
|
179
182
|
file: writeParsed.fileId || 'rangetest.txt',
|
|
180
183
|
startLine: 2,
|
|
181
184
|
endLine: 4,
|
|
@@ -195,7 +198,7 @@ test('ReadFile: Read line range', async t => {
|
|
|
195
198
|
});
|
|
196
199
|
|
|
197
200
|
test('ReadFile: Read with line range limit', async t => {
|
|
198
|
-
const contextId = createTestContext();
|
|
201
|
+
const { contextId, agentContext } = createTestContext();
|
|
199
202
|
|
|
200
203
|
try {
|
|
201
204
|
// Write a large file
|
|
@@ -203,7 +206,7 @@ test('ReadFile: Read with line range limit', async t => {
|
|
|
203
206
|
const content = lines.join('\n');
|
|
204
207
|
|
|
205
208
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
206
|
-
|
|
209
|
+
agentContext,
|
|
207
210
|
content,
|
|
208
211
|
filename: 'largetest.txt',
|
|
209
212
|
userMessage: 'Writing large file'
|
|
@@ -221,7 +224,7 @@ test('ReadFile: Read with line range limit', async t => {
|
|
|
221
224
|
|
|
222
225
|
// Read with endLine limit (first 10 lines)
|
|
223
226
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
224
|
-
|
|
227
|
+
agentContext,
|
|
225
228
|
file: writeParsed.fileId || 'largetest.txt',
|
|
226
229
|
startLine: 1,
|
|
227
230
|
endLine: 10,
|
|
@@ -241,13 +244,13 @@ test('ReadFile: Read with line range limit', async t => {
|
|
|
241
244
|
// ========== EditFileByLine Tests ==========
|
|
242
245
|
|
|
243
246
|
test('EditFileByLine: Replace single line', async t => {
|
|
244
|
-
const contextId = createTestContext();
|
|
247
|
+
const { contextId, agentContext } = createTestContext();
|
|
245
248
|
|
|
246
249
|
try {
|
|
247
250
|
// Write initial file
|
|
248
251
|
const initialContent = 'Line 1\nLine 2\nLine 3\nLine 4\nLine 5';
|
|
249
252
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
250
|
-
|
|
253
|
+
agentContext,
|
|
251
254
|
content: initialContent,
|
|
252
255
|
filename: 'modifytest.txt',
|
|
253
256
|
userMessage: 'Writing file for modify test'
|
|
@@ -269,7 +272,7 @@ test('EditFileByLine: Replace single line', async t => {
|
|
|
269
272
|
|
|
270
273
|
// Modify line 3
|
|
271
274
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
272
|
-
|
|
275
|
+
agentContext,
|
|
273
276
|
file: writeParsed.fileId || 'modifytest.txt',
|
|
274
277
|
startLine: 3,
|
|
275
278
|
endLine: 3,
|
|
@@ -285,7 +288,7 @@ test('EditFileByLine: Replace single line', async t => {
|
|
|
285
288
|
// Read back to verify
|
|
286
289
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
287
290
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
288
|
-
|
|
291
|
+
agentContext,
|
|
289
292
|
file: modifyParsed.fileId || 'modifytest.txt',
|
|
290
293
|
userMessage: 'Reading modified file'
|
|
291
294
|
});
|
|
@@ -300,13 +303,13 @@ test('EditFileByLine: Replace single line', async t => {
|
|
|
300
303
|
});
|
|
301
304
|
|
|
302
305
|
test('EditFileByLine: Replace multiple lines', async t => {
|
|
303
|
-
const contextId = createTestContext();
|
|
306
|
+
const { contextId, agentContext } = createTestContext();
|
|
304
307
|
|
|
305
308
|
try {
|
|
306
309
|
// Write initial file
|
|
307
310
|
const initialContent = 'Line 1\nLine 2\nLine 3\nLine 4\nLine 5';
|
|
308
311
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
309
|
-
|
|
312
|
+
agentContext,
|
|
310
313
|
content: initialContent,
|
|
311
314
|
filename: 'multimodify.txt',
|
|
312
315
|
userMessage: 'Writing file for multi-line modify'
|
|
@@ -324,7 +327,7 @@ test('EditFileByLine: Replace multiple lines', async t => {
|
|
|
324
327
|
|
|
325
328
|
// Replace lines 2-4 with new content
|
|
326
329
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
327
|
-
|
|
330
|
+
agentContext,
|
|
328
331
|
file: writeParsed.fileId || 'multimodify.txt',
|
|
329
332
|
startLine: 2,
|
|
330
333
|
endLine: 4,
|
|
@@ -340,7 +343,7 @@ test('EditFileByLine: Replace multiple lines', async t => {
|
|
|
340
343
|
// Read back to verify
|
|
341
344
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
342
345
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
343
|
-
|
|
346
|
+
agentContext,
|
|
344
347
|
file: modifyParsed.fileId || 'multimodify.txt',
|
|
345
348
|
userMessage: 'Reading modified file'
|
|
346
349
|
});
|
|
@@ -359,13 +362,13 @@ test('EditFileByLine: Replace multiple lines', async t => {
|
|
|
359
362
|
});
|
|
360
363
|
|
|
361
364
|
test('EditFileByLine: Insert content (replace with more lines)', async t => {
|
|
362
|
-
const contextId = createTestContext();
|
|
365
|
+
const { contextId, agentContext } = createTestContext();
|
|
363
366
|
|
|
364
367
|
try {
|
|
365
368
|
// Write initial file
|
|
366
369
|
const initialContent = 'Line 1\nLine 2\nLine 3';
|
|
367
370
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
368
|
-
|
|
371
|
+
agentContext,
|
|
369
372
|
content: initialContent,
|
|
370
373
|
filename: 'inserttest.txt',
|
|
371
374
|
userMessage: 'Writing file for insert test'
|
|
@@ -383,7 +386,7 @@ test('EditFileByLine: Insert content (replace with more lines)', async t => {
|
|
|
383
386
|
|
|
384
387
|
// Replace line 2 with 3 new lines
|
|
385
388
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
386
|
-
|
|
389
|
+
agentContext,
|
|
387
390
|
file: writeParsed.fileId || 'inserttest.txt',
|
|
388
391
|
startLine: 2,
|
|
389
392
|
endLine: 2,
|
|
@@ -400,7 +403,7 @@ test('EditFileByLine: Insert content (replace with more lines)', async t => {
|
|
|
400
403
|
// Read back to verify
|
|
401
404
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
402
405
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
403
|
-
|
|
406
|
+
agentContext,
|
|
404
407
|
file: modifyParsed.fileId || 'inserttest.txt',
|
|
405
408
|
userMessage: 'Reading modified file'
|
|
406
409
|
});
|
|
@@ -420,13 +423,13 @@ test('EditFileByLine: Insert content (replace with more lines)', async t => {
|
|
|
420
423
|
});
|
|
421
424
|
|
|
422
425
|
test('EditFileByLine: Delete content (replace with fewer lines)', async t => {
|
|
423
|
-
const contextId = createTestContext();
|
|
426
|
+
const { contextId, agentContext } = createTestContext();
|
|
424
427
|
|
|
425
428
|
try {
|
|
426
429
|
// Write initial file
|
|
427
430
|
const initialContent = 'Line 1\nLine 2\nLine 3\nLine 4\nLine 5';
|
|
428
431
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
429
|
-
|
|
432
|
+
agentContext,
|
|
430
433
|
content: initialContent,
|
|
431
434
|
filename: 'deletetest.txt',
|
|
432
435
|
userMessage: 'Writing file for delete test'
|
|
@@ -444,7 +447,7 @@ test('EditFileByLine: Delete content (replace with fewer lines)', async t => {
|
|
|
444
447
|
|
|
445
448
|
// Replace lines 2-4 with a single line
|
|
446
449
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
447
|
-
|
|
450
|
+
agentContext,
|
|
448
451
|
file: writeParsed.fileId || 'deletetest.txt',
|
|
449
452
|
startLine: 2,
|
|
450
453
|
endLine: 4,
|
|
@@ -461,7 +464,7 @@ test('EditFileByLine: Delete content (replace with fewer lines)', async t => {
|
|
|
461
464
|
// Read back to verify
|
|
462
465
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
463
466
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
464
|
-
|
|
467
|
+
agentContext,
|
|
465
468
|
file: modifyParsed.fileId || 'deletetest.txt',
|
|
466
469
|
userMessage: 'Reading modified file'
|
|
467
470
|
});
|
|
@@ -479,11 +482,11 @@ test('EditFileByLine: Delete content (replace with fewer lines)', async t => {
|
|
|
479
482
|
});
|
|
480
483
|
|
|
481
484
|
test('EditFileByLine: Error handling - file not found', async t => {
|
|
482
|
-
const contextId = createTestContext();
|
|
485
|
+
const { contextId, agentContext } = createTestContext();
|
|
483
486
|
|
|
484
487
|
try {
|
|
485
488
|
const result = await callPathway('sys_tool_editfile', {
|
|
486
|
-
|
|
489
|
+
agentContext,
|
|
487
490
|
file: 'nonexistent.txt',
|
|
488
491
|
startLine: 1,
|
|
489
492
|
endLine: 1,
|
|
@@ -500,12 +503,12 @@ test('EditFileByLine: Error handling - file not found', async t => {
|
|
|
500
503
|
});
|
|
501
504
|
|
|
502
505
|
test('EditFileByLine: Error handling - invalid line range', async t => {
|
|
503
|
-
const contextId = createTestContext();
|
|
506
|
+
const { contextId, agentContext } = createTestContext();
|
|
504
507
|
|
|
505
508
|
try {
|
|
506
509
|
// Write a file first
|
|
507
510
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
508
|
-
|
|
511
|
+
agentContext,
|
|
509
512
|
content: 'Line 1\nLine 2',
|
|
510
513
|
filename: 'rangetest.txt',
|
|
511
514
|
userMessage: 'Writing test file'
|
|
@@ -523,7 +526,7 @@ test('EditFileByLine: Error handling - invalid line range', async t => {
|
|
|
523
526
|
|
|
524
527
|
// Try invalid range (endLine < startLine)
|
|
525
528
|
const result = await callPathway('sys_tool_editfile', {
|
|
526
|
-
|
|
529
|
+
agentContext,
|
|
527
530
|
file: writeParsed.fileId || 'rangetest.txt',
|
|
528
531
|
startLine: 5,
|
|
529
532
|
endLine: 3,
|
|
@@ -540,13 +543,13 @@ test('EditFileByLine: Error handling - invalid line range', async t => {
|
|
|
540
543
|
});
|
|
541
544
|
|
|
542
545
|
test('EditFileByLine: Works after prior SearchAndReplace edit', async t => {
|
|
543
|
-
const contextId = createTestContext();
|
|
546
|
+
const { contextId, agentContext } = createTestContext();
|
|
544
547
|
|
|
545
548
|
try {
|
|
546
549
|
// Write initial file
|
|
547
550
|
const initialContent = 'Version: v1\nLine2: alpha\nLine3: bravo\nLine4: charlie';
|
|
548
551
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
549
|
-
|
|
552
|
+
agentContext,
|
|
550
553
|
content: initialContent,
|
|
551
554
|
filename: 'smoketest-tools.txt',
|
|
552
555
|
userMessage: 'Writing file for sequential edit test'
|
|
@@ -567,7 +570,7 @@ test('EditFileByLine: Works after prior SearchAndReplace edit', async t => {
|
|
|
567
570
|
|
|
568
571
|
// First edit: SearchAndReplace (changes hash)
|
|
569
572
|
const searchReplaceResult = await callPathway('sys_tool_editfile', {
|
|
570
|
-
|
|
573
|
+
agentContext,
|
|
571
574
|
file: fileId,
|
|
572
575
|
oldString: 'Version: v1',
|
|
573
576
|
newString: 'Version: v2',
|
|
@@ -585,7 +588,7 @@ test('EditFileByLine: Works after prior SearchAndReplace edit', async t => {
|
|
|
585
588
|
|
|
586
589
|
// Second edit: EditFileByLine (should work after hash change)
|
|
587
590
|
const editByLineResult = await callPathway('sys_tool_editfile', {
|
|
588
|
-
|
|
591
|
+
agentContext,
|
|
589
592
|
file: fileId, // Use same fileId - should resolve correctly after hash change
|
|
590
593
|
startLine: 3,
|
|
591
594
|
endLine: 3,
|
|
@@ -601,7 +604,7 @@ test('EditFileByLine: Works after prior SearchAndReplace edit', async t => {
|
|
|
601
604
|
// Verify final content
|
|
602
605
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
603
606
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
604
|
-
|
|
607
|
+
agentContext,
|
|
605
608
|
file: fileId,
|
|
606
609
|
userMessage: 'Reading final file content'
|
|
607
610
|
});
|
|
@@ -616,13 +619,13 @@ test('EditFileByLine: Works after prior SearchAndReplace edit', async t => {
|
|
|
616
619
|
});
|
|
617
620
|
|
|
618
621
|
test('ReadTextFile: Gets fresh content after EditFileByLine', async t => {
|
|
619
|
-
const contextId = createTestContext();
|
|
622
|
+
const { contextId, agentContext } = createTestContext();
|
|
620
623
|
|
|
621
624
|
try {
|
|
622
625
|
// Write initial file
|
|
623
626
|
const initialContent = 'Line1: alpha\nLine2: bravo\nLine3: charlie';
|
|
624
627
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
625
|
-
|
|
628
|
+
agentContext,
|
|
626
629
|
content: initialContent,
|
|
627
630
|
filename: 'read-after-edit.txt',
|
|
628
631
|
userMessage: 'Writing file for read-after-edit test'
|
|
@@ -643,7 +646,7 @@ test('ReadTextFile: Gets fresh content after EditFileByLine', async t => {
|
|
|
643
646
|
|
|
644
647
|
// Edit the file
|
|
645
648
|
const editResult = await callPathway('sys_tool_editfile', {
|
|
646
|
-
|
|
649
|
+
agentContext,
|
|
647
650
|
file: fileId,
|
|
648
651
|
startLine: 2,
|
|
649
652
|
endLine: 2,
|
|
@@ -659,7 +662,7 @@ test('ReadTextFile: Gets fresh content after EditFileByLine', async t => {
|
|
|
659
662
|
|
|
660
663
|
// Read file - should get fresh content (not cached)
|
|
661
664
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
662
|
-
|
|
665
|
+
agentContext,
|
|
663
666
|
file: fileId,
|
|
664
667
|
userMessage: 'Reading file after edit'
|
|
665
668
|
});
|
|
@@ -674,12 +677,12 @@ test('ReadTextFile: Gets fresh content after EditFileByLine', async t => {
|
|
|
674
677
|
});
|
|
675
678
|
|
|
676
679
|
test('EditFileByLine: Error handling - line out of range', async t => {
|
|
677
|
-
const contextId = createTestContext();
|
|
680
|
+
const { contextId, agentContext } = createTestContext();
|
|
678
681
|
|
|
679
682
|
try {
|
|
680
683
|
// Write a file with 2 lines
|
|
681
684
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
682
|
-
|
|
685
|
+
agentContext,
|
|
683
686
|
content: 'Line 1\nLine 2',
|
|
684
687
|
filename: 'rangetest2.txt',
|
|
685
688
|
userMessage: 'Writing test file'
|
|
@@ -697,7 +700,7 @@ test('EditFileByLine: Error handling - line out of range', async t => {
|
|
|
697
700
|
|
|
698
701
|
// Try to modify line 10 (doesn't exist)
|
|
699
702
|
const result = await callPathway('sys_tool_editfile', {
|
|
700
|
-
|
|
703
|
+
agentContext,
|
|
701
704
|
file: writeParsed.fileId || 'rangetest2.txt',
|
|
702
705
|
startLine: 10,
|
|
703
706
|
endLine: 10,
|
|
@@ -716,13 +719,13 @@ test('EditFileByLine: Error handling - line out of range', async t => {
|
|
|
716
719
|
// ========== EditFileBySearchAndReplace Tests ==========
|
|
717
720
|
|
|
718
721
|
test('EditFileBySearchAndReplace: Replace first occurrence', async t => {
|
|
719
|
-
const contextId = createTestContext();
|
|
722
|
+
const { contextId, agentContext } = createTestContext();
|
|
720
723
|
|
|
721
724
|
try {
|
|
722
725
|
// Write initial file
|
|
723
726
|
const initialContent = 'Hello world\nThis is a test\nHello again';
|
|
724
727
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
725
|
-
|
|
728
|
+
agentContext,
|
|
726
729
|
content: initialContent,
|
|
727
730
|
filename: 'searchreplace.txt',
|
|
728
731
|
userMessage: 'Writing file for search replace test'
|
|
@@ -740,7 +743,7 @@ test('EditFileBySearchAndReplace: Replace first occurrence', async t => {
|
|
|
740
743
|
|
|
741
744
|
// Replace first occurrence of "Hello"
|
|
742
745
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
743
|
-
|
|
746
|
+
agentContext,
|
|
744
747
|
file: writeParsed.fileId || 'searchreplace.txt',
|
|
745
748
|
oldString: 'Hello',
|
|
746
749
|
newString: 'Hi',
|
|
@@ -758,7 +761,7 @@ test('EditFileBySearchAndReplace: Replace first occurrence', async t => {
|
|
|
758
761
|
// Read back to verify
|
|
759
762
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
760
763
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
761
|
-
|
|
764
|
+
agentContext,
|
|
762
765
|
file: modifyParsed.fileId || 'searchreplace.txt',
|
|
763
766
|
userMessage: 'Reading modified file'
|
|
764
767
|
});
|
|
@@ -772,13 +775,13 @@ test('EditFileBySearchAndReplace: Replace first occurrence', async t => {
|
|
|
772
775
|
});
|
|
773
776
|
|
|
774
777
|
test('EditFileBySearchAndReplace: Replace all occurrences', async t => {
|
|
775
|
-
const contextId = createTestContext();
|
|
778
|
+
const { contextId, agentContext } = createTestContext();
|
|
776
779
|
|
|
777
780
|
try {
|
|
778
781
|
// Write initial file
|
|
779
782
|
const initialContent = 'Hello world\nThis is a test\nHello again';
|
|
780
783
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
781
|
-
|
|
784
|
+
agentContext,
|
|
782
785
|
content: initialContent,
|
|
783
786
|
filename: 'searchreplaceall.txt',
|
|
784
787
|
userMessage: 'Writing file for search replace all test'
|
|
@@ -796,7 +799,7 @@ test('EditFileBySearchAndReplace: Replace all occurrences', async t => {
|
|
|
796
799
|
|
|
797
800
|
// Replace all occurrences of "Hello"
|
|
798
801
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
799
|
-
|
|
802
|
+
agentContext,
|
|
800
803
|
file: writeParsed.fileId || 'searchreplaceall.txt',
|
|
801
804
|
oldString: 'Hello',
|
|
802
805
|
newString: 'Hi',
|
|
@@ -813,7 +816,7 @@ test('EditFileBySearchAndReplace: Replace all occurrences', async t => {
|
|
|
813
816
|
// Read back to verify
|
|
814
817
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
815
818
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
816
|
-
|
|
819
|
+
agentContext,
|
|
817
820
|
file: modifyParsed.fileId || 'searchreplaceall.txt',
|
|
818
821
|
userMessage: 'Reading modified file'
|
|
819
822
|
});
|
|
@@ -827,13 +830,13 @@ test('EditFileBySearchAndReplace: Replace all occurrences', async t => {
|
|
|
827
830
|
});
|
|
828
831
|
|
|
829
832
|
test('EditFileBySearchAndReplace: Replace multiline string', async t => {
|
|
830
|
-
const contextId = createTestContext();
|
|
833
|
+
const { contextId, agentContext } = createTestContext();
|
|
831
834
|
|
|
832
835
|
try {
|
|
833
836
|
// Write initial file
|
|
834
837
|
const initialContent = 'Line 1\nLine 2\nLine 3\nLine 2\nLine 4';
|
|
835
838
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
836
|
-
|
|
839
|
+
agentContext,
|
|
837
840
|
content: initialContent,
|
|
838
841
|
filename: 'multiline.txt',
|
|
839
842
|
userMessage: 'Writing file for multiline replace test'
|
|
@@ -851,7 +854,7 @@ test('EditFileBySearchAndReplace: Replace multiline string', async t => {
|
|
|
851
854
|
|
|
852
855
|
// Replace multiline string
|
|
853
856
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
854
|
-
|
|
857
|
+
agentContext,
|
|
855
858
|
file: writeParsed.fileId || 'multiline.txt',
|
|
856
859
|
oldString: 'Line 2\nLine 3',
|
|
857
860
|
newString: 'Replaced 2\nReplaced 3',
|
|
@@ -865,7 +868,7 @@ test('EditFileBySearchAndReplace: Replace multiline string', async t => {
|
|
|
865
868
|
// Read back to verify
|
|
866
869
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
867
870
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
868
|
-
|
|
871
|
+
agentContext,
|
|
869
872
|
file: modifyParsed.fileId || 'multiline.txt',
|
|
870
873
|
userMessage: 'Reading modified file'
|
|
871
874
|
});
|
|
@@ -879,12 +882,12 @@ test('EditFileBySearchAndReplace: Replace multiline string', async t => {
|
|
|
879
882
|
});
|
|
880
883
|
|
|
881
884
|
test('EditFileBySearchAndReplace: Error handling - string not found', async t => {
|
|
882
|
-
const contextId = createTestContext();
|
|
885
|
+
const { contextId, agentContext } = createTestContext();
|
|
883
886
|
|
|
884
887
|
try {
|
|
885
888
|
// Write a file
|
|
886
889
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
887
|
-
|
|
890
|
+
agentContext,
|
|
888
891
|
content: 'Line 1\nLine 2',
|
|
889
892
|
filename: 'notfound.txt',
|
|
890
893
|
userMessage: 'Writing test file'
|
|
@@ -902,7 +905,7 @@ test('EditFileBySearchAndReplace: Error handling - string not found', async t =>
|
|
|
902
905
|
|
|
903
906
|
// Try to replace a string that doesn't exist
|
|
904
907
|
const result = await callPathway('sys_tool_editfile', {
|
|
905
|
-
|
|
908
|
+
agentContext,
|
|
906
909
|
file: writeParsed.fileId || 'notfound.txt',
|
|
907
910
|
oldString: 'This string does not exist',
|
|
908
911
|
newString: 'replacement',
|
|
@@ -920,13 +923,13 @@ test('EditFileBySearchAndReplace: Error handling - string not found', async t =>
|
|
|
920
923
|
// ========== Data Integrity Tests ==========
|
|
921
924
|
|
|
922
925
|
test('EditFile: Old file preserved if upload fails (data integrity)', async t => {
|
|
923
|
-
const contextId = createTestContext();
|
|
926
|
+
const { contextId, agentContext } = createTestContext();
|
|
924
927
|
|
|
925
928
|
try {
|
|
926
929
|
// Write initial file
|
|
927
930
|
const initialContent = 'Original content\nLine 2\nLine 3';
|
|
928
931
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
929
|
-
|
|
932
|
+
agentContext,
|
|
930
933
|
content: initialContent,
|
|
931
934
|
filename: 'integrity-test.txt',
|
|
932
935
|
userMessage: 'Writing file for integrity test'
|
|
@@ -948,7 +951,7 @@ test('EditFile: Old file preserved if upload fails (data integrity)', async t =>
|
|
|
948
951
|
// Verify original file is readable
|
|
949
952
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
950
953
|
const readOriginal = await callPathway('sys_tool_readfile', {
|
|
951
|
-
|
|
954
|
+
agentContext,
|
|
952
955
|
file: originalFileId,
|
|
953
956
|
userMessage: 'Reading original file'
|
|
954
957
|
});
|
|
@@ -958,7 +961,7 @@ test('EditFile: Old file preserved if upload fails (data integrity)', async t =>
|
|
|
958
961
|
|
|
959
962
|
// Edit the file (this should upload first, then delete old file)
|
|
960
963
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
961
|
-
|
|
964
|
+
agentContext,
|
|
962
965
|
file: originalFileId,
|
|
963
966
|
startLine: 1,
|
|
964
967
|
endLine: 1,
|
|
@@ -978,7 +981,7 @@ test('EditFile: Old file preserved if upload fails (data integrity)', async t =>
|
|
|
978
981
|
// Verify new file has correct content
|
|
979
982
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
980
983
|
const readModified = await callPathway('sys_tool_readfile', {
|
|
981
|
-
|
|
984
|
+
agentContext,
|
|
982
985
|
file: modifyParsed.fileId || originalFileId,
|
|
983
986
|
userMessage: 'Reading modified file'
|
|
984
987
|
});
|
|
@@ -989,7 +992,7 @@ test('EditFile: Old file preserved if upload fails (data integrity)', async t =>
|
|
|
989
992
|
|
|
990
993
|
// Verify file collection was updated with new URL (proves upload happened first)
|
|
991
994
|
const listResult = await callPathway('sys_tool_file_collection', {
|
|
992
|
-
|
|
995
|
+
agentContext,
|
|
993
996
|
userMessage: 'List files'
|
|
994
997
|
});
|
|
995
998
|
const listParsed = JSON.parse(listResult);
|
|
@@ -1016,13 +1019,13 @@ test('EditFile: Old file preserved if upload fails (data integrity)', async t =>
|
|
|
1016
1019
|
// ========== Serialization Tests ==========
|
|
1017
1020
|
|
|
1018
1021
|
test('EditFile: Concurrent edits are serialized (no race conditions)', async t => {
|
|
1019
|
-
const contextId = createTestContext();
|
|
1022
|
+
const { contextId, agentContext } = createTestContext();
|
|
1020
1023
|
|
|
1021
1024
|
try {
|
|
1022
1025
|
// Write initial file with numbered lines
|
|
1023
1026
|
const initialContent = 'Line 1\nLine 2\nLine 3\nLine 4\nLine 5';
|
|
1024
1027
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
1025
|
-
|
|
1028
|
+
agentContext,
|
|
1026
1029
|
content: initialContent,
|
|
1027
1030
|
filename: 'serialization-test.txt',
|
|
1028
1031
|
userMessage: 'Writing file for serialization test'
|
|
@@ -1092,7 +1095,7 @@ test('EditFile: Concurrent edits are serialized (no race conditions)', async t =
|
|
|
1092
1095
|
|
|
1093
1096
|
// Read the final file content
|
|
1094
1097
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
1095
|
-
|
|
1098
|
+
agentContext,
|
|
1096
1099
|
file: fileId,
|
|
1097
1100
|
userMessage: 'Reading final file after concurrent edits'
|
|
1098
1101
|
});
|
|
@@ -1116,13 +1119,13 @@ test('EditFile: Concurrent edits are serialized (no race conditions)', async t =
|
|
|
1116
1119
|
});
|
|
1117
1120
|
|
|
1118
1121
|
test('EditFile: Sequential edits maintain order (serialization verification)', async t => {
|
|
1119
|
-
const contextId = createTestContext();
|
|
1122
|
+
const { contextId, agentContext } = createTestContext();
|
|
1120
1123
|
|
|
1121
1124
|
try {
|
|
1122
1125
|
// Write initial file
|
|
1123
1126
|
const initialContent = 'Version: 0';
|
|
1124
1127
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
1125
|
-
|
|
1128
|
+
agentContext,
|
|
1126
1129
|
content: initialContent,
|
|
1127
1130
|
filename: 'order-test.txt',
|
|
1128
1131
|
userMessage: 'Writing file for order test'
|
|
@@ -1184,7 +1187,7 @@ test('EditFile: Sequential edits maintain order (serialization verification)', a
|
|
|
1184
1187
|
|
|
1185
1188
|
// Read final content
|
|
1186
1189
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
1187
|
-
|
|
1190
|
+
agentContext,
|
|
1188
1191
|
file: fileId,
|
|
1189
1192
|
userMessage: 'Reading final file'
|
|
1190
1193
|
});
|
|
@@ -1208,12 +1211,12 @@ test('EditFile: Sequential edits maintain order (serialization verification)', a
|
|
|
1208
1211
|
// ========== Integration Tests ==========
|
|
1209
1212
|
|
|
1210
1213
|
test('File Operations: Write, Read, Modify workflow', async t => {
|
|
1211
|
-
const contextId = createTestContext();
|
|
1214
|
+
const { contextId, agentContext } = createTestContext();
|
|
1212
1215
|
|
|
1213
1216
|
try {
|
|
1214
1217
|
// 1. Write a file
|
|
1215
1218
|
const writeResult = await callPathway('sys_tool_writefile', {
|
|
1216
|
-
|
|
1219
|
+
agentContext,
|
|
1217
1220
|
content: 'Initial content\nLine 2\nLine 3',
|
|
1218
1221
|
filename: 'workflow.txt',
|
|
1219
1222
|
userMessage: 'Writing initial file'
|
|
@@ -1234,7 +1237,7 @@ test('File Operations: Write, Read, Modify workflow', async t => {
|
|
|
1234
1237
|
|
|
1235
1238
|
// 2. Read the file
|
|
1236
1239
|
const readResult = await callPathway('sys_tool_readfile', {
|
|
1237
|
-
|
|
1240
|
+
agentContext,
|
|
1238
1241
|
file: fileId,
|
|
1239
1242
|
userMessage: 'Reading file'
|
|
1240
1243
|
});
|
|
@@ -1247,7 +1250,7 @@ test('File Operations: Write, Read, Modify workflow', async t => {
|
|
|
1247
1250
|
|
|
1248
1251
|
// 3. Modify the file
|
|
1249
1252
|
const modifyResult = await callPathway('sys_tool_editfile', {
|
|
1250
|
-
|
|
1253
|
+
agentContext,
|
|
1251
1254
|
file: fileId,
|
|
1252
1255
|
startLine: 2,
|
|
1253
1256
|
endLine: 2,
|
|
@@ -1262,7 +1265,7 @@ test('File Operations: Write, Read, Modify workflow', async t => {
|
|
|
1262
1265
|
|
|
1263
1266
|
// 4. Read again to verify modification
|
|
1264
1267
|
const readResult2 = await callPathway('sys_tool_readfile', {
|
|
1265
|
-
|
|
1268
|
+
agentContext,
|
|
1266
1269
|
file: fileId,
|
|
1267
1270
|
userMessage: 'Reading modified file'
|
|
1268
1271
|
});
|
|
@@ -1276,3 +1279,50 @@ test('File Operations: Write, Read, Modify workflow', async t => {
|
|
|
1276
1279
|
}
|
|
1277
1280
|
});
|
|
1278
1281
|
|
|
1282
|
+
// ========== Backward Compatibility Test ==========
|
|
1283
|
+
|
|
1284
|
+
test('Backward compat: contextId without agentContext still works', async t => {
|
|
1285
|
+
// Test that passing contextId directly (without agentContext) still works
|
|
1286
|
+
// The pathwayResolver should automatically create agentContext from contextId
|
|
1287
|
+
const contextId = `test-backcompat-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
1288
|
+
|
|
1289
|
+
try {
|
|
1290
|
+
const content = 'Backward compatibility test content';
|
|
1291
|
+
const filename = 'backcompat.txt';
|
|
1292
|
+
|
|
1293
|
+
// Use contextId directly instead of agentContext
|
|
1294
|
+
const result = await callPathway('sys_tool_writefile', {
|
|
1295
|
+
contextId, // Legacy format - no agentContext
|
|
1296
|
+
content,
|
|
1297
|
+
filename,
|
|
1298
|
+
userMessage: 'Testing backward compatibility'
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
const parsed = JSON.parse(result);
|
|
1302
|
+
|
|
1303
|
+
// Skip test if file handler is not configured
|
|
1304
|
+
if (!parsed.success && parsed.error?.includes('WHISPER_MEDIA_API_URL')) {
|
|
1305
|
+
t.log('Test skipped - file handler URL not configured');
|
|
1306
|
+
t.pass();
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
t.is(parsed.success, true, 'Write with legacy contextId should succeed');
|
|
1311
|
+
t.is(parsed.filename, filename);
|
|
1312
|
+
t.truthy(parsed.url);
|
|
1313
|
+
|
|
1314
|
+
// Also test read with legacy format
|
|
1315
|
+
const readResult = await callPathway('sys_tool_readfile', {
|
|
1316
|
+
contextId, // Legacy format
|
|
1317
|
+
file: parsed.fileId || filename,
|
|
1318
|
+
userMessage: 'Reading with legacy contextId'
|
|
1319
|
+
});
|
|
1320
|
+
|
|
1321
|
+
const readParsed = JSON.parse(readResult);
|
|
1322
|
+
t.is(readParsed.success, true, 'Read with legacy contextId should succeed');
|
|
1323
|
+
t.is(readParsed.content, content);
|
|
1324
|
+
} finally {
|
|
1325
|
+
await cleanup(contextId);
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
|