@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
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import test from 'ava';
|
|
4
4
|
import got from 'got';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import serverFactory from '../../../../index.js';
|
|
6
|
+
import { connectToSSEEndpoint } from '../../../helpers/sseClient.js';
|
|
7
7
|
|
|
8
8
|
const API_BASE = `http://localhost:${process.env.CORTEX_PORT}/v1`;
|
|
9
9
|
|
|
@@ -90,157 +90,45 @@ test('POST /chat/completions with multimodal content', async (t) => {
|
|
|
90
90
|
t.truthy(response.body.choices[0].message.content);
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const response = await instance.post(endpoint, payload);
|
|
102
|
-
const responseData = response.data;
|
|
103
|
-
|
|
104
|
-
const incomingMessage = Array.isArray(responseData) && responseData.length > 0 ? responseData[0] : responseData;
|
|
105
|
-
|
|
106
|
-
let eventCount = 0;
|
|
107
|
-
|
|
108
|
-
incomingMessage.on('data', data => {
|
|
109
|
-
const events = data.toString().split('\n');
|
|
110
|
-
|
|
111
|
-
events.forEach(event => {
|
|
112
|
-
eventCount++;
|
|
113
|
-
|
|
114
|
-
if (event.trim() === '') return;
|
|
93
|
+
test('POST SSE: /v1/completions should send a series of events and a [DONE] event', async (t) => {
|
|
94
|
+
const payload = {
|
|
95
|
+
model: 'gpt-3.5-turbo',
|
|
96
|
+
prompt: 'Word to your motha!',
|
|
97
|
+
stream: true,
|
|
98
|
+
};
|
|
115
99
|
|
|
116
|
-
|
|
117
|
-
t.truthy(eventCount > 1);
|
|
118
|
-
resolve();
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const message = event.replace(/^data: /, '');
|
|
123
|
-
const messageJson = JSON.parse(message);
|
|
124
|
-
|
|
125
|
-
customAssertions(t, messageJson);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
} catch (error) {
|
|
130
|
-
console.error('Error connecting to SSE endpoint:', error);
|
|
131
|
-
reject(error);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
}
|
|
100
|
+
const url = `http://localhost:${process.env.CORTEX_PORT}/v1`;
|
|
135
101
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const url = `http://localhost:${process.env.CORTEX_PORT}/v1`;
|
|
144
|
-
|
|
145
|
-
const completionsAssertions = (t, messageJson) => {
|
|
146
|
-
t.truthy(messageJson.id);
|
|
147
|
-
t.is(messageJson.object, 'text_completion');
|
|
148
|
-
t.truthy(messageJson.choices[0].finish_reason === null || messageJson.choices[0].finish_reason === 'stop');
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
await connectToSSEEndpoint(url, '/completions', payload, t, completionsAssertions);
|
|
102
|
+
await connectToSSEEndpoint(url, '/completions', payload, (messageJson) => {
|
|
103
|
+
t.truthy(messageJson.id);
|
|
104
|
+
t.is(messageJson.object, 'text_completion');
|
|
105
|
+
t.truthy(messageJson.choices[0].finish_reason === null || messageJson.choices[0].finish_reason === 'stop');
|
|
106
|
+
});
|
|
152
107
|
});
|
|
153
108
|
|
|
154
109
|
test('POST SSE: /v1/chat/completions should send a series of events and a [DONE] event', async (t) => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const url = `http://localhost:${process.env.CORTEX_PORT}/v1`;
|
|
167
|
-
|
|
168
|
-
const chatCompletionsAssertions = (t, messageJson) => {
|
|
169
|
-
t.truthy(messageJson.id);
|
|
170
|
-
t.is(messageJson.object, 'chat.completion.chunk');
|
|
171
|
-
t.truthy(messageJson.choices[0].delta);
|
|
172
|
-
t.truthy(messageJson.choices[0].finish_reason === null || messageJson.choices[0].finish_reason === 'stop');
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
await connectToSSEEndpoint(url, '/chat/completions', payload, t, chatCompletionsAssertions);
|
|
176
|
-
});
|
|
110
|
+
const payload = {
|
|
111
|
+
model: 'gpt-4o',
|
|
112
|
+
messages: [
|
|
113
|
+
{
|
|
114
|
+
role: 'user',
|
|
115
|
+
content: 'Hello!',
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
stream: true,
|
|
119
|
+
};
|
|
177
120
|
|
|
178
|
-
|
|
179
|
-
const payload = {
|
|
180
|
-
model: 'gpt-4o',
|
|
181
|
-
messages: [{
|
|
182
|
-
role: 'user',
|
|
183
|
-
content: [
|
|
184
|
-
{
|
|
185
|
-
type: 'text',
|
|
186
|
-
text: 'What do you see in this image?'
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
type: 'image',
|
|
190
|
-
image_url: {
|
|
191
|
-
url: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDABQODxIPDRQSEBIXFRQdHx4eHRoaHSQrJyEwPENBMDQ4NDQ0QUJCSkNLS0tNSkpQUFFQR1BTYWNgY2FQYWFQYWj/2wBDARUXFyAeIBohHh4oIiE2LCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAIAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k='
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
]
|
|
195
|
-
}],
|
|
196
|
-
stream: true,
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
const url = `http://localhost:${process.env.CORTEX_PORT}/v1`;
|
|
200
|
-
|
|
201
|
-
const multimodalChatCompletionsAssertions = (t, messageJson) => {
|
|
202
|
-
t.truthy(messageJson.id);
|
|
203
|
-
t.is(messageJson.object, 'chat.completion.chunk');
|
|
204
|
-
t.truthy(messageJson.choices[0].delta);
|
|
205
|
-
if (messageJson.choices[0].finish_reason === 'stop') {
|
|
206
|
-
t.truthy(messageJson.choices[0].delta);
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
await connectToSSEEndpoint(url, '/chat/completions', payload, t, multimodalChatCompletionsAssertions);
|
|
211
|
-
});
|
|
121
|
+
const url = `http://localhost:${process.env.CORTEX_PORT}/v1`;
|
|
212
122
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
role: 'user',
|
|
219
|
-
content: [
|
|
220
|
-
{
|
|
221
|
-
type: 'text',
|
|
222
|
-
text: 'What do you see in this image?'
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
type: 'image',
|
|
226
|
-
image_url: {
|
|
227
|
-
url: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD...'
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
]
|
|
231
|
-
}],
|
|
232
|
-
stream: false,
|
|
233
|
-
},
|
|
234
|
-
responseType: 'json',
|
|
123
|
+
await connectToSSEEndpoint(url, '/chat/completions', payload, (messageJson) => {
|
|
124
|
+
t.truthy(messageJson.id);
|
|
125
|
+
t.is(messageJson.object, 'chat.completion.chunk');
|
|
126
|
+
t.truthy(messageJson.choices[0].delta);
|
|
127
|
+
t.truthy(messageJson.choices[0].finish_reason === null || messageJson.choices[0].finish_reason === 'stop');
|
|
235
128
|
});
|
|
236
|
-
|
|
237
|
-
t.is(response.statusCode, 200);
|
|
238
|
-
t.is(response.body.object, 'chat.completion');
|
|
239
|
-
t.true(Array.isArray(response.body.choices));
|
|
240
|
-
t.truthy(response.body.choices[0].message.content);
|
|
241
129
|
});
|
|
242
130
|
|
|
243
|
-
test('POST SSE: /v1/chat/completions should
|
|
131
|
+
test('POST SSE: /v1/chat/completions with multimodal content should send a series of events and a [DONE] event', async (t) => {
|
|
244
132
|
const payload = {
|
|
245
133
|
model: 'gpt-4o',
|
|
246
134
|
messages: [{
|
|
@@ -253,7 +141,7 @@ test('POST SSE: /v1/chat/completions should handle streaming multimodal content
|
|
|
253
141
|
{
|
|
254
142
|
type: 'image',
|
|
255
143
|
image_url: {
|
|
256
|
-
url: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD
|
|
144
|
+
url: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDABQODxIPDRQSEBIXFRQdHx4eHRoaHSQrJyEwPENBMDQ4NDQ0QUJCSkNLS0tNSkpQUFFQR1BTYWNgY2FQYWFQYWj/2wBDARUXFyAeIBohHh4oIiE2LCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAIAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k='
|
|
257
145
|
}
|
|
258
146
|
}
|
|
259
147
|
]
|
|
@@ -261,23 +149,17 @@ test('POST SSE: /v1/chat/completions should handle streaming multimodal content
|
|
|
261
149
|
stream: true,
|
|
262
150
|
};
|
|
263
151
|
|
|
264
|
-
const
|
|
152
|
+
const url = `http://localhost:${process.env.CORTEX_PORT}/v1`;
|
|
153
|
+
|
|
154
|
+
await connectToSSEEndpoint(url, '/chat/completions', payload, (messageJson) => {
|
|
265
155
|
t.truthy(messageJson.id);
|
|
266
156
|
t.is(messageJson.object, 'chat.completion.chunk');
|
|
267
157
|
t.truthy(messageJson.choices[0].delta);
|
|
268
158
|
if (messageJson.choices[0].finish_reason === 'stop') {
|
|
269
159
|
t.truthy(messageJson.choices[0].delta);
|
|
270
160
|
}
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
await connectToSSEEndpoint(
|
|
274
|
-
`http://localhost:${process.env.CORTEX_PORT}/v1`,
|
|
275
|
-
'/chat/completions',
|
|
276
|
-
payload,
|
|
277
|
-
t,
|
|
278
|
-
streamingAssertions
|
|
279
|
-
);
|
|
280
|
-
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
281
163
|
|
|
282
164
|
test('POST /chat/completions should handle malformed multimodal content', async (t) => {
|
|
283
165
|
const response = await got.post(`${API_BASE}/chat/completions`, {
|
|
@@ -340,8 +222,8 @@ test('POST /chat/completions should handle invalid image data', async (t) => {
|
|
|
340
222
|
test('POST /completions should handle model parameters', async (t) => {
|
|
341
223
|
const response = await got.post(`${API_BASE}/completions`, {
|
|
342
224
|
json: {
|
|
343
|
-
model: 'gpt-
|
|
344
|
-
prompt: 'Say this is a test',
|
|
225
|
+
model: 'gpt-4o',
|
|
226
|
+
prompt: 'Repeat after me: Say this is a test',
|
|
345
227
|
temperature: 0.7,
|
|
346
228
|
max_tokens: 100,
|
|
347
229
|
top_p: 1,
|
|
@@ -358,46 +240,6 @@ test('POST /completions should handle model parameters', async (t) => {
|
|
|
358
240
|
t.truthy(response.body.choices[0].text);
|
|
359
241
|
});
|
|
360
242
|
|
|
361
|
-
test('POST /chat/completions should handle function calling', async (t) => {
|
|
362
|
-
const response = await got.post(`${API_BASE}/chat/completions`, {
|
|
363
|
-
json: {
|
|
364
|
-
model: 'gpt-4o',
|
|
365
|
-
messages: [{ role: 'user', content: 'What is the weather in Boston?' }],
|
|
366
|
-
functions: [{
|
|
367
|
-
name: 'get_weather',
|
|
368
|
-
description: 'Get the current weather in a given location',
|
|
369
|
-
parameters: {
|
|
370
|
-
type: 'object',
|
|
371
|
-
properties: {
|
|
372
|
-
location: {
|
|
373
|
-
type: 'string',
|
|
374
|
-
description: 'The city and state, e.g. San Francisco, CA'
|
|
375
|
-
},
|
|
376
|
-
unit: {
|
|
377
|
-
type: 'string',
|
|
378
|
-
enum: ['celsius', 'fahrenheit']
|
|
379
|
-
}
|
|
380
|
-
},
|
|
381
|
-
required: ['location']
|
|
382
|
-
}
|
|
383
|
-
}],
|
|
384
|
-
stream: false,
|
|
385
|
-
},
|
|
386
|
-
responseType: 'json',
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
t.is(response.statusCode, 200);
|
|
390
|
-
t.is(response.body.object, 'chat.completion');
|
|
391
|
-
t.true(Array.isArray(response.body.choices));
|
|
392
|
-
const choice = response.body.choices[0];
|
|
393
|
-
t.true(['function_call', 'stop'].includes(choice.finish_reason));
|
|
394
|
-
if (choice.finish_reason === 'function_call') {
|
|
395
|
-
t.truthy(choice.message.function_call);
|
|
396
|
-
t.truthy(choice.message.function_call.name);
|
|
397
|
-
t.truthy(choice.message.function_call.arguments);
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
|
|
401
243
|
test('POST /chat/completions should validate response format', async (t) => {
|
|
402
244
|
const response = await got.post(`${API_BASE}/chat/completions`, {
|
|
403
245
|
json: {
|
|
@@ -492,7 +334,6 @@ test('POST /chat/completions should return complete responses from gpt-4o', asyn
|
|
|
492
334
|
t.is(response.statusCode, 200);
|
|
493
335
|
t.is(response.body.object, 'chat.completion');
|
|
494
336
|
t.true(Array.isArray(response.body.choices));
|
|
495
|
-
console.log('GPT-4o Response:', JSON.stringify(response.body.choices[0].message.content));
|
|
496
337
|
const content = response.body.choices[0].message.content;
|
|
497
338
|
t.regex(content, /END_MARKER_XYZ$/);
|
|
498
339
|
});
|
|
@@ -513,7 +354,7 @@ test('POST /chat/completions should handle array content properly', async (t) =>
|
|
|
513
354
|
},
|
|
514
355
|
{
|
|
515
356
|
type: 'image',
|
|
516
|
-
url: 'https://
|
|
357
|
+
url: 'https://static.toiimg.com/thumb/msid-102827471,width-1280,height-720,resizemode-4/102827471.jpg'
|
|
517
358
|
}
|
|
518
359
|
];
|
|
519
360
|
|
|
@@ -557,68 +398,52 @@ test('POST /chat/completions should handle array content properly', async (t) =>
|
|
|
557
398
|
}
|
|
558
399
|
}
|
|
559
400
|
|
|
560
|
-
t.log(`Using model: ${modelToUse}`);
|
|
561
401
|
}
|
|
562
|
-
} catch (
|
|
563
|
-
|
|
402
|
+
} catch (_modelError) {
|
|
403
|
+
// ignore model errors, fallback to default
|
|
564
404
|
}
|
|
565
405
|
|
|
566
406
|
// Make a direct HTTP request to the REST API
|
|
567
|
-
const response = await
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
407
|
+
const response = await got.post(`${API_BASE}/chat/completions`, {
|
|
408
|
+
json: {
|
|
409
|
+
model: modelToUse,
|
|
410
|
+
messages: [
|
|
411
|
+
{
|
|
412
|
+
role: 'user',
|
|
413
|
+
content: testContent
|
|
414
|
+
}
|
|
415
|
+
],
|
|
416
|
+
stream: false,
|
|
417
|
+
},
|
|
418
|
+
responseType: 'json',
|
|
575
419
|
});
|
|
576
420
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const message = response.data.choices[0].message;
|
|
421
|
+
const message = response.body.choices[0].message;
|
|
580
422
|
|
|
581
|
-
//message should not have anything similar to:
|
|
582
|
-
//Execution failed for sys_claude_37_sonnet: HTTP error: 400 Bad Request
|
|
583
|
-
//HTTP error:
|
|
584
423
|
t.falsy(message.content.startsWith('HTTP error:'));
|
|
585
|
-
//400 Bad Request
|
|
586
424
|
t.falsy(message.content.startsWith('400 Bad Request'));
|
|
587
|
-
//Execution failed
|
|
588
425
|
t.falsy(message.content.startsWith('Execution failed'));
|
|
589
|
-
//Invalid JSON
|
|
590
426
|
t.falsy(message.content.startsWith('Invalid JSON'));
|
|
591
427
|
|
|
592
|
-
|
|
593
|
-
// If the request succeeds, it means the array content was properly processed
|
|
594
|
-
// If the JSON.stringify was not applied correctly, the request would fail
|
|
595
|
-
t.truthy(response.data);
|
|
596
|
-
t.pass('REST API successfully processed array content');
|
|
428
|
+
t.truthy(response.body);
|
|
597
429
|
} catch (error) {
|
|
598
|
-
// If there's a connection error (e.g., API not running), we'll skip this test
|
|
599
430
|
if (error.code === 'ECONNREFUSED') {
|
|
600
431
|
t.pass('Skipping test - REST API not available');
|
|
601
432
|
} else {
|
|
602
|
-
// Check if the error response contains useful information
|
|
603
433
|
if (error.response) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (error.response.status === 404 &&
|
|
609
|
-
error.response.data.error &&
|
|
610
|
-
error.response.data.error.includes('not found')) {
|
|
434
|
+
if (error.response.statusCode === 404 &&
|
|
435
|
+
error.response.body &&
|
|
436
|
+
error.response.body.error &&
|
|
437
|
+
error.response.body.error.includes('not found')) {
|
|
611
438
|
t.pass('Skipping test - No suitable pathway configured for this API endpoint');
|
|
612
439
|
} else {
|
|
613
|
-
t.fail(`API request failed with status ${error.response.
|
|
440
|
+
t.fail(`API request failed with status ${error.response.statusCode}: ${error.response.statusMessage || ''}`);
|
|
614
441
|
}
|
|
615
442
|
} else {
|
|
616
|
-
// No response received
|
|
617
443
|
t.fail(`API request failed: ${error.message}`);
|
|
618
444
|
}
|
|
619
445
|
}
|
|
620
446
|
}
|
|
621
|
-
});
|
|
622
|
-
|
|
447
|
+
});
|
|
448
|
+
|
|
623
449
|
|
|
624
|
-
|