@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.
Files changed (211) hide show
  1. package/.github/workflows/cortex-file-handler-test.yml +61 -0
  2. package/README.md +31 -7
  3. package/config/default.example.json +15 -0
  4. package/config.js +133 -12
  5. package/helper-apps/cortex-autogen2/DigiCertGlobalRootCA.crt.pem +22 -0
  6. package/helper-apps/cortex-autogen2/Dockerfile +31 -0
  7. package/helper-apps/cortex-autogen2/Dockerfile.worker +41 -0
  8. package/helper-apps/cortex-autogen2/README.md +183 -0
  9. package/helper-apps/cortex-autogen2/__init__.py +1 -0
  10. package/helper-apps/cortex-autogen2/agents.py +131 -0
  11. package/helper-apps/cortex-autogen2/docker-compose.yml +20 -0
  12. package/helper-apps/cortex-autogen2/function_app.py +55 -0
  13. package/helper-apps/cortex-autogen2/host.json +15 -0
  14. package/helper-apps/cortex-autogen2/main.py +126 -0
  15. package/helper-apps/cortex-autogen2/poetry.lock +3652 -0
  16. package/helper-apps/cortex-autogen2/pyproject.toml +36 -0
  17. package/helper-apps/cortex-autogen2/requirements.txt +20 -0
  18. package/helper-apps/cortex-autogen2/send_task.py +105 -0
  19. package/helper-apps/cortex-autogen2/services/__init__.py +1 -0
  20. package/helper-apps/cortex-autogen2/services/azure_queue.py +85 -0
  21. package/helper-apps/cortex-autogen2/services/redis_publisher.py +153 -0
  22. package/helper-apps/cortex-autogen2/task_processor.py +488 -0
  23. package/helper-apps/cortex-autogen2/tools/__init__.py +24 -0
  24. package/helper-apps/cortex-autogen2/tools/azure_blob_tools.py +175 -0
  25. package/helper-apps/cortex-autogen2/tools/azure_foundry_agents.py +601 -0
  26. package/helper-apps/cortex-autogen2/tools/coding_tools.py +72 -0
  27. package/helper-apps/cortex-autogen2/tools/download_tools.py +48 -0
  28. package/helper-apps/cortex-autogen2/tools/file_tools.py +545 -0
  29. package/helper-apps/cortex-autogen2/tools/search_tools.py +646 -0
  30. package/helper-apps/cortex-azure-cleaner/README.md +36 -0
  31. package/helper-apps/cortex-file-converter/README.md +93 -0
  32. package/helper-apps/cortex-file-converter/key_to_pdf.py +104 -0
  33. package/helper-apps/cortex-file-converter/list_blob_extensions.py +89 -0
  34. package/helper-apps/cortex-file-converter/process_azure_keynotes.py +181 -0
  35. package/helper-apps/cortex-file-converter/requirements.txt +1 -0
  36. package/helper-apps/cortex-file-handler/.env.test.azure.ci +7 -0
  37. package/helper-apps/cortex-file-handler/.env.test.azure.sample +1 -1
  38. package/helper-apps/cortex-file-handler/.env.test.gcs.ci +10 -0
  39. package/helper-apps/cortex-file-handler/.env.test.gcs.sample +2 -2
  40. package/helper-apps/cortex-file-handler/INTERFACE.md +41 -0
  41. package/helper-apps/cortex-file-handler/package.json +1 -1
  42. package/helper-apps/cortex-file-handler/scripts/setup-azure-container.js +41 -17
  43. package/helper-apps/cortex-file-handler/scripts/setup-test-containers.js +30 -15
  44. package/helper-apps/cortex-file-handler/scripts/test-azure.sh +32 -6
  45. package/helper-apps/cortex-file-handler/scripts/test-gcs.sh +24 -2
  46. package/helper-apps/cortex-file-handler/scripts/validate-env.js +128 -0
  47. package/helper-apps/cortex-file-handler/src/blobHandler.js +161 -51
  48. package/helper-apps/cortex-file-handler/src/constants.js +3 -0
  49. package/helper-apps/cortex-file-handler/src/fileChunker.js +10 -8
  50. package/helper-apps/cortex-file-handler/src/index.js +116 -9
  51. package/helper-apps/cortex-file-handler/src/redis.js +61 -1
  52. package/helper-apps/cortex-file-handler/src/services/ConversionService.js +11 -8
  53. package/helper-apps/cortex-file-handler/src/services/FileConversionService.js +2 -2
  54. package/helper-apps/cortex-file-handler/src/services/storage/AzureStorageProvider.js +88 -6
  55. package/helper-apps/cortex-file-handler/src/services/storage/GCSStorageProvider.js +58 -0
  56. package/helper-apps/cortex-file-handler/src/services/storage/StorageFactory.js +25 -5
  57. package/helper-apps/cortex-file-handler/src/services/storage/StorageProvider.js +9 -0
  58. package/helper-apps/cortex-file-handler/src/services/storage/StorageService.js +120 -16
  59. package/helper-apps/cortex-file-handler/src/start.js +27 -17
  60. package/helper-apps/cortex-file-handler/tests/FileConversionService.test.js +52 -1
  61. package/helper-apps/cortex-file-handler/tests/blobHandler.test.js +40 -0
  62. package/helper-apps/cortex-file-handler/tests/checkHashShortLived.test.js +553 -0
  63. package/helper-apps/cortex-file-handler/tests/cleanup.test.js +46 -52
  64. package/helper-apps/cortex-file-handler/tests/containerConversionFlow.test.js +451 -0
  65. package/helper-apps/cortex-file-handler/tests/containerNameParsing.test.js +229 -0
  66. package/helper-apps/cortex-file-handler/tests/containerParameterFlow.test.js +392 -0
  67. package/helper-apps/cortex-file-handler/tests/conversionResilience.test.js +7 -2
  68. package/helper-apps/cortex-file-handler/tests/deleteOperations.test.js +348 -0
  69. package/helper-apps/cortex-file-handler/tests/fileChunker.test.js +23 -2
  70. package/helper-apps/cortex-file-handler/tests/fileUpload.test.js +11 -5
  71. package/helper-apps/cortex-file-handler/tests/getOperations.test.js +58 -24
  72. package/helper-apps/cortex-file-handler/tests/postOperations.test.js +11 -4
  73. package/helper-apps/cortex-file-handler/tests/shortLivedUrlConversion.test.js +225 -0
  74. package/helper-apps/cortex-file-handler/tests/start.test.js +8 -12
  75. package/helper-apps/cortex-file-handler/tests/storage/StorageFactory.test.js +80 -0
  76. package/helper-apps/cortex-file-handler/tests/storage/StorageService.test.js +388 -22
  77. package/helper-apps/cortex-file-handler/tests/testUtils.helper.js +74 -0
  78. package/lib/cortexResponse.js +153 -0
  79. package/lib/entityConstants.js +21 -3
  80. package/lib/logger.js +21 -4
  81. package/lib/pathwayTools.js +28 -9
  82. package/lib/util.js +49 -0
  83. package/package.json +1 -1
  84. package/pathways/basePathway.js +1 -0
  85. package/pathways/bing_afagent.js +54 -1
  86. package/pathways/call_tools.js +2 -3
  87. package/pathways/chat_jarvis.js +1 -1
  88. package/pathways/google_cse.js +27 -0
  89. package/pathways/grok_live_search.js +18 -0
  90. package/pathways/system/entity/memory/sys_memory_lookup_required.js +1 -0
  91. package/pathways/system/entity/memory/sys_memory_required.js +1 -0
  92. package/pathways/system/entity/memory/sys_search_memory.js +1 -0
  93. package/pathways/system/entity/sys_entity_agent.js +56 -4
  94. package/pathways/system/entity/sys_generator_quick.js +1 -0
  95. package/pathways/system/entity/tools/sys_tool_bing_search_afagent.js +26 -0
  96. package/pathways/system/entity/tools/sys_tool_google_search.js +141 -0
  97. package/pathways/system/entity/tools/sys_tool_grok_x_search.js +237 -0
  98. package/pathways/system/entity/tools/sys_tool_image.js +1 -1
  99. package/pathways/system/rest_streaming/sys_claude_37_sonnet.js +21 -0
  100. package/pathways/system/rest_streaming/sys_claude_41_opus.js +21 -0
  101. package/pathways/system/rest_streaming/sys_claude_4_sonnet.js +21 -0
  102. package/pathways/system/rest_streaming/sys_google_gemini_25_flash.js +25 -0
  103. package/pathways/system/rest_streaming/{sys_google_gemini_chat.js → sys_google_gemini_25_pro.js} +6 -4
  104. package/pathways/system/rest_streaming/sys_grok_4.js +23 -0
  105. package/pathways/system/rest_streaming/sys_grok_4_fast_non_reasoning.js +23 -0
  106. package/pathways/system/rest_streaming/sys_grok_4_fast_reasoning.js +23 -0
  107. package/pathways/system/rest_streaming/sys_openai_chat.js +3 -0
  108. package/pathways/system/rest_streaming/sys_openai_chat_gpt41.js +22 -0
  109. package/pathways/system/rest_streaming/sys_openai_chat_gpt41_mini.js +21 -0
  110. package/pathways/system/rest_streaming/sys_openai_chat_gpt41_nano.js +21 -0
  111. package/pathways/system/rest_streaming/{sys_claude_35_sonnet.js → sys_openai_chat_gpt4_omni.js} +6 -4
  112. package/pathways/system/rest_streaming/sys_openai_chat_gpt4_omni_mini.js +21 -0
  113. package/pathways/system/rest_streaming/{sys_claude_3_haiku.js → sys_openai_chat_gpt5.js} +7 -5
  114. package/pathways/system/rest_streaming/sys_openai_chat_gpt5_chat.js +21 -0
  115. package/pathways/system/rest_streaming/sys_openai_chat_gpt5_mini.js +21 -0
  116. package/pathways/system/rest_streaming/sys_openai_chat_gpt5_nano.js +21 -0
  117. package/pathways/system/rest_streaming/{sys_openai_chat_o1.js → sys_openai_chat_o3.js} +6 -3
  118. package/pathways/system/rest_streaming/sys_openai_chat_o3_mini.js +3 -0
  119. package/pathways/system/workspaces/run_workspace_prompt.js +99 -0
  120. package/pathways/vision.js +1 -1
  121. package/server/graphql.js +1 -1
  122. package/server/modelExecutor.js +8 -0
  123. package/server/pathwayResolver.js +166 -16
  124. package/server/pathwayResponseParser.js +16 -8
  125. package/server/plugins/azureFoundryAgentsPlugin.js +1 -1
  126. package/server/plugins/claude3VertexPlugin.js +193 -45
  127. package/server/plugins/gemini15ChatPlugin.js +21 -0
  128. package/server/plugins/gemini15VisionPlugin.js +360 -0
  129. package/server/plugins/googleCsePlugin.js +94 -0
  130. package/server/plugins/grokVisionPlugin.js +365 -0
  131. package/server/plugins/modelPlugin.js +3 -1
  132. package/server/plugins/openAiChatPlugin.js +106 -13
  133. package/server/plugins/openAiVisionPlugin.js +42 -30
  134. package/server/resolver.js +28 -4
  135. package/server/rest.js +270 -53
  136. package/server/typeDef.js +1 -0
  137. package/tests/{mocks.js → helpers/mocks.js} +5 -2
  138. package/tests/{server.js → helpers/server.js} +2 -2
  139. package/tests/helpers/sseAssert.js +23 -0
  140. package/tests/helpers/sseClient.js +73 -0
  141. package/tests/helpers/subscriptionAssert.js +11 -0
  142. package/tests/helpers/subscriptions.js +113 -0
  143. package/tests/{sublong.srt → integration/features/translate/sublong.srt} +4543 -4543
  144. package/tests/integration/features/translate/translate_chunking_stream.test.js +100 -0
  145. package/tests/{translate_srt.test.js → integration/features/translate/translate_srt.test.js} +2 -2
  146. package/tests/integration/graphql/async/stream/agentic.test.js +477 -0
  147. package/tests/integration/graphql/async/stream/subscription_streaming.test.js +62 -0
  148. package/tests/integration/graphql/async/stream/sys_entity_start_streaming.test.js +71 -0
  149. package/tests/integration/graphql/async/stream/vendors/claude_streaming.test.js +56 -0
  150. package/tests/integration/graphql/async/stream/vendors/gemini_streaming.test.js +66 -0
  151. package/tests/integration/graphql/async/stream/vendors/grok_streaming.test.js +56 -0
  152. package/tests/integration/graphql/async/stream/vendors/openai_streaming.test.js +72 -0
  153. package/tests/integration/graphql/features/google/sysToolGoogleSearch.test.js +96 -0
  154. package/tests/integration/graphql/features/grok/grok.test.js +688 -0
  155. package/tests/integration/graphql/features/grok/grok_x_search_tool.test.js +354 -0
  156. package/tests/{main.test.js → integration/graphql/features/main.test.js} +1 -1
  157. package/tests/{call_tools.test.js → integration/graphql/features/tools/call_tools.test.js} +2 -2
  158. package/tests/{vision.test.js → integration/graphql/features/vision/vision.test.js} +1 -1
  159. package/tests/integration/graphql/subscriptions/connection.test.js +26 -0
  160. package/tests/{openai_api.test.js → integration/rest/oai/openai_api.test.js} +63 -238
  161. package/tests/integration/rest/oai/tool_calling_api.test.js +343 -0
  162. package/tests/integration/rest/oai/tool_calling_streaming.test.js +85 -0
  163. package/tests/integration/rest/vendors/claude_streaming.test.js +47 -0
  164. package/tests/integration/rest/vendors/claude_tool_calling_streaming.test.js +75 -0
  165. package/tests/integration/rest/vendors/gemini_streaming.test.js +47 -0
  166. package/tests/integration/rest/vendors/gemini_tool_calling_streaming.test.js +75 -0
  167. package/tests/integration/rest/vendors/grok_streaming.test.js +55 -0
  168. package/tests/integration/rest/vendors/grok_tool_calling_streaming.test.js +75 -0
  169. package/tests/{azureAuthTokenHelper.test.js → unit/core/azureAuthTokenHelper.test.js} +1 -1
  170. package/tests/{chunkfunction.test.js → unit/core/chunkfunction.test.js} +2 -2
  171. package/tests/{config.test.js → unit/core/config.test.js} +3 -3
  172. package/tests/{encodeCache.test.js → unit/core/encodeCache.test.js} +1 -1
  173. package/tests/{fastLruCache.test.js → unit/core/fastLruCache.test.js} +1 -1
  174. package/tests/{handleBars.test.js → unit/core/handleBars.test.js} +1 -1
  175. package/tests/{memoryfunction.test.js → unit/core/memoryfunction.test.js} +2 -2
  176. package/tests/unit/core/mergeResolver.test.js +952 -0
  177. package/tests/{parser.test.js → unit/core/parser.test.js} +3 -3
  178. package/tests/unit/core/pathwayResolver.test.js +187 -0
  179. package/tests/{requestMonitor.test.js → unit/core/requestMonitor.test.js} +1 -1
  180. package/tests/{requestMonitorDurationEstimator.test.js → unit/core/requestMonitorDurationEstimator.test.js} +1 -1
  181. package/tests/{truncateMessages.test.js → unit/core/truncateMessages.test.js} +3 -3
  182. package/tests/{util.test.js → unit/core/util.test.js} +1 -1
  183. package/tests/{apptekTranslatePlugin.test.js → unit/plugins/apptekTranslatePlugin.test.js} +3 -3
  184. package/tests/{azureFoundryAgents.test.js → unit/plugins/azureFoundryAgents.test.js} +136 -1
  185. package/tests/{claude3VertexPlugin.test.js → unit/plugins/claude3VertexPlugin.test.js} +32 -10
  186. package/tests/{claude3VertexToolConversion.test.js → unit/plugins/claude3VertexToolConversion.test.js} +3 -3
  187. package/tests/unit/plugins/googleCsePlugin.test.js +111 -0
  188. package/tests/unit/plugins/grokVisionPlugin.test.js +1392 -0
  189. package/tests/{modelPlugin.test.js → unit/plugins/modelPlugin.test.js} +3 -3
  190. package/tests/{multimodal_conversion.test.js → unit/plugins/multimodal_conversion.test.js} +4 -4
  191. package/tests/{openAiChatPlugin.test.js → unit/plugins/openAiChatPlugin.test.js} +13 -4
  192. package/tests/{openAiToolPlugin.test.js → unit/plugins/openAiToolPlugin.test.js} +35 -27
  193. package/tests/{tokenHandlingTests.test.js → unit/plugins/tokenHandlingTests.test.js} +5 -5
  194. package/tests/{translate_apptek.test.js → unit/plugins/translate_apptek.test.js} +3 -3
  195. package/tests/{streaming.test.js → unit/plugins.streaming/plugin_stream_events.test.js} +19 -58
  196. package/helper-apps/mogrt-handler/tests/test-files/test.gif +0 -1
  197. package/helper-apps/mogrt-handler/tests/test-files/test.mogrt +0 -1
  198. package/helper-apps/mogrt-handler/tests/test-files/test.mp4 +0 -1
  199. package/pathways/system/rest_streaming/sys_openai_chat_gpt4.js +0 -19
  200. package/pathways/system/rest_streaming/sys_openai_chat_gpt4_32.js +0 -19
  201. package/pathways/system/rest_streaming/sys_openai_chat_gpt4_turbo.js +0 -19
  202. package/pathways/system/workspaces/run_claude35_sonnet.js +0 -21
  203. package/pathways/system/workspaces/run_claude3_haiku.js +0 -20
  204. package/pathways/system/workspaces/run_gpt35turbo.js +0 -20
  205. package/pathways/system/workspaces/run_gpt4.js +0 -20
  206. package/pathways/system/workspaces/run_gpt4_32.js +0 -20
  207. package/tests/agentic.test.js +0 -256
  208. package/tests/pathwayResolver.test.js +0 -78
  209. package/tests/subscription.test.js +0 -387
  210. /package/tests/{subchunk.srt → integration/features/translate/subchunk.srt} +0 -0
  211. /package/tests/{subhorizontal.srt → integration/features/translate/subhorizontal.srt} +0 -0
@@ -0,0 +1,71 @@
1
+ import test from 'ava';
2
+ import serverFactory from '../../../../../index.js';
3
+ import { createWsClient, ensureWsConnection, collectSubscriptionEvents, validateProgressMessage } from '../../../../helpers/subscriptions.js';
4
+
5
+ let testServer;
6
+ let wsClient;
7
+
8
+ test.before(async () => {
9
+ process.env.CORTEX_ENABLE_REST = 'true';
10
+ const { server, startServer } = await serverFactory();
11
+ startServer && await startServer();
12
+ testServer = server;
13
+
14
+ wsClient = createWsClient();
15
+ await ensureWsConnection(wsClient);
16
+ });
17
+
18
+ test.after.always('cleanup', async () => {
19
+ if (wsClient) wsClient.dispose();
20
+ if (testServer) await testServer.stop();
21
+ });
22
+
23
+ test.serial('sys_entity_start streaming works correctly', async (t) => {
24
+ const response = await testServer.executeOperation({
25
+ query: `
26
+ query TestQuery($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean!) {
27
+ sys_entity_start(text: $text, chatHistory: $chatHistory, stream: $stream) {
28
+ result
29
+ contextId
30
+ tool
31
+ warnings
32
+ errors
33
+ }
34
+ }
35
+ `,
36
+ variables: {
37
+ text: 'Tell me about the history of Al Jazeera',
38
+ chatHistory: [{ role: "user", content: ["Tell me about the history of Al Jazeera"] }],
39
+ stream: true
40
+ }
41
+ });
42
+
43
+ const requestId = response.body?.singleResult?.data?.sys_entity_start?.result;
44
+ t.truthy(requestId);
45
+
46
+ const events = await collectSubscriptionEvents(wsClient, {
47
+ query: `
48
+ subscription OnRequestProgress($requestId: String!) {
49
+ requestProgress(requestIds: [$requestId]) {
50
+ requestId
51
+ progress
52
+ data
53
+ info
54
+ }
55
+ }
56
+ `,
57
+ variables: { requestId },
58
+ }, 30000, { requireCompletion: false, minEvents: 1 });
59
+
60
+ t.true(events.length > 0);
61
+ for (const event of events) {
62
+ const progress = event.data.requestProgress;
63
+ validateProgressMessage(t, progress, requestId);
64
+ if (progress.data) {
65
+ const parsed = JSON.parse(progress.data);
66
+ t.true(typeof parsed === 'string' || typeof parsed === 'object');
67
+ }
68
+ }
69
+ });
70
+
71
+
@@ -0,0 +1,56 @@
1
+ import test from 'ava';
2
+ import serverFactory from '../../../../../../index.js';
3
+ import { createWsClient, ensureWsConnection, collectSubscriptionEvents } from '../../../../../helpers/subscriptions.js';
4
+
5
+ let testServer;
6
+ let wsClient;
7
+
8
+ test.before(async () => {
9
+ const { server, startServer } = await serverFactory();
10
+ startServer && await startServer();
11
+ testServer = server;
12
+ wsClient = createWsClient();
13
+ await ensureWsConnection(wsClient);
14
+ });
15
+
16
+ test.after.always('cleanup', async () => {
17
+ if (wsClient) wsClient.dispose();
18
+ if (testServer) await testServer.stop();
19
+ });
20
+
21
+ test('Claude vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
22
+ const response = await testServer.executeOperation({
23
+ query: `
24
+ query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean, $aiStyle: String) {
25
+ sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream, aiStyle: $aiStyle) {
26
+ result
27
+ }
28
+ }
29
+ `,
30
+ variables: {
31
+ text: 'Say hi',
32
+ chatHistory: [{ role: 'user', content: ['Say hi'] }],
33
+ stream: true,
34
+ aiStyle: 'Anthropic'
35
+ }
36
+ });
37
+
38
+ const requestId = response.body?.singleResult?.data?.sys_entity_agent?.result;
39
+ if (!requestId) {
40
+ t.pass('Skipping - Claude vendor model not configured');
41
+ return;
42
+ }
43
+
44
+ const events = await collectSubscriptionEvents(wsClient, {
45
+ query: `
46
+ subscription($requestId: String!) {
47
+ requestProgress(requestIds: [$requestId]) { requestId progress data }
48
+ }
49
+ `,
50
+ variables: { requestId },
51
+ }, 20000, { requireCompletion: false, minEvents: 1 });
52
+
53
+ t.true(events.length > 0);
54
+ });
55
+
56
+
@@ -0,0 +1,66 @@
1
+ import test from 'ava';
2
+ import serverFactory from '../../../../../../index.js';
3
+ import { createWsClient, ensureWsConnection, collectSubscriptionEvents } from '../../../../../helpers/subscriptions.js';
4
+
5
+ let testServer;
6
+ let wsClient;
7
+
8
+ test.before(async () => {
9
+ const { server, startServer } = await serverFactory();
10
+ startServer && await startServer();
11
+ testServer = server;
12
+ wsClient = createWsClient();
13
+ await ensureWsConnection(wsClient);
14
+ });
15
+
16
+ test.after.always('cleanup', async () => {
17
+ if (wsClient) wsClient.dispose();
18
+ if (testServer) await testServer.stop();
19
+ });
20
+
21
+ test('Gemini vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
22
+ const response = await testServer.executeOperation({
23
+ query: `
24
+ query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean, $aiStyle: String) {
25
+ sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream, aiStyle: $aiStyle) {
26
+ result
27
+ }
28
+ }
29
+ `,
30
+ variables: {
31
+ text: 'Say hi',
32
+ chatHistory: [{ role: 'user', content: ['Say hi'] }],
33
+ stream: true,
34
+ aiStyle: 'Google'
35
+ }
36
+ });
37
+
38
+ const requestId = response.body?.singleResult?.data?.sys_entity_agent?.result;
39
+ if (!requestId) {
40
+ t.pass('Skipping - Google vendor model not configured');
41
+ return;
42
+ }
43
+
44
+ const events = await collectSubscriptionEvents(wsClient, {
45
+ query: `
46
+ subscription($requestId: String!) {
47
+ requestProgress(requestIds: [$requestId]) { requestId progress data }
48
+ }
49
+ `,
50
+ variables: { requestId },
51
+ }, 20000, { requireCompletion: false, minEvents: 1 });
52
+ t.true(events.length > 0);
53
+ const hasDelta = events.some(e => {
54
+ const data = e?.data?.requestProgress?.data;
55
+ if (!data) return false;
56
+ try {
57
+ const parsed = JSON.parse(data);
58
+ return parsed?.choices?.[0]?.delta;
59
+ } catch (_) {
60
+ return false;
61
+ }
62
+ });
63
+ t.true(hasDelta);
64
+ });
65
+
66
+
@@ -0,0 +1,56 @@
1
+ import test from 'ava';
2
+ import serverFactory from '../../../../../../index.js';
3
+ import { createWsClient, ensureWsConnection, collectSubscriptionEvents } from '../../../../../helpers/subscriptions.js';
4
+
5
+ let testServer;
6
+ let wsClient;
7
+
8
+ test.before(async () => {
9
+ const { server, startServer } = await serverFactory();
10
+ startServer && await startServer();
11
+ testServer = server;
12
+ wsClient = createWsClient();
13
+ await ensureWsConnection(wsClient);
14
+ });
15
+
16
+ test.after.always('cleanup', async () => {
17
+ if (wsClient) wsClient.dispose();
18
+ if (testServer) await testServer.stop();
19
+ });
20
+
21
+ test('XAI Grok vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
22
+ const response = await testServer.executeOperation({
23
+ query: `
24
+ query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean, $aiStyle: String) {
25
+ sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream, aiStyle: $aiStyle) {
26
+ result
27
+ }
28
+ }
29
+ `,
30
+ variables: {
31
+ text: 'Say hi',
32
+ chatHistory: [{ role: 'user', content: ['Say hi'] }],
33
+ stream: true,
34
+ aiStyle: 'XAI'
35
+ }
36
+ });
37
+
38
+ const requestId = response.body?.singleResult?.data?.sys_entity_agent?.result;
39
+ if (!requestId) {
40
+ t.pass('Skipping - XAI vendor model not configured');
41
+ return;
42
+ }
43
+
44
+ const events = await collectSubscriptionEvents(wsClient, {
45
+ query: `
46
+ subscription($requestId: String!) {
47
+ requestProgress(requestIds: [$requestId]) { requestId progress data }
48
+ }
49
+ `,
50
+ variables: { requestId },
51
+ }, 20000, { requireCompletion: false, minEvents: 1 });
52
+
53
+ t.true(events.length > 0);
54
+ });
55
+
56
+
@@ -0,0 +1,72 @@
1
+ import test from 'ava';
2
+ import serverFactory from '../../../../../../index.js';
3
+ import { createWsClient, ensureWsConnection, collectSubscriptionEvents } from '../../../../../helpers/subscriptions.js';
4
+
5
+ let testServer;
6
+ let wsClient;
7
+
8
+ test.before(async () => {
9
+ const { server, startServer } = await serverFactory();
10
+ startServer && await startServer();
11
+ testServer = server;
12
+ wsClient = createWsClient();
13
+ await ensureWsConnection(wsClient);
14
+ });
15
+
16
+ test.after.always('cleanup', async () => {
17
+ if (wsClient) wsClient.dispose();
18
+ if (testServer) await testServer.stop();
19
+ });
20
+
21
+ test('OpenAI vendor streaming over subscriptions emits OAI-style deltas', async (t) => {
22
+ const response = await testServer.executeOperation({
23
+ query: `
24
+ query($text: String!, $chatHistory: [MultiMessage]!, $stream: Boolean, $aiStyle: String) {
25
+ sys_entity_agent(text: $text, chatHistory: $chatHistory, stream: $stream, aiStyle: $aiStyle) {
26
+ result
27
+ }
28
+ }
29
+ `,
30
+ variables: {
31
+ text: 'Say hi',
32
+ chatHistory: [{ role: 'user', content: ['Say hi'] }],
33
+ stream: true,
34
+ aiStyle: 'OpenAI'
35
+ }
36
+ });
37
+
38
+ const requestId = response.body?.singleResult?.data?.sys_entity_agent?.result;
39
+ if (!requestId) {
40
+ t.pass('Skipping - OpenAI vendor model not configured');
41
+ return;
42
+ }
43
+
44
+ const events = await collectSubscriptionEvents(wsClient, {
45
+ query: `
46
+ subscription($requestId: String!) {
47
+ requestProgress(requestIds: [$requestId]) { requestId progress data }
48
+ }
49
+ `,
50
+ variables: { requestId },
51
+ }, 20000, { requireCompletion: false, minEvents: 1 });
52
+
53
+ t.true(events.length > 0);
54
+
55
+ // Ensure streamed chunks (when they include model) use gpt-4.1 (not mini)
56
+ const models = events
57
+ .map(e => {
58
+ try {
59
+ return JSON.parse(e?.data?.requestProgress?.data || '{}')?.model;
60
+ } catch (_) {
61
+ return undefined;
62
+ }
63
+ })
64
+ .filter(Boolean);
65
+
66
+ if (models.length > 0) {
67
+ t.truthy(models.find(m => /gpt-4\.1(?!-mini)/.test(m)));
68
+ t.falsy(models.find(m => /gpt-4\.1-mini/.test(m)));
69
+ }
70
+ });
71
+
72
+
@@ -0,0 +1,96 @@
1
+ import test from 'ava';
2
+ import sinon from 'sinon';
3
+
4
+ const mockGoogleResponse = {
5
+ searchInformation: {
6
+ totalResults: '123',
7
+ searchTime: 0.12
8
+ },
9
+ items: [
10
+ {
11
+ title: 'Pikachu - Wikipedia',
12
+ link: 'https://en.wikipedia.org/wiki/Pikachu',
13
+ snippet: 'Pikachu is a species of Pokémon...'
14
+ },
15
+ {
16
+ title: 'Pokemon News - Official Site',
17
+ link: 'https://www.pokemon.com/us',
18
+ snippet: 'The official source for Pokémon news...'
19
+ }
20
+ ]
21
+ };
22
+
23
+ // Build a minimal stub pathway for google_cse returning canned results
24
+ const buildStubGooglePathway = () => ({
25
+ name: 'google_cse',
26
+ // Simulate the core rootResolver returning data.result
27
+ rootResolver: async () => {
28
+ return { result: JSON.stringify(mockGoogleResponse) };
29
+ }
30
+ });
31
+
32
+ // Build a minimal resolver object to pass to executePathway
33
+ const buildResolver = () => ({
34
+ errors: [],
35
+ tool: null,
36
+ mergeResults: () => {},
37
+ });
38
+
39
+ // Ensure required env vars exist before importing config/tool
40
+ const setEnv = (t) => {
41
+ t.context.originalEnv = { ...process.env };
42
+ process.env.OPENAI_API_KEY = 'test-openai-key';
43
+ process.env.GOOGLE_CSE_KEY = 'test-google-key';
44
+ process.env.GOOGLE_CSE_CX = 'test-google-cx';
45
+ };
46
+
47
+ const restoreEnv = (t) => {
48
+ process.env = t.context.originalEnv;
49
+ };
50
+
51
+ // We import modules lazily after env vars are set to avoid config init errors
52
+ const loadModules = async () => {
53
+ const { config } = await import('../../../../../config.js');
54
+ const toolModule = await import('../../../../../pathways/system/entity/tools/sys_tool_google_search.js');
55
+ return { config, tool: toolModule.default };
56
+ };
57
+
58
+ // Helper to inject stub google_cse pathway
59
+ const injectStubPathway = (config) => {
60
+ const existing = config.get('pathways') || {};
61
+ const modified = { ...existing, google_cse: buildStubGooglePathway() };
62
+ config.load({ pathways: modified });
63
+ };
64
+
65
+ // Test: normalization to SearchResponse
66
+
67
+ test('sys_tool_google_search normalizes Google items into SearchResponse', async (t) => {
68
+ setEnv(t);
69
+ const { config, tool } = await loadModules();
70
+ injectStubPathway(config);
71
+
72
+ const resolver = buildResolver();
73
+ const args = { q: 'pokemon', userMessage: 'testing' };
74
+
75
+ const resultStr = await tool.executePathway({ args, runAllPrompts: null, resolver });
76
+ t.truthy(resultStr, 'Should return a stringified JSON response');
77
+
78
+ const result = JSON.parse(resultStr);
79
+ t.is(result._type, 'SearchResponse');
80
+ t.true(Array.isArray(result.value));
81
+
82
+ // Normalized items should match the CSE items length
83
+ const items = result.value;
84
+ t.is(items.length, mockGoogleResponse.items.length);
85
+ t.truthy(items[0].searchResultId);
86
+ t.is(items[0].title, mockGoogleResponse.items[0].title);
87
+ t.is(items[0].url, mockGoogleResponse.items[0].link);
88
+ t.is(items[0].content, mockGoogleResponse.items[0].snippet);
89
+
90
+ // Tool metadata is set
91
+ t.truthy(resolver.tool);
92
+ const toolMeta = JSON.parse(resolver.tool);
93
+ t.is(toolMeta.toolUsed, 'GoogleSearch');
94
+
95
+ restoreEnv(t);
96
+ });