@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,8 +21,8 @@ test.after.always('cleanup', async () => {
|
|
|
21
21
|
test('Claude vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
|
|
22
22
|
const response = await testServer.executeOperation({
|
|
23
23
|
query: `
|
|
24
|
-
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean
|
|
25
|
-
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream
|
|
24
|
+
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean) {
|
|
25
|
+
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream) {
|
|
26
26
|
result
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -30,8 +30,7 @@ test('Claude vendor streaming over subscriptions emits OAI-style deltas', async
|
|
|
30
30
|
variables: {
|
|
31
31
|
text: 'Say hi',
|
|
32
32
|
chatHistory: [{ role: 'user', content: ['Say hi'] }],
|
|
33
|
-
stream: true
|
|
34
|
-
aiStyle: 'Anthropic'
|
|
33
|
+
stream: true
|
|
35
34
|
}
|
|
36
35
|
});
|
|
37
36
|
|
|
@@ -21,8 +21,8 @@ test.after.always('cleanup', async () => {
|
|
|
21
21
|
test('Gemini vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
|
|
22
22
|
const response = await testServer.executeOperation({
|
|
23
23
|
query: `
|
|
24
|
-
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean
|
|
25
|
-
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream
|
|
24
|
+
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean) {
|
|
25
|
+
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream) {
|
|
26
26
|
result
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -30,8 +30,7 @@ test('Gemini vendor streaming over subscriptions emits OAI-style deltas', async
|
|
|
30
30
|
variables: {
|
|
31
31
|
text: 'Say hi',
|
|
32
32
|
chatHistory: [{ role: 'user', content: ['Say hi'] }],
|
|
33
|
-
stream: true
|
|
34
|
-
aiStyle: 'Google'
|
|
33
|
+
stream: true
|
|
35
34
|
}
|
|
36
35
|
});
|
|
37
36
|
|
|
@@ -21,8 +21,8 @@ test.after.always('cleanup', async () => {
|
|
|
21
21
|
test('XAI Grok vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
|
|
22
22
|
const response = await testServer.executeOperation({
|
|
23
23
|
query: `
|
|
24
|
-
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean
|
|
25
|
-
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream
|
|
24
|
+
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean) {
|
|
25
|
+
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream) {
|
|
26
26
|
result
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -30,8 +30,7 @@ test('XAI Grok vendor streaming over subscriptions emits OAI-style deltas', asyn
|
|
|
30
30
|
variables: {
|
|
31
31
|
text: 'Say hi',
|
|
32
32
|
chatHistory: [{ role: 'user', content: ['Say hi'] }],
|
|
33
|
-
stream: true
|
|
34
|
-
aiStyle: 'XAI'
|
|
33
|
+
stream: true
|
|
35
34
|
}
|
|
36
35
|
});
|
|
37
36
|
|
|
@@ -21,8 +21,8 @@ test.after.always('cleanup', async () => {
|
|
|
21
21
|
test('OpenAI vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
|
|
22
22
|
const response = await testServer.executeOperation({
|
|
23
23
|
query: `
|
|
24
|
-
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean
|
|
25
|
-
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream
|
|
24
|
+
query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean) {
|
|
25
|
+
sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream) {
|
|
26
26
|
result
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -30,8 +30,7 @@ test('OpenAI vendor streaming over subscriptions emits OAI-style deltas', async
|
|
|
30
30
|
variables: {
|
|
31
31
|
text: 'Say hi',
|
|
32
32
|
chatHistory: [{ role: 'user', content: ['Say hi'] }],
|
|
33
|
-
stream: true
|
|
34
|
-
aiStyle: 'OpenAI'
|
|
33
|
+
stream: true
|
|
35
34
|
}
|
|
36
35
|
});
|
|
37
36
|
|
|
@@ -63,7 +62,8 @@ test('OpenAI vendor streaming over subscriptions emits OAI-style deltas', async
|
|
|
63
62
|
.filter(Boolean);
|
|
64
63
|
|
|
65
64
|
if (models.length > 0) {
|
|
66
|
-
|
|
65
|
+
// Model could be gpt-4.1, gpt-4, gpt-5, etc. depending on config
|
|
66
|
+
t.truthy(models.find(m => /gpt-4|gpt-5/.test(m)));
|
|
67
67
|
}
|
|
68
68
|
});
|
|
69
69
|
|
|
@@ -500,42 +500,103 @@ test('addFileToCollection should preserve original displayFilename for converted
|
|
|
500
500
|
}
|
|
501
501
|
});
|
|
502
502
|
|
|
503
|
-
|
|
504
|
-
|
|
503
|
+
// Note: Tests that require Redis (adding files to collection) are in integration tests
|
|
504
|
+
// These unit tests only test behavior that doesn't require Redis
|
|
505
|
+
|
|
506
|
+
test('syncAndStripFilesFromChatHistory should leave all files when no contextId', async t => {
|
|
507
|
+
const { syncAndStripFilesFromChatHistory } = await import('../../../lib/fileUtils.js');
|
|
505
508
|
|
|
506
|
-
// Simulate chat history with converted file
|
|
507
|
-
const contextId = `test-sync-converted-${Date.now()}`;
|
|
508
509
|
const chatHistory = [
|
|
509
510
|
{
|
|
510
511
|
role: 'user',
|
|
511
512
|
content: [
|
|
512
513
|
{
|
|
513
|
-
type: '
|
|
514
|
-
url: 'https://example.com/
|
|
515
|
-
|
|
516
|
-
hash: 'hash123'
|
|
514
|
+
type: 'image_url',
|
|
515
|
+
image_url: { url: 'https://example.com/image.jpg' },
|
|
516
|
+
hash: 'somehash'
|
|
517
517
|
}
|
|
518
518
|
]
|
|
519
519
|
}
|
|
520
520
|
];
|
|
521
521
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
522
|
+
// No contextId - should leave files in place
|
|
523
|
+
const { chatHistory: processedHistory } = await syncAndStripFilesFromChatHistory(chatHistory, null, null);
|
|
524
|
+
|
|
525
|
+
t.is(processedHistory[0].content[0].type, 'image_url');
|
|
526
|
+
t.is(processedHistory[0].content[0].image_url.url, 'https://example.com/image.jpg');
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
test('syncAndStripFilesFromChatHistory should leave files when collection is empty', async t => {
|
|
530
|
+
const { syncAndStripFilesFromChatHistory } = await import('../../../lib/fileUtils.js');
|
|
531
|
+
|
|
532
|
+
// Use a unique contextId that won't have any files
|
|
533
|
+
const contextId = `test-empty-${Date.now()}`;
|
|
534
|
+
|
|
535
|
+
const chatHistory = [
|
|
536
|
+
{
|
|
537
|
+
role: 'user',
|
|
538
|
+
content: [
|
|
539
|
+
{
|
|
540
|
+
type: 'image_url',
|
|
541
|
+
image_url: { url: 'https://example.com/image.jpg' },
|
|
542
|
+
hash: 'somehash'
|
|
543
|
+
}
|
|
544
|
+
]
|
|
538
545
|
}
|
|
539
|
-
|
|
546
|
+
];
|
|
547
|
+
|
|
548
|
+
// Empty collection - files should stay in place (not stripped)
|
|
549
|
+
const { chatHistory: processedHistory } = await syncAndStripFilesFromChatHistory(chatHistory, contextId, null);
|
|
550
|
+
|
|
551
|
+
t.is(processedHistory[0].content[0].type, 'image_url');
|
|
552
|
+
t.is(processedHistory[0].content[0].image_url.url, 'https://example.com/image.jpg');
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
test('syncAndStripFilesFromChatHistory should handle empty chat history', async t => {
|
|
556
|
+
const { syncAndStripFilesFromChatHistory } = await import('../../../lib/fileUtils.js');
|
|
557
|
+
|
|
558
|
+
const { chatHistory: result1 } = await syncAndStripFilesFromChatHistory([], 'context', null);
|
|
559
|
+
t.deepEqual(result1, []);
|
|
560
|
+
|
|
561
|
+
const { chatHistory: result2 } = await syncAndStripFilesFromChatHistory(null, 'context', null);
|
|
562
|
+
t.deepEqual(result2, []);
|
|
540
563
|
});
|
|
541
564
|
|
|
565
|
+
test('syncAndStripFilesFromChatHistory should preserve non-file content', async t => {
|
|
566
|
+
const { syncAndStripFilesFromChatHistory } = await import('../../../lib/fileUtils.js');
|
|
567
|
+
|
|
568
|
+
const contextId = `test-preserve-${Date.now()}`;
|
|
569
|
+
|
|
570
|
+
const chatHistory = [
|
|
571
|
+
{
|
|
572
|
+
role: 'user',
|
|
573
|
+
content: [
|
|
574
|
+
{ type: 'text', text: 'Hello world' },
|
|
575
|
+
{
|
|
576
|
+
type: 'image_url',
|
|
577
|
+
image_url: { url: 'https://example.com/image.jpg' },
|
|
578
|
+
hash: 'somehash'
|
|
579
|
+
}
|
|
580
|
+
]
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
role: 'assistant',
|
|
584
|
+
content: 'I see an image'
|
|
585
|
+
}
|
|
586
|
+
];
|
|
587
|
+
|
|
588
|
+
const { chatHistory: processedHistory } = await syncAndStripFilesFromChatHistory(chatHistory, contextId, null);
|
|
589
|
+
|
|
590
|
+
// Text content should be preserved
|
|
591
|
+
t.is(processedHistory[0].content[0].type, 'text');
|
|
592
|
+
t.is(processedHistory[0].content[0].text, 'Hello world');
|
|
593
|
+
|
|
594
|
+
// Image not in collection should be preserved
|
|
595
|
+
t.is(processedHistory[0].content[1].type, 'image_url');
|
|
596
|
+
|
|
597
|
+
// Assistant message should be preserved
|
|
598
|
+
t.is(processedHistory[1].role, 'assistant');
|
|
599
|
+
t.is(processedHistory[1].content, 'I see an image');
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { callPathway } from '../../../lib/pathwayTools.js';
|
|
2
|
-
|
|
3
|
-
export default {
|
|
4
|
-
// The main prompt function that takes the input text and asks to generate a summary.
|
|
5
|
-
prompt: [],
|
|
6
|
-
|
|
7
|
-
inputParameters: {
|
|
8
|
-
model: "oai-gpt41",
|
|
9
|
-
aiStyle: "OpenAI",
|
|
10
|
-
chatHistory: [{role: '', content: []}],
|
|
11
|
-
},
|
|
12
|
-
timeout: 600,
|
|
13
|
-
|
|
14
|
-
executePathway: async ({args, _runAllPrompts, resolver}) => {
|
|
15
|
-
// chatHistory is always passed in complete
|
|
16
|
-
const response = await callPathway('sys_entity_agent', {
|
|
17
|
-
...args,
|
|
18
|
-
chatHistory: args.chatHistory || [],
|
|
19
|
-
stream: false,
|
|
20
|
-
useMemory: false,
|
|
21
|
-
researchMode: true
|
|
22
|
-
}, resolver);
|
|
23
|
-
|
|
24
|
-
return response;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|