@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
@@ -1,5 +1,8 @@
1
1
  import OpenAIVisionPlugin from "./openAiVisionPlugin.js";
2
2
  import logger from "../../lib/logger.js";
3
+ import { requestState } from '../requestState.js';
4
+ import { addCitationsToResolver } from '../../lib/pathwayTools.js';
5
+ import CortexResponse from '../../lib/cortexResponse.js';
3
6
  import axios from 'axios';
4
7
 
5
8
  async function convertContentItem(item, maxImageSize, plugin) {
@@ -108,35 +111,63 @@ async function fetchImageAsDataURL(imageUrl) {
108
111
 
109
112
  class Claude3VertexPlugin extends OpenAIVisionPlugin {
110
113
 
114
+ constructor(pathway, model) {
115
+ super(pathway, model);
116
+ this.isMultiModal = true;
117
+ this.pathwayToolCallback = pathway.toolCallback;
118
+ this.toolCallsBuffer = [];
119
+ this.contentBuffer = ''; // Initialize content buffer
120
+ this.hadToolCalls = false; // Track if this stream had tool calls
121
+ }
122
+
111
123
  parseResponse(data) {
112
124
  if (!data) {
113
125
  return data;
114
126
  }
115
127
 
116
- const { content } = data;
128
+ const { content, usage, stop_reason } = data;
117
129
 
118
130
  // Handle tool use responses from Claude
119
131
  if (content && Array.isArray(content)) {
120
132
  const toolUses = content.filter(item => item.type === "tool_use");
121
133
  if (toolUses.length > 0) {
122
- return {
123
- role: "assistant",
124
- content: "",
125
- tool_calls: toolUses.map(toolUse => ({
126
- id: toolUse.id,
127
- type: "function",
128
- function: {
129
- name: toolUse.name,
130
- arguments: JSON.stringify(toolUse.input)
131
- }
132
- }))
133
- };
134
+ // Create standardized CortexResponse object for tool calls
135
+ const cortexResponse = new CortexResponse({
136
+ output_text: "",
137
+ finishReason: "tool_calls",
138
+ usage: usage || null,
139
+ metadata: {
140
+ model: this.modelName
141
+ }
142
+ });
143
+
144
+ // Convert Claude tool uses to OpenAI format
145
+ cortexResponse.toolCalls = toolUses.map(toolUse => ({
146
+ id: toolUse.id,
147
+ type: "function",
148
+ function: {
149
+ name: toolUse.name,
150
+ arguments: JSON.stringify(toolUse.input)
151
+ }
152
+ }));
153
+
154
+ return cortexResponse;
134
155
  }
135
156
 
136
157
  // Handle regular text responses
137
158
  const textContent = content.find(item => item.type === "text");
138
159
  if (textContent) {
139
- return textContent.text;
160
+ // Create standardized CortexResponse object for text responses
161
+ const cortexResponse = new CortexResponse({
162
+ output_text: textContent.text || "",
163
+ finishReason: stop_reason === "tool_use" ? "tool_calls" : "stop",
164
+ usage: usage || null,
165
+ metadata: {
166
+ model: this.modelName
167
+ }
168
+ });
169
+
170
+ return cortexResponse;
140
171
  }
141
172
  }
142
173
 
@@ -273,6 +304,10 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
273
304
  requestParameters.messages = modifiedMessages;
274
305
 
275
306
  // Convert OpenAI tools format to Claude format if present
307
+ if (typeof parameters.tools === 'string') {
308
+ parameters.tools = JSON.parse(parameters.tools);
309
+ }
310
+
276
311
  if (parameters.tools) {
277
312
  requestParameters.tools = parameters.tools.map(tool => {
278
313
  if (tool.type === 'function') {
@@ -292,20 +327,31 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
292
327
 
293
328
  if (parameters.tool_choice) {
294
329
  // Convert OpenAI tool_choice format to Claude format
295
- if (typeof parameters.tool_choice === 'string') {
296
- // Handle string values: auto, required, none
297
- if (parameters.tool_choice === 'required') {
298
- requestParameters.tool_choice = { type: 'any' }; // OpenAI's 'required' maps to Claude's 'any'
299
- } else if (parameters.tool_choice === 'auto') {
300
- requestParameters.tool_choice = { type: 'auto' };
301
- } else if (parameters.tool_choice === 'none') {
302
- requestParameters.tool_choice = { type: 'none' };
330
+ let toolChoice = parameters.tool_choice;
331
+
332
+ // Handle JSON string from REST endpoint
333
+ if (typeof toolChoice === 'string') {
334
+ try {
335
+ // Try to parse as JSON first
336
+ toolChoice = JSON.parse(toolChoice);
337
+ } catch (e) {
338
+ // If not JSON, handle as simple string values: auto, required, none
339
+ if (toolChoice === 'required') {
340
+ requestParameters.tool_choice = { type: 'any' }; // OpenAI's 'required' maps to Claude's 'any'
341
+ } else if (toolChoice === 'auto') {
342
+ requestParameters.tool_choice = { type: 'auto' };
343
+ } else if (toolChoice === 'none') {
344
+ requestParameters.tool_choice = { type: 'none' };
345
+ }
303
346
  }
304
- } else if (parameters.tool_choice.type === "function") {
347
+ }
348
+
349
+ // Handle parsed object
350
+ if (toolChoice.type === "function") {
305
351
  // Handle function-specific tool choice
306
352
  requestParameters.tool_choice = {
307
353
  type: "tool",
308
- name: parameters.tool_choice.function.name
354
+ name: toolChoice.function.name || toolChoice.function
309
355
  };
310
356
  }
311
357
  }
@@ -447,8 +493,19 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
447
493
  return this.executeRequest(cortexRequest);
448
494
  }
449
495
 
450
- processStreamEvent(event, requestProgress) {
451
- const eventData = JSON.parse(event.data);
496
+ convertClaudeSSEToOpenAI(event) {
497
+ // Handle end of stream
498
+ if (event.data.trim() === '[DONE]') {
499
+ return event; // Pass through unchanged
500
+ }
501
+
502
+ let eventData;
503
+ try {
504
+ eventData = JSON.parse(event.data);
505
+ } catch (error) {
506
+ throw new Error(`Could not parse stream data: ${error}`);
507
+ }
508
+
452
509
  const baseOpenAIResponse = {
453
510
  id: eventData.message?.id || `chatcmpl-${Date.now()}`,
454
511
  object: "chat.completion.chunk",
@@ -461,50 +518,141 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
461
518
  }]
462
519
  };
463
520
 
521
+ let delta = {};
522
+ let finishReason = null;
523
+
524
+ // Handle errors - convert to OpenAI error format instead of throwing
525
+ const streamError = eventData?.error?.message || eventData?.error;
526
+ if (streamError) {
527
+ delta = {
528
+ content: `\n\n*** ${streamError} ***`
529
+ };
530
+ finishReason = "error";
531
+
532
+ // Update the OpenAI response
533
+ baseOpenAIResponse.choices[0].delta = delta;
534
+ baseOpenAIResponse.choices[0].finish_reason = finishReason;
535
+
536
+ // Create new event with OpenAI format
537
+ return {
538
+ ...event,
539
+ data: JSON.stringify(baseOpenAIResponse)
540
+ };
541
+ }
542
+
543
+ // Handle different Claude event types
464
544
  switch (eventData.type) {
465
545
  case "message_start":
466
- // Initial message with role
467
- baseOpenAIResponse.choices[0].delta = {
468
- role: "assistant",
469
- content: ""
470
- };
471
- requestProgress.data = JSON.stringify(baseOpenAIResponse);
546
+ delta = { role: "assistant", content: "" };
547
+ // Reset tool calls flag for new message
548
+ this.hadToolCalls = false;
472
549
  break;
473
550
 
474
551
  case "content_block_delta":
475
552
  if (eventData.delta.type === "text_delta") {
476
- baseOpenAIResponse.choices[0].delta = {
477
- content: eventData.delta.text
553
+ delta = { content: eventData.delta.text };
554
+ } else if (eventData.delta.type === "input_json_delta") {
555
+ // Handle tool call argument streaming
556
+ const toolCallIndex = eventData.index || 0;
557
+
558
+ // Create OpenAI tool call delta - parent class will handle accumulation
559
+ delta = {
560
+ tool_calls: [{
561
+ index: toolCallIndex,
562
+ id: eventData.id || `call_${toolCallIndex}_${Date.now()}`,
563
+ type: "function",
564
+ function: {
565
+ arguments: eventData.delta.partial_json || ""
566
+ }
567
+ }]
568
+ };
569
+ } else if (eventData.delta.type === "name_delta") {
570
+ // Handle tool call name streaming
571
+ const toolCallIndex = eventData.index || 0;
572
+
573
+ // Create OpenAI tool call delta - parent class will handle accumulation
574
+ delta = {
575
+ tool_calls: [{
576
+ index: toolCallIndex,
577
+ id: eventData.id || `call_${toolCallIndex}_${Date.now()}`,
578
+ type: "function",
579
+ function: {
580
+ name: eventData.delta.name || ""
581
+ }
582
+ }]
478
583
  };
479
- requestProgress.data = JSON.stringify(baseOpenAIResponse);
480
584
  }
481
585
  break;
482
586
 
587
+ case "content_block_start":
588
+ if (eventData.content_block.type === "tool_use") {
589
+ // Mark that we have tool calls in this stream
590
+ this.hadToolCalls = true;
591
+
592
+ // Create OpenAI tool call delta - parent class will handle buffer management
593
+ const toolCallIndex = eventData.index || 0;
594
+ delta = {
595
+ tool_calls: [{
596
+ index: toolCallIndex,
597
+ id: eventData.content_block.id || `call_${toolCallIndex}_${Date.now()}`,
598
+ type: "function",
599
+ function: {
600
+ name: eventData.content_block.name || ""
601
+ }
602
+ }]
603
+ };
604
+ }
605
+ break;
606
+
607
+ case "message_delta":
608
+ // Handle message delta events (like stop_reason)
609
+ // Don't set finish_reason here - let the stream continue until message_stop
610
+ delta = {};
611
+ break;
612
+
483
613
  case "message_stop":
484
- baseOpenAIResponse.choices[0].delta = {};
485
- baseOpenAIResponse.choices[0].finish_reason = "stop";
486
- requestProgress.data = JSON.stringify(baseOpenAIResponse);
487
- requestProgress.progress = 1;
614
+ delta = {};
615
+ // Determine finish reason based on whether there were tool calls in this stream
616
+ if (this.hadToolCalls) {
617
+ finishReason = "tool_calls";
618
+ } else {
619
+ finishReason = "stop";
620
+ }
488
621
  break;
489
622
 
490
623
  case "error":
491
- baseOpenAIResponse.choices[0].delta = {
624
+ delta = {
492
625
  content: `\n\n*** ${eventData.error.message || eventData.error} ***`
493
626
  };
494
- baseOpenAIResponse.choices[0].finish_reason = "error";
495
- requestProgress.data = JSON.stringify(baseOpenAIResponse);
496
- requestProgress.progress = 1;
627
+ finishReason = "error";
497
628
  break;
498
629
 
499
630
  // Ignore other event types as they don't map to OpenAI format
500
- case "content_block_start":
501
631
  case "content_block_stop":
502
632
  case "message_delta":
503
633
  case "ping":
504
634
  break;
505
635
  }
506
636
 
507
- return requestProgress;
637
+ // Update the OpenAI response
638
+ baseOpenAIResponse.choices[0].delta = delta;
639
+ if (finishReason) {
640
+ baseOpenAIResponse.choices[0].finish_reason = finishReason;
641
+ }
642
+
643
+ // Create new event with OpenAI format
644
+ return {
645
+ ...event,
646
+ data: JSON.stringify(baseOpenAIResponse)
647
+ };
648
+ }
649
+
650
+ processStreamEvent(event, requestProgress) {
651
+ // Convert Claude event to OpenAI format
652
+ const openAIEvent = this.convertClaudeSSEToOpenAI(event);
653
+
654
+ // Delegate to parent class for all the tool call logic
655
+ return super.processStreamEvent(openAIEvent, requestProgress);
508
656
  }
509
657
 
510
658
  }
@@ -69,6 +69,27 @@ class Gemini15ChatPlugin extends ModelPlugin {
69
69
  modifiedMessages[modifiedMessages.length - 1].parts.push({ text: content });
70
70
  }
71
71
 
72
+ // Handle tool result messages
73
+ else if (role === 'tool') {
74
+ // Convert OpenAI tool result format to Gemini format
75
+ // OpenAI: { role: 'tool', tool_call_id: '...', content: '...' }
76
+ // Gemini: { role: 'function', parts: [{ functionResponse: { name: '...', response: { content: '...' } } }] }
77
+ const toolCallId = message.tool_call_id || message.toolCallId;
78
+ const toolName = toolCallId ? toolCallId.split('_')[0] : 'unknown_tool';
79
+
80
+ modifiedMessages.push({
81
+ role: 'function',
82
+ parts: [{
83
+ functionResponse: {
84
+ name: toolName,
85
+ response: {
86
+ content: content
87
+ }
88
+ }
89
+ }]
90
+ });
91
+ lastAuthor = 'function';
92
+ }
72
93
  // Push messages that are role: 'user' or 'assistant', changing 'assistant' to 'model'
73
94
  else if (role === 'user' || role === 'assistant' || author) {
74
95
  modifiedMessages.push({