@aj-archipelago/cortex 1.3.62 → 1.3.63
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/.github/workflows/cortex-file-handler-test.yml +61 -0
- package/README.md +31 -7
- package/config/default.example.json +15 -0
- package/config.js +133 -12
- package/helper-apps/cortex-autogen2/DigiCertGlobalRootCA.crt.pem +22 -0
- package/helper-apps/cortex-autogen2/Dockerfile +31 -0
- package/helper-apps/cortex-autogen2/Dockerfile.worker +41 -0
- package/helper-apps/cortex-autogen2/README.md +183 -0
- package/helper-apps/cortex-autogen2/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/agents.py +131 -0
- package/helper-apps/cortex-autogen2/docker-compose.yml +20 -0
- package/helper-apps/cortex-autogen2/function_app.py +55 -0
- package/helper-apps/cortex-autogen2/host.json +15 -0
- package/helper-apps/cortex-autogen2/main.py +126 -0
- package/helper-apps/cortex-autogen2/poetry.lock +3652 -0
- package/helper-apps/cortex-autogen2/pyproject.toml +36 -0
- package/helper-apps/cortex-autogen2/requirements.txt +20 -0
- package/helper-apps/cortex-autogen2/send_task.py +105 -0
- package/helper-apps/cortex-autogen2/services/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/services/azure_queue.py +85 -0
- package/helper-apps/cortex-autogen2/services/redis_publisher.py +153 -0
- package/helper-apps/cortex-autogen2/task_processor.py +488 -0
- package/helper-apps/cortex-autogen2/tools/__init__.py +24 -0
- package/helper-apps/cortex-autogen2/tools/azure_blob_tools.py +175 -0
- package/helper-apps/cortex-autogen2/tools/azure_foundry_agents.py +601 -0
- package/helper-apps/cortex-autogen2/tools/coding_tools.py +72 -0
- package/helper-apps/cortex-autogen2/tools/download_tools.py +48 -0
- package/helper-apps/cortex-autogen2/tools/file_tools.py +545 -0
- package/helper-apps/cortex-autogen2/tools/search_tools.py +646 -0
- package/helper-apps/cortex-azure-cleaner/README.md +36 -0
- package/helper-apps/cortex-file-converter/README.md +93 -0
- package/helper-apps/cortex-file-converter/key_to_pdf.py +104 -0
- package/helper-apps/cortex-file-converter/list_blob_extensions.py +89 -0
- package/helper-apps/cortex-file-converter/process_azure_keynotes.py +181 -0
- package/helper-apps/cortex-file-converter/requirements.txt +1 -0
- package/helper-apps/cortex-file-handler/.env.test.azure.ci +7 -0
- package/helper-apps/cortex-file-handler/.env.test.azure.sample +1 -1
- package/helper-apps/cortex-file-handler/.env.test.gcs.ci +10 -0
- package/helper-apps/cortex-file-handler/.env.test.gcs.sample +2 -2
- package/helper-apps/cortex-file-handler/INTERFACE.md +41 -0
- package/helper-apps/cortex-file-handler/package.json +1 -1
- package/helper-apps/cortex-file-handler/scripts/setup-azure-container.js +41 -17
- package/helper-apps/cortex-file-handler/scripts/setup-test-containers.js +30 -15
- package/helper-apps/cortex-file-handler/scripts/test-azure.sh +32 -6
- package/helper-apps/cortex-file-handler/scripts/test-gcs.sh +24 -2
- package/helper-apps/cortex-file-handler/scripts/validate-env.js +128 -0
- package/helper-apps/cortex-file-handler/src/blobHandler.js +161 -51
- package/helper-apps/cortex-file-handler/src/constants.js +3 -0
- package/helper-apps/cortex-file-handler/src/fileChunker.js +10 -8
- package/helper-apps/cortex-file-handler/src/index.js +116 -9
- package/helper-apps/cortex-file-handler/src/redis.js +61 -1
- package/helper-apps/cortex-file-handler/src/services/ConversionService.js +11 -8
- package/helper-apps/cortex-file-handler/src/services/FileConversionService.js +2 -2
- package/helper-apps/cortex-file-handler/src/services/storage/AzureStorageProvider.js +88 -6
- package/helper-apps/cortex-file-handler/src/services/storage/GCSStorageProvider.js +58 -0
- package/helper-apps/cortex-file-handler/src/services/storage/StorageFactory.js +25 -5
- package/helper-apps/cortex-file-handler/src/services/storage/StorageProvider.js +9 -0
- package/helper-apps/cortex-file-handler/src/services/storage/StorageService.js +120 -16
- package/helper-apps/cortex-file-handler/src/start.js +27 -17
- package/helper-apps/cortex-file-handler/tests/FileConversionService.test.js +52 -1
- package/helper-apps/cortex-file-handler/tests/blobHandler.test.js +40 -0
- package/helper-apps/cortex-file-handler/tests/checkHashShortLived.test.js +553 -0
- package/helper-apps/cortex-file-handler/tests/cleanup.test.js +46 -52
- package/helper-apps/cortex-file-handler/tests/containerConversionFlow.test.js +451 -0
- package/helper-apps/cortex-file-handler/tests/containerNameParsing.test.js +229 -0
- package/helper-apps/cortex-file-handler/tests/containerParameterFlow.test.js +392 -0
- package/helper-apps/cortex-file-handler/tests/conversionResilience.test.js +7 -2
- package/helper-apps/cortex-file-handler/tests/deleteOperations.test.js +348 -0
- package/helper-apps/cortex-file-handler/tests/fileChunker.test.js +23 -2
- package/helper-apps/cortex-file-handler/tests/fileUpload.test.js +11 -5
- package/helper-apps/cortex-file-handler/tests/getOperations.test.js +58 -24
- package/helper-apps/cortex-file-handler/tests/postOperations.test.js +11 -4
- package/helper-apps/cortex-file-handler/tests/shortLivedUrlConversion.test.js +225 -0
- package/helper-apps/cortex-file-handler/tests/start.test.js +8 -12
- package/helper-apps/cortex-file-handler/tests/storage/StorageFactory.test.js +80 -0
- package/helper-apps/cortex-file-handler/tests/storage/StorageService.test.js +388 -22
- package/helper-apps/cortex-file-handler/tests/testUtils.helper.js +74 -0
- package/lib/cortexResponse.js +153 -0
- package/lib/entityConstants.js +21 -3
- package/lib/logger.js +21 -4
- package/lib/pathwayTools.js +28 -9
- package/lib/util.js +49 -0
- package/package.json +1 -1
- package/pathways/basePathway.js +1 -0
- package/pathways/bing_afagent.js +54 -1
- package/pathways/call_tools.js +2 -3
- package/pathways/chat_jarvis.js +1 -1
- package/pathways/google_cse.js +27 -0
- package/pathways/grok_live_search.js +18 -0
- package/pathways/system/entity/memory/sys_memory_lookup_required.js +1 -0
- package/pathways/system/entity/memory/sys_memory_required.js +1 -0
- package/pathways/system/entity/memory/sys_search_memory.js +1 -0
- package/pathways/system/entity/sys_entity_agent.js +56 -4
- package/pathways/system/entity/sys_generator_quick.js +1 -0
- package/pathways/system/entity/tools/sys_tool_bing_search_afagent.js +26 -0
- package/pathways/system/entity/tools/sys_tool_google_search.js +141 -0
- package/pathways/system/entity/tools/sys_tool_grok_x_search.js +237 -0
- package/pathways/system/entity/tools/sys_tool_image.js +1 -1
- package/pathways/system/rest_streaming/sys_claude_37_sonnet.js +21 -0
- package/pathways/system/rest_streaming/sys_claude_41_opus.js +21 -0
- package/pathways/system/rest_streaming/sys_claude_4_sonnet.js +21 -0
- package/pathways/system/rest_streaming/sys_google_gemini_25_flash.js +25 -0
- package/pathways/system/rest_streaming/{sys_google_gemini_chat.js → sys_google_gemini_25_pro.js} +6 -4
- package/pathways/system/rest_streaming/sys_grok_4.js +23 -0
- package/pathways/system/rest_streaming/sys_grok_4_fast_non_reasoning.js +23 -0
- package/pathways/system/rest_streaming/sys_grok_4_fast_reasoning.js +23 -0
- package/pathways/system/rest_streaming/sys_openai_chat.js +3 -0
- package/pathways/system/rest_streaming/sys_openai_chat_gpt41.js +22 -0
- package/pathways/system/rest_streaming/sys_openai_chat_gpt41_mini.js +21 -0
- package/pathways/system/rest_streaming/sys_openai_chat_gpt41_nano.js +21 -0
- package/pathways/system/rest_streaming/{sys_claude_35_sonnet.js → sys_openai_chat_gpt4_omni.js} +6 -4
- package/pathways/system/rest_streaming/sys_openai_chat_gpt4_omni_mini.js +21 -0
- package/pathways/system/rest_streaming/{sys_claude_3_haiku.js → sys_openai_chat_gpt5.js} +7 -5
- package/pathways/system/rest_streaming/sys_openai_chat_gpt5_chat.js +21 -0
- package/pathways/system/rest_streaming/sys_openai_chat_gpt5_mini.js +21 -0
- package/pathways/system/rest_streaming/sys_openai_chat_gpt5_nano.js +21 -0
- package/pathways/system/rest_streaming/{sys_openai_chat_o1.js → sys_openai_chat_o3.js} +6 -3
- package/pathways/system/rest_streaming/sys_openai_chat_o3_mini.js +3 -0
- package/pathways/system/workspaces/run_workspace_prompt.js +99 -0
- package/pathways/vision.js +1 -1
- package/server/graphql.js +1 -1
- package/server/modelExecutor.js +8 -0
- package/server/pathwayResolver.js +166 -16
- package/server/pathwayResponseParser.js +16 -8
- package/server/plugins/azureFoundryAgentsPlugin.js +1 -1
- package/server/plugins/claude3VertexPlugin.js +193 -45
- package/server/plugins/gemini15ChatPlugin.js +21 -0
- package/server/plugins/gemini15VisionPlugin.js +360 -0
- package/server/plugins/googleCsePlugin.js +94 -0
- package/server/plugins/grokVisionPlugin.js +365 -0
- package/server/plugins/modelPlugin.js +3 -1
- package/server/plugins/openAiChatPlugin.js +106 -13
- package/server/plugins/openAiVisionPlugin.js +42 -30
- package/server/resolver.js +28 -4
- package/server/rest.js +270 -53
- package/server/typeDef.js +1 -0
- package/tests/{mocks.js → helpers/mocks.js} +5 -2
- package/tests/{server.js → helpers/server.js} +2 -2
- package/tests/helpers/sseAssert.js +23 -0
- package/tests/helpers/sseClient.js +73 -0
- package/tests/helpers/subscriptionAssert.js +11 -0
- package/tests/helpers/subscriptions.js +113 -0
- package/tests/{sublong.srt → integration/features/translate/sublong.srt} +4543 -4543
- package/tests/integration/features/translate/translate_chunking_stream.test.js +100 -0
- package/tests/{translate_srt.test.js → integration/features/translate/translate_srt.test.js} +2 -2
- package/tests/integration/graphql/async/stream/agentic.test.js +477 -0
- package/tests/integration/graphql/async/stream/subscription_streaming.test.js +62 -0
- package/tests/integration/graphql/async/stream/sys_entity_start_streaming.test.js +71 -0
- package/tests/integration/graphql/async/stream/vendors/claude_streaming.test.js +56 -0
- package/tests/integration/graphql/async/stream/vendors/gemini_streaming.test.js +66 -0
- package/tests/integration/graphql/async/stream/vendors/grok_streaming.test.js +56 -0
- package/tests/integration/graphql/async/stream/vendors/openai_streaming.test.js +72 -0
- package/tests/integration/graphql/features/google/sysToolGoogleSearch.test.js +96 -0
- package/tests/integration/graphql/features/grok/grok.test.js +688 -0
- package/tests/integration/graphql/features/grok/grok_x_search_tool.test.js +354 -0
- package/tests/{main.test.js → integration/graphql/features/main.test.js} +1 -1
- package/tests/{call_tools.test.js → integration/graphql/features/tools/call_tools.test.js} +2 -2
- package/tests/{vision.test.js → integration/graphql/features/vision/vision.test.js} +1 -1
- package/tests/integration/graphql/subscriptions/connection.test.js +26 -0
- package/tests/{openai_api.test.js → integration/rest/oai/openai_api.test.js} +63 -238
- package/tests/integration/rest/oai/tool_calling_api.test.js +343 -0
- package/tests/integration/rest/oai/tool_calling_streaming.test.js +85 -0
- package/tests/integration/rest/vendors/claude_streaming.test.js +47 -0
- package/tests/integration/rest/vendors/claude_tool_calling_streaming.test.js +75 -0
- package/tests/integration/rest/vendors/gemini_streaming.test.js +47 -0
- package/tests/integration/rest/vendors/gemini_tool_calling_streaming.test.js +75 -0
- package/tests/integration/rest/vendors/grok_streaming.test.js +55 -0
- package/tests/integration/rest/vendors/grok_tool_calling_streaming.test.js +75 -0
- package/tests/{azureAuthTokenHelper.test.js → unit/core/azureAuthTokenHelper.test.js} +1 -1
- package/tests/{chunkfunction.test.js → unit/core/chunkfunction.test.js} +2 -2
- package/tests/{config.test.js → unit/core/config.test.js} +3 -3
- package/tests/{encodeCache.test.js → unit/core/encodeCache.test.js} +1 -1
- package/tests/{fastLruCache.test.js → unit/core/fastLruCache.test.js} +1 -1
- package/tests/{handleBars.test.js → unit/core/handleBars.test.js} +1 -1
- package/tests/{memoryfunction.test.js → unit/core/memoryfunction.test.js} +2 -2
- package/tests/unit/core/mergeResolver.test.js +952 -0
- package/tests/{parser.test.js → unit/core/parser.test.js} +3 -3
- package/tests/unit/core/pathwayResolver.test.js +187 -0
- package/tests/{requestMonitor.test.js → unit/core/requestMonitor.test.js} +1 -1
- package/tests/{requestMonitorDurationEstimator.test.js → unit/core/requestMonitorDurationEstimator.test.js} +1 -1
- package/tests/{truncateMessages.test.js → unit/core/truncateMessages.test.js} +3 -3
- package/tests/{util.test.js → unit/core/util.test.js} +1 -1
- package/tests/{apptekTranslatePlugin.test.js → unit/plugins/apptekTranslatePlugin.test.js} +3 -3
- package/tests/{azureFoundryAgents.test.js → unit/plugins/azureFoundryAgents.test.js} +136 -1
- package/tests/{claude3VertexPlugin.test.js → unit/plugins/claude3VertexPlugin.test.js} +32 -10
- package/tests/{claude3VertexToolConversion.test.js → unit/plugins/claude3VertexToolConversion.test.js} +3 -3
- package/tests/unit/plugins/googleCsePlugin.test.js +111 -0
- package/tests/unit/plugins/grokVisionPlugin.test.js +1392 -0
- package/tests/{modelPlugin.test.js → unit/plugins/modelPlugin.test.js} +3 -3
- package/tests/{multimodal_conversion.test.js → unit/plugins/multimodal_conversion.test.js} +4 -4
- package/tests/{openAiChatPlugin.test.js → unit/plugins/openAiChatPlugin.test.js} +13 -4
- package/tests/{openAiToolPlugin.test.js → unit/plugins/openAiToolPlugin.test.js} +35 -27
- package/tests/{tokenHandlingTests.test.js → unit/plugins/tokenHandlingTests.test.js} +5 -5
- package/tests/{translate_apptek.test.js → unit/plugins/translate_apptek.test.js} +3 -3
- package/tests/{streaming.test.js → unit/plugins.streaming/plugin_stream_events.test.js} +19 -58
- package/helper-apps/mogrt-handler/tests/test-files/test.gif +0 -1
- package/helper-apps/mogrt-handler/tests/test-files/test.mogrt +0 -1
- package/helper-apps/mogrt-handler/tests/test-files/test.mp4 +0 -1
- package/pathways/system/rest_streaming/sys_openai_chat_gpt4.js +0 -19
- package/pathways/system/rest_streaming/sys_openai_chat_gpt4_32.js +0 -19
- package/pathways/system/rest_streaming/sys_openai_chat_gpt4_turbo.js +0 -19
- package/pathways/system/workspaces/run_claude35_sonnet.js +0 -21
- package/pathways/system/workspaces/run_claude3_haiku.js +0 -20
- package/pathways/system/workspaces/run_gpt35turbo.js +0 -20
- package/pathways/system/workspaces/run_gpt4.js +0 -20
- package/pathways/system/workspaces/run_gpt4_32.js +0 -20
- package/tests/agentic.test.js +0 -256
- package/tests/pathwayResolver.test.js +0 -78
- package/tests/subscription.test.js +0 -387
- /package/tests/{subchunk.srt → integration/features/translate/subchunk.srt} +0 -0
- /package/tests/{subhorizontal.srt → integration/features/translate/subhorizontal.srt} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import * as parser from '
|
|
3
|
-
import * as pathwayTools from '
|
|
4
|
-
import serverFactory from '
|
|
2
|
+
import * as parser from '../../../server/parser.js';
|
|
3
|
+
import * as pathwayTools from '../../../lib/pathwayTools.js';
|
|
4
|
+
import serverFactory from '../../../index.js';
|
|
5
5
|
|
|
6
6
|
let testServer;
|
|
7
7
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { PathwayResolver } from '../../../server/pathwayResolver.js';
|
|
3
|
+
import sinon from 'sinon';
|
|
4
|
+
import { mockConfig, mockPathwayString, mockModelEndpoints } from '../../helpers/mocks.js';
|
|
5
|
+
|
|
6
|
+
const mockPathway = mockPathwayString;
|
|
7
|
+
mockPathway.useInputChunking = false;
|
|
8
|
+
mockPathway.prompt = 'What is AI?';
|
|
9
|
+
|
|
10
|
+
const mockArgs = {
|
|
11
|
+
text: 'Artificial intelligence',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
test.beforeEach((t) => {
|
|
15
|
+
t.context.pathwayResolver = new PathwayResolver({
|
|
16
|
+
config: mockConfig,
|
|
17
|
+
pathway: mockPathway,
|
|
18
|
+
args: mockArgs,
|
|
19
|
+
endpoints: mockModelEndpoints,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('constructor initializes properties correctly', (t) => {
|
|
24
|
+
const resolver = t.context.pathwayResolver;
|
|
25
|
+
t.deepEqual(resolver.config, mockConfig);
|
|
26
|
+
t.deepEqual(resolver.pathway, mockPathway);
|
|
27
|
+
t.deepEqual(resolver.args, mockArgs);
|
|
28
|
+
t.is(resolver.useInputChunking, mockPathway.useInputChunking);
|
|
29
|
+
t.is(typeof resolver.requestId, 'string');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('resolve returns request id when async is true', async (t) => {
|
|
33
|
+
const resolver = t.context.pathwayResolver;
|
|
34
|
+
const requestId = await resolver.resolve({ ...mockArgs, async: true });
|
|
35
|
+
t.is(typeof requestId, 'string');
|
|
36
|
+
t.is(requestId, resolver.requestId);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('resolve calls promptAndParse when async is false', async (t) => {
|
|
40
|
+
const resolver = t.context.pathwayResolver;
|
|
41
|
+
const promptAndParseStub = sinon.stub(resolver, 'promptAndParse').returns(Promise.resolve('test-result'));
|
|
42
|
+
|
|
43
|
+
const result = await resolver.resolve(mockArgs);
|
|
44
|
+
t.true(promptAndParseStub.calledOnce);
|
|
45
|
+
t.is(result, 'test-result');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('processInputText returns input text if no chunking', (t) => {
|
|
49
|
+
const resolver = t.context.pathwayResolver;
|
|
50
|
+
const text = 'This is a test input text';
|
|
51
|
+
const result = resolver.processInputText(text);
|
|
52
|
+
t.deepEqual(result, [text]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('applyPromptsSerially returns result of last prompt', async (t) => {
|
|
56
|
+
const resolver = t.context.pathwayResolver;
|
|
57
|
+
const text = 'This is a test input text';
|
|
58
|
+
const applyPromptStub = sinon.stub(resolver, 'applyPrompt');
|
|
59
|
+
applyPromptStub.onCall(0).returns(Promise.resolve('result1'));
|
|
60
|
+
applyPromptStub.onCall(1).returns(Promise.resolve('result2'));
|
|
61
|
+
|
|
62
|
+
resolver.pathwayPrompt = ['prompt1', 'prompt2'];
|
|
63
|
+
const result = await resolver.applyPromptsSerially(text, mockArgs);
|
|
64
|
+
|
|
65
|
+
t.is(result, 'result2');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('processRequest returns empty result when input text is empty', async (t) => {
|
|
69
|
+
const resolver = t.context.pathwayResolver;
|
|
70
|
+
const text = '';
|
|
71
|
+
const processRequestStub = sinon.stub(resolver, 'processRequest').returns(Promise.resolve(''));
|
|
72
|
+
|
|
73
|
+
await resolver.resolve({ ...mockArgs, text });
|
|
74
|
+
|
|
75
|
+
t.true(processRequestStub.calledOnce);
|
|
76
|
+
const returnValue = await processRequestStub.firstCall.returnValue;
|
|
77
|
+
t.is(returnValue, text);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('swapModel successfully changes model', (t) => {
|
|
81
|
+
const resolver = t.context.pathwayResolver;
|
|
82
|
+
const originalModelName = resolver.modelName;
|
|
83
|
+
const originalModel = resolver.model;
|
|
84
|
+
const originalModelExecutor = resolver.modelExecutor;
|
|
85
|
+
|
|
86
|
+
// Mock the getChunkMaxTokenLength method to avoid complex calculations
|
|
87
|
+
const getChunkMaxTokenLengthStub = sinon.stub(resolver, 'getChunkMaxTokenLength').returns(1000);
|
|
88
|
+
|
|
89
|
+
// Find a different model name from the mock endpoints
|
|
90
|
+
const availableModels = Object.keys(mockModelEndpoints);
|
|
91
|
+
const newModelName = availableModels.find(name => name !== originalModelName) || availableModels[0];
|
|
92
|
+
|
|
93
|
+
resolver.swapModel(newModelName);
|
|
94
|
+
|
|
95
|
+
t.not(resolver.modelName, originalModelName);
|
|
96
|
+
t.is(resolver.modelName, newModelName);
|
|
97
|
+
t.not(resolver.model, originalModel);
|
|
98
|
+
t.is(resolver.model, mockModelEndpoints[newModelName]);
|
|
99
|
+
t.not(resolver.modelExecutor, originalModelExecutor);
|
|
100
|
+
t.true(getChunkMaxTokenLengthStub.calledOnce);
|
|
101
|
+
|
|
102
|
+
getChunkMaxTokenLengthStub.restore();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('swapModel throws error for non-existent model', (t) => {
|
|
106
|
+
const resolver = t.context.pathwayResolver;
|
|
107
|
+
|
|
108
|
+
t.throws(() => {
|
|
109
|
+
resolver.swapModel('non-existent-model');
|
|
110
|
+
}, { message: 'Model non-existent-model not found in config' });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('swapModel logs warning about model change', (t) => {
|
|
114
|
+
const resolver = t.context.pathwayResolver;
|
|
115
|
+
const logWarningStub = sinon.stub(resolver, 'logWarning');
|
|
116
|
+
|
|
117
|
+
// Find a different model name from the mock endpoints
|
|
118
|
+
const availableModels = Object.keys(mockModelEndpoints);
|
|
119
|
+
const newModelName = availableModels.find(name => name !== resolver.modelName) || availableModels[0];
|
|
120
|
+
|
|
121
|
+
resolver.swapModel(newModelName);
|
|
122
|
+
|
|
123
|
+
t.true(logWarningStub.calledWith(`Model swapped to ${newModelName}`));
|
|
124
|
+
|
|
125
|
+
logWarningStub.restore();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('promptAndParse swaps model when model is specified in args', async (t) => {
|
|
129
|
+
const resolver = t.context.pathwayResolver;
|
|
130
|
+
const swapModelStub = sinon.stub(resolver, 'swapModel');
|
|
131
|
+
const processRequestStub = sinon.stub(resolver, 'processRequest').returns(Promise.resolve('test result'));
|
|
132
|
+
|
|
133
|
+
// Mock the response parser to return the result directly
|
|
134
|
+
const parseStub = sinon.stub(resolver.responseParser, 'parse').returns(Promise.resolve('test result'));
|
|
135
|
+
|
|
136
|
+
const argsWithModel = { ...mockArgs, modelOverride: 'anotherModel' };
|
|
137
|
+
|
|
138
|
+
await resolver.promptAndParse(argsWithModel);
|
|
139
|
+
|
|
140
|
+
t.true(swapModelStub.calledWith('anotherModel'));
|
|
141
|
+
|
|
142
|
+
swapModelStub.restore();
|
|
143
|
+
processRequestStub.restore();
|
|
144
|
+
parseStub.restore();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('promptAndParse does not swap model when model is same as current', async (t) => {
|
|
148
|
+
const resolver = t.context.pathwayResolver;
|
|
149
|
+
const swapModelStub = sinon.stub(resolver, 'swapModel');
|
|
150
|
+
const processRequestStub = sinon.stub(resolver, 'processRequest').returns(Promise.resolve('test result'));
|
|
151
|
+
|
|
152
|
+
// Mock the response parser to return the result directly
|
|
153
|
+
const parseStub = sinon.stub(resolver.responseParser, 'parse').returns(Promise.resolve('test result'));
|
|
154
|
+
|
|
155
|
+
const argsWithSameModel = { ...mockArgs, model: resolver.modelName };
|
|
156
|
+
|
|
157
|
+
await resolver.promptAndParse(argsWithSameModel);
|
|
158
|
+
|
|
159
|
+
t.false(swapModelStub.called);
|
|
160
|
+
|
|
161
|
+
swapModelStub.restore();
|
|
162
|
+
processRequestStub.restore();
|
|
163
|
+
parseStub.restore();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('promptAndParse handles model swap errors gracefully', async (t) => {
|
|
167
|
+
const resolver = t.context.pathwayResolver;
|
|
168
|
+
const logErrorStub = sinon.stub(resolver, 'logError');
|
|
169
|
+
const processRequestStub = sinon.stub(resolver, 'processRequest').returns(Promise.resolve('test result'));
|
|
170
|
+
|
|
171
|
+
// Mock the response parser to return the result directly
|
|
172
|
+
const parseStub = sinon.stub(resolver.responseParser, 'parse').returns(Promise.resolve('test result'));
|
|
173
|
+
|
|
174
|
+
// Mock swapModel to throw an error
|
|
175
|
+
const swapModelStub = sinon.stub(resolver, 'swapModel').throws(new Error('Model not found'));
|
|
176
|
+
|
|
177
|
+
const argsWithInvalidModel = { ...mockArgs, modelOverride: 'invalidModel' };
|
|
178
|
+
|
|
179
|
+
await resolver.promptAndParse(argsWithInvalidModel);
|
|
180
|
+
|
|
181
|
+
t.true(logErrorStub.calledWith('Failed to swap model to invalidModel: Model not found'));
|
|
182
|
+
|
|
183
|
+
swapModelStub.restore();
|
|
184
|
+
logErrorStub.restore();
|
|
185
|
+
processRequestStub.restore();
|
|
186
|
+
parseStub.restore();
|
|
187
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import RequestMonitor from '
|
|
2
|
+
import RequestMonitor from '../../../lib/requestMonitor.js'; // replace with actual path
|
|
3
3
|
|
|
4
4
|
test('RequestMonitor: startCall', t => {
|
|
5
5
|
const rm = new RequestMonitor();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// ModelPlugin.test.js
|
|
2
2
|
import test from 'ava';
|
|
3
|
-
import ModelPlugin from '
|
|
4
|
-
import { encode } from '
|
|
5
|
-
import { mockPathwayResolverString } from '
|
|
3
|
+
import ModelPlugin from '../../../server/plugins/modelPlugin.js';
|
|
4
|
+
import { encode } from '../../../lib/encodeCache.js';
|
|
5
|
+
import { mockPathwayResolverString } from '../../helpers/mocks.js';
|
|
6
6
|
|
|
7
7
|
const { config, pathway, modelName, model } = mockPathwayResolverString;
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Tests for utility functions in cortex/lib/util.js
|
|
3
3
|
|
|
4
4
|
import test from 'ava';
|
|
5
|
-
import { removeOldImageAndFileContent } from '
|
|
5
|
+
import { removeOldImageAndFileContent } from '../../../lib/util.js';
|
|
6
6
|
|
|
7
7
|
// Test removeOldImageAndFileContent function
|
|
8
8
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
2
|
import sinon from 'sinon';
|
|
3
|
-
import ApptekTranslatePlugin from '
|
|
4
|
-
import { config } from '
|
|
5
|
-
import * as pathwayTools from '
|
|
3
|
+
import ApptekTranslatePlugin from '../../../server/plugins/apptekTranslatePlugin.js';
|
|
4
|
+
import { config } from '../../../config.js';
|
|
5
|
+
import * as pathwayTools from '../../../lib/pathwayTools.js';
|
|
6
6
|
|
|
7
7
|
// Mock pathway and model
|
|
8
8
|
const mockPathway = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// azureFoundryAgents.test.js
|
|
2
2
|
import test from 'ava';
|
|
3
|
-
import AzureFoundryAgentsPlugin from '
|
|
3
|
+
import AzureFoundryAgentsPlugin from '../../../server/plugins/azureFoundryAgentsPlugin.js';
|
|
4
4
|
|
|
5
5
|
test.beforeEach(t => {
|
|
6
6
|
const mockPathway = {
|
|
@@ -87,6 +87,141 @@ test('should create correct request parameters', t => {
|
|
|
87
87
|
t.is(result.stream, false);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
test('should use custom instructions from parameters', t => {
|
|
91
|
+
const { plugin } = t.context;
|
|
92
|
+
const text = 'Hello, can you help me?';
|
|
93
|
+
const customInstructions = 'You are a specialized search agent.';
|
|
94
|
+
const parameters = {
|
|
95
|
+
stream: false,
|
|
96
|
+
instructions: customInstructions
|
|
97
|
+
};
|
|
98
|
+
const prompt = {
|
|
99
|
+
context: 'You are helpful.',
|
|
100
|
+
examples: [],
|
|
101
|
+
messages: [{ role: 'user', content: text }]
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
plugin.baseUrl = 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry';
|
|
105
|
+
plugin.assistantId = 'asst_testid';
|
|
106
|
+
const result = plugin.getRequestParameters(text, parameters, prompt);
|
|
107
|
+
|
|
108
|
+
t.is(result.instructions, customInstructions);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('should use custom tools from parameters', t => {
|
|
112
|
+
const { plugin } = t.context;
|
|
113
|
+
const text = 'Hello, can you help me?';
|
|
114
|
+
const customTools = [
|
|
115
|
+
{
|
|
116
|
+
type: "bing_grounding",
|
|
117
|
+
bing_grounding: {
|
|
118
|
+
search_configurations: [
|
|
119
|
+
{
|
|
120
|
+
connection_id: "test-connection-id",
|
|
121
|
+
count: 10,
|
|
122
|
+
freshness: "day",
|
|
123
|
+
market: "en-us",
|
|
124
|
+
set_lang: "en"
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
];
|
|
130
|
+
const parameters = {
|
|
131
|
+
stream: false,
|
|
132
|
+
tools: customTools
|
|
133
|
+
};
|
|
134
|
+
const prompt = {
|
|
135
|
+
context: 'You are helpful.',
|
|
136
|
+
examples: [],
|
|
137
|
+
messages: [{ role: 'user', content: text }]
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
plugin.baseUrl = 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry';
|
|
141
|
+
plugin.assistantId = 'asst_testid';
|
|
142
|
+
const result = plugin.getRequestParameters(text, parameters, prompt);
|
|
143
|
+
|
|
144
|
+
t.deepEqual(result.tools, customTools);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('should use custom parallel_tool_calls from parameters', t => {
|
|
148
|
+
const { plugin } = t.context;
|
|
149
|
+
const text = 'Hello, can you help me?';
|
|
150
|
+
const parameters = {
|
|
151
|
+
stream: false,
|
|
152
|
+
parallel_tool_calls: false
|
|
153
|
+
};
|
|
154
|
+
const prompt = {
|
|
155
|
+
context: 'You are helpful.',
|
|
156
|
+
examples: [],
|
|
157
|
+
messages: [{ role: 'user', content: text }]
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
plugin.baseUrl = 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry';
|
|
161
|
+
plugin.assistantId = 'asst_testid';
|
|
162
|
+
const result = plugin.getRequestParameters(text, parameters, prompt);
|
|
163
|
+
|
|
164
|
+
t.is(result.parallel_tool_calls, false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('should not include tools or parallel_tool_calls when not provided', t => {
|
|
168
|
+
const { plugin } = t.context;
|
|
169
|
+
const text = 'Hello, can you help me?';
|
|
170
|
+
const parameters = { stream: false };
|
|
171
|
+
const prompt = {
|
|
172
|
+
context: 'You are helpful.',
|
|
173
|
+
examples: [],
|
|
174
|
+
messages: [{ role: 'user', content: text }]
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
plugin.baseUrl = 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry';
|
|
178
|
+
plugin.assistantId = 'asst_testid';
|
|
179
|
+
const result = plugin.getRequestParameters(text, parameters, prompt);
|
|
180
|
+
|
|
181
|
+
t.falsy(result.tools);
|
|
182
|
+
t.falsy(result.parallel_tool_calls);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('should handle Bing grounding tools with custom search parameters', t => {
|
|
186
|
+
const { plugin } = t.context;
|
|
187
|
+
const text = 'Hello, can you help me?';
|
|
188
|
+
const customTools = [
|
|
189
|
+
{
|
|
190
|
+
type: "bing_grounding",
|
|
191
|
+
bing_grounding: {
|
|
192
|
+
search_configurations: [
|
|
193
|
+
{
|
|
194
|
+
connection_id: "test-connection-id",
|
|
195
|
+
count: 10,
|
|
196
|
+
freshness: "day",
|
|
197
|
+
market: "en-gb",
|
|
198
|
+
set_lang: "en"
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
];
|
|
204
|
+
const parameters = {
|
|
205
|
+
stream: false,
|
|
206
|
+
tools: customTools
|
|
207
|
+
};
|
|
208
|
+
const prompt = {
|
|
209
|
+
context: 'You are helpful.',
|
|
210
|
+
examples: [],
|
|
211
|
+
messages: [{ role: 'user', content: text }]
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
plugin.baseUrl = 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry';
|
|
215
|
+
plugin.assistantId = 'asst_testid';
|
|
216
|
+
const result = plugin.getRequestParameters(text, parameters, prompt);
|
|
217
|
+
|
|
218
|
+
t.deepEqual(result.tools, customTools);
|
|
219
|
+
t.is(result.tools[0].bing_grounding.search_configurations[0].count, 10);
|
|
220
|
+
t.is(result.tools[0].bing_grounding.search_configurations[0].freshness, "day");
|
|
221
|
+
t.is(result.tools[0].bing_grounding.search_configurations[0].market, "en-gb");
|
|
222
|
+
t.is(result.tools[0].bing_grounding.search_configurations[0].set_lang, "en");
|
|
223
|
+
});
|
|
224
|
+
|
|
90
225
|
test('should parse completed run response', t => {
|
|
91
226
|
const { plugin } = t.context;
|
|
92
227
|
const mockResponse = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import Claude3VertexPlugin from '
|
|
3
|
-
import { mockPathwayResolverMessages } from '
|
|
4
|
-
import { config } from '
|
|
2
|
+
import Claude3VertexPlugin from '../../../server/plugins/claude3VertexPlugin.js';
|
|
3
|
+
import { mockPathwayResolverMessages } from '../../helpers/mocks.js';
|
|
4
|
+
import { config } from '../../../config.js';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
|
|
@@ -137,26 +137,48 @@ test('getRequestParameters with long message in chatHistory', async (t) => {
|
|
|
137
137
|
test('parseResponse', (t) => {
|
|
138
138
|
const plugin = new Claude3VertexPlugin(pathway, model);
|
|
139
139
|
|
|
140
|
+
// Test text content response
|
|
140
141
|
const dataWithTextContent = {
|
|
141
142
|
content: [
|
|
142
143
|
{ type: 'text', text: 'Hello, World!' }
|
|
143
|
-
]
|
|
144
|
+
],
|
|
145
|
+
usage: { input_tokens: 10, output_tokens: 5 },
|
|
146
|
+
stop_reason: 'end_turn'
|
|
144
147
|
};
|
|
145
148
|
const resultWithTextContent = plugin.parseResponse(dataWithTextContent);
|
|
146
|
-
t.
|
|
149
|
+
t.truthy(resultWithTextContent.output_text === 'Hello, World!');
|
|
150
|
+
t.truthy(resultWithTextContent.finishReason === 'stop');
|
|
151
|
+
t.truthy(resultWithTextContent.usage);
|
|
152
|
+
t.truthy(resultWithTextContent.metadata.model === plugin.modelName);
|
|
147
153
|
|
|
148
|
-
|
|
154
|
+
// Test tool calls response
|
|
155
|
+
const dataWithToolCalls = {
|
|
149
156
|
content: [
|
|
150
|
-
{
|
|
151
|
-
|
|
157
|
+
{
|
|
158
|
+
type: 'tool_use',
|
|
159
|
+
id: 'tool_1',
|
|
160
|
+
name: 'search_web',
|
|
161
|
+
input: { query: 'test search' }
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
usage: { input_tokens: 15, output_tokens: 8 },
|
|
165
|
+
stop_reason: 'tool_use'
|
|
152
166
|
};
|
|
153
|
-
const
|
|
154
|
-
t.
|
|
167
|
+
const resultWithToolCalls = plugin.parseResponse(dataWithToolCalls);
|
|
168
|
+
t.truthy(resultWithToolCalls.output_text === '');
|
|
169
|
+
t.truthy(resultWithToolCalls.finishReason === 'tool_calls');
|
|
170
|
+
t.truthy(resultWithToolCalls.toolCalls);
|
|
171
|
+
t.truthy(resultWithToolCalls.toolCalls.length === 1);
|
|
172
|
+
t.truthy(resultWithToolCalls.toolCalls[0].id === 'tool_1');
|
|
173
|
+
t.truthy(resultWithToolCalls.toolCalls[0].function.name === 'search_web');
|
|
174
|
+
t.truthy(resultWithToolCalls.toolCalls[0].function.arguments === '{"query":"test search"}');
|
|
155
175
|
|
|
176
|
+
// Test data without content (should return original data)
|
|
156
177
|
const dataWithoutContent = {};
|
|
157
178
|
const resultWithoutContent = plugin.parseResponse(dataWithoutContent);
|
|
158
179
|
t.deepEqual(resultWithoutContent, dataWithoutContent);
|
|
159
180
|
|
|
181
|
+
// Test null data (should return null)
|
|
160
182
|
const dataNull = null;
|
|
161
183
|
const resultNull = plugin.parseResponse(dataNull);
|
|
162
184
|
t.is(resultNull, dataNull);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import Claude3VertexPlugin from '
|
|
3
|
-
import { mockPathwayResolverMessages } from '
|
|
4
|
-
import { config } from '
|
|
2
|
+
import Claude3VertexPlugin from '../../../server/plugins/claude3VertexPlugin.js';
|
|
3
|
+
import { mockPathwayResolverMessages } from '../../helpers/mocks.js';
|
|
4
|
+
import { config } from '../../../config.js';
|
|
5
5
|
|
|
6
6
|
const { pathway, modelName, model } = mockPathwayResolverMessages;
|
|
7
7
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
|
|
4
|
+
const mockPathway = {
|
|
5
|
+
name: 'google_cse',
|
|
6
|
+
temperature: 0.0,
|
|
7
|
+
prompt: '',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const mockModel = {
|
|
11
|
+
name: 'google-cse',
|
|
12
|
+
type: 'GOOGLE-CSE',
|
|
13
|
+
url: 'https://www.googleapis.com/customsearch/v1',
|
|
14
|
+
headers: { 'Content-Type': 'application/json' },
|
|
15
|
+
requestsPerSecond: 10,
|
|
16
|
+
maxTokenLength: 200000,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
test.beforeEach(async t => {
|
|
20
|
+
t.context.sandbox = sinon.createSandbox();
|
|
21
|
+
t.context.originalEnv = { ...process.env };
|
|
22
|
+
process.env.OPENAI_API_KEY = 'test-openai-key';
|
|
23
|
+
process.env.GOOGLE_CSE_KEY = 'test-google-key';
|
|
24
|
+
process.env.GOOGLE_CSE_CX = 'test-google-cx';
|
|
25
|
+
const module = await import('../../../server/plugins/googleCsePlugin.js');
|
|
26
|
+
const GoogleCsePlugin = module.default;
|
|
27
|
+
t.context.plugin = new GoogleCsePlugin(mockPathway, mockModel);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test.afterEach.always(t => {
|
|
31
|
+
t.context.sandbox.restore();
|
|
32
|
+
process.env = t.context.originalEnv;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('getRequestParameters builds query params correctly', t => {
|
|
36
|
+
const { plugin } = t.context;
|
|
37
|
+
const text = 'pokemon';
|
|
38
|
+
const parameters = {
|
|
39
|
+
q: 'pokemon cards',
|
|
40
|
+
num: 5,
|
|
41
|
+
start: 2,
|
|
42
|
+
safe: 'active',
|
|
43
|
+
dateRestrict: 'w1',
|
|
44
|
+
siteSearch: 'example.com',
|
|
45
|
+
siteSearchFilter: 'i',
|
|
46
|
+
searchType: 'image',
|
|
47
|
+
gl: 'us',
|
|
48
|
+
hl: 'en',
|
|
49
|
+
lr: 'lang_en',
|
|
50
|
+
sort: 'date',
|
|
51
|
+
exactTerms: 'pikachu',
|
|
52
|
+
excludeTerms: 'fake',
|
|
53
|
+
orTerms: 'deck,booster',
|
|
54
|
+
fileType: 'pdf',
|
|
55
|
+
cx: 'override-cx',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const result = plugin.getRequestParameters(text, parameters, {});
|
|
59
|
+
|
|
60
|
+
t.deepEqual(result, {
|
|
61
|
+
data: [],
|
|
62
|
+
params: {
|
|
63
|
+
key: 'test-google-key',
|
|
64
|
+
cx: 'override-cx',
|
|
65
|
+
q: 'pokemon cards',
|
|
66
|
+
num: 5,
|
|
67
|
+
start: 2,
|
|
68
|
+
safe: 'active',
|
|
69
|
+
dateRestrict: 'w1',
|
|
70
|
+
siteSearch: 'example.com',
|
|
71
|
+
siteSearchFilter: 'i',
|
|
72
|
+
searchType: 'image',
|
|
73
|
+
gl: 'us',
|
|
74
|
+
hl: 'en',
|
|
75
|
+
lr: 'lang_en',
|
|
76
|
+
sort: 'date',
|
|
77
|
+
exactTerms: 'pikachu',
|
|
78
|
+
excludeTerms: 'fake',
|
|
79
|
+
orTerms: 'deck,booster',
|
|
80
|
+
fileType: 'pdf',
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('execute sets method GET and calls executeRequest', async t => {
|
|
86
|
+
const { plugin } = t.context;
|
|
87
|
+
const spy = t.context.sandbox.stub(plugin, 'executeRequest').resolves('{"items": []}');
|
|
88
|
+
|
|
89
|
+
const cortexRequest = {
|
|
90
|
+
data: null,
|
|
91
|
+
params: null,
|
|
92
|
+
method: null,
|
|
93
|
+
url: mockModel.url,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const res = await plugin.execute('pokemon', { q: 'pokemon' }, {}, cortexRequest);
|
|
97
|
+
|
|
98
|
+
t.is(res, '{"items": []}');
|
|
99
|
+
t.true(spy.calledOnce);
|
|
100
|
+
const calledWith = spy.firstCall.args[0];
|
|
101
|
+
t.is(calledWith.method, 'GET');
|
|
102
|
+
t.is(calledWith.url, 'https://www.googleapis.com/customsearch/v1');
|
|
103
|
+
t.deepEqual(calledWith.params.q, 'pokemon');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('parseResponse returns JSON string', t => {
|
|
107
|
+
const { plugin } = t.context;
|
|
108
|
+
const data = { items: [{ link: 'https://example.com' }] };
|
|
109
|
+
const res = plugin.parseResponse(data);
|
|
110
|
+
t.is(res, JSON.stringify(data));
|
|
111
|
+
});
|