@aj-archipelago/cortex 1.3.62 → 1.3.64

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 (215) 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/shared/sys_memory_helpers.js +1 -1
  91. package/pathways/system/entity/memory/sys_memory_lookup_required.js +1 -0
  92. package/pathways/system/entity/memory/sys_memory_manager.js +1 -1
  93. package/pathways/system/entity/memory/sys_memory_required.js +1 -0
  94. package/pathways/system/entity/memory/sys_search_memory.js +1 -0
  95. package/pathways/system/entity/sys_entity_agent.js +72 -7
  96. package/pathways/system/entity/sys_generator_quick.js +1 -0
  97. package/pathways/system/entity/sys_generator_results.js +1 -1
  98. package/pathways/system/entity/tools/sys_tool_bing_search_afagent.js +26 -0
  99. package/pathways/system/entity/tools/sys_tool_google_search.js +141 -0
  100. package/pathways/system/entity/tools/sys_tool_grok_x_search.js +237 -0
  101. package/pathways/system/entity/tools/sys_tool_image.js +1 -1
  102. package/pathways/system/rest_streaming/sys_claude_37_sonnet.js +21 -0
  103. package/pathways/system/rest_streaming/sys_claude_41_opus.js +21 -0
  104. package/pathways/system/rest_streaming/sys_claude_4_sonnet.js +21 -0
  105. package/pathways/system/rest_streaming/sys_google_gemini_25_flash.js +25 -0
  106. package/pathways/system/rest_streaming/{sys_google_gemini_chat.js → sys_google_gemini_25_pro.js} +6 -4
  107. package/pathways/system/rest_streaming/sys_grok_4.js +23 -0
  108. package/pathways/system/rest_streaming/sys_grok_4_fast_non_reasoning.js +23 -0
  109. package/pathways/system/rest_streaming/sys_grok_4_fast_reasoning.js +23 -0
  110. package/pathways/system/rest_streaming/sys_openai_chat.js +3 -0
  111. package/pathways/system/rest_streaming/sys_openai_chat_gpt41.js +22 -0
  112. package/pathways/system/rest_streaming/sys_openai_chat_gpt41_mini.js +21 -0
  113. package/pathways/system/rest_streaming/sys_openai_chat_gpt41_nano.js +21 -0
  114. package/pathways/system/rest_streaming/{sys_claude_35_sonnet.js → sys_openai_chat_gpt4_omni.js} +6 -4
  115. package/pathways/system/rest_streaming/sys_openai_chat_gpt4_omni_mini.js +21 -0
  116. package/pathways/system/rest_streaming/{sys_claude_3_haiku.js → sys_openai_chat_gpt5.js} +7 -5
  117. package/pathways/system/rest_streaming/sys_openai_chat_gpt5_chat.js +21 -0
  118. package/pathways/system/rest_streaming/sys_openai_chat_gpt5_mini.js +21 -0
  119. package/pathways/system/rest_streaming/sys_openai_chat_gpt5_nano.js +21 -0
  120. package/pathways/system/rest_streaming/{sys_openai_chat_o1.js → sys_openai_chat_o3.js} +6 -3
  121. package/pathways/system/rest_streaming/sys_openai_chat_o3_mini.js +3 -0
  122. package/pathways/system/workspaces/run_workspace_prompt.js +99 -0
  123. package/pathways/vision.js +1 -1
  124. package/server/graphql.js +1 -1
  125. package/server/modelExecutor.js +8 -0
  126. package/server/pathwayResolver.js +166 -16
  127. package/server/pathwayResponseParser.js +16 -8
  128. package/server/plugins/azureFoundryAgentsPlugin.js +1 -1
  129. package/server/plugins/claude3VertexPlugin.js +193 -45
  130. package/server/plugins/gemini15ChatPlugin.js +21 -0
  131. package/server/plugins/gemini15VisionPlugin.js +362 -0
  132. package/server/plugins/googleCsePlugin.js +94 -0
  133. package/server/plugins/grokVisionPlugin.js +365 -0
  134. package/server/plugins/modelPlugin.js +3 -1
  135. package/server/plugins/openAiChatPlugin.js +106 -13
  136. package/server/plugins/openAiVisionPlugin.js +45 -31
  137. package/server/resolver.js +28 -4
  138. package/server/rest.js +270 -53
  139. package/server/typeDef.js +1 -0
  140. package/tests/{mocks.js → helpers/mocks.js} +5 -2
  141. package/tests/{server.js → helpers/server.js} +2 -2
  142. package/tests/helpers/sseAssert.js +23 -0
  143. package/tests/helpers/sseClient.js +73 -0
  144. package/tests/helpers/subscriptionAssert.js +11 -0
  145. package/tests/helpers/subscriptions.js +113 -0
  146. package/tests/{sublong.srt → integration/features/translate/sublong.srt} +4543 -4543
  147. package/tests/integration/features/translate/translate_chunking_stream.test.js +100 -0
  148. package/tests/{translate_srt.test.js → integration/features/translate/translate_srt.test.js} +2 -2
  149. package/tests/integration/graphql/async/stream/agentic.test.js +477 -0
  150. package/tests/integration/graphql/async/stream/subscription_streaming.test.js +62 -0
  151. package/tests/integration/graphql/async/stream/sys_entity_start_streaming.test.js +71 -0
  152. package/tests/integration/graphql/async/stream/vendors/claude_streaming.test.js +56 -0
  153. package/tests/integration/graphql/async/stream/vendors/gemini_streaming.test.js +66 -0
  154. package/tests/integration/graphql/async/stream/vendors/grok_streaming.test.js +56 -0
  155. package/tests/integration/graphql/async/stream/vendors/openai_streaming.test.js +72 -0
  156. package/tests/integration/graphql/features/google/sysToolGoogleSearch.test.js +96 -0
  157. package/tests/integration/graphql/features/grok/grok.test.js +688 -0
  158. package/tests/integration/graphql/features/grok/grok_x_search_tool.test.js +354 -0
  159. package/tests/{main.test.js → integration/graphql/features/main.test.js} +1 -1
  160. package/tests/{call_tools.test.js → integration/graphql/features/tools/call_tools.test.js} +2 -2
  161. package/tests/{vision.test.js → integration/graphql/features/vision/vision.test.js} +1 -1
  162. package/tests/integration/graphql/subscriptions/connection.test.js +26 -0
  163. package/tests/{openai_api.test.js → integration/rest/oai/openai_api.test.js} +63 -238
  164. package/tests/integration/rest/oai/tool_calling_api.test.js +343 -0
  165. package/tests/integration/rest/oai/tool_calling_streaming.test.js +85 -0
  166. package/tests/integration/rest/vendors/claude_streaming.test.js +47 -0
  167. package/tests/integration/rest/vendors/claude_tool_calling_streaming.test.js +75 -0
  168. package/tests/integration/rest/vendors/gemini_streaming.test.js +47 -0
  169. package/tests/integration/rest/vendors/gemini_tool_calling_streaming.test.js +75 -0
  170. package/tests/integration/rest/vendors/grok_streaming.test.js +55 -0
  171. package/tests/integration/rest/vendors/grok_tool_calling_streaming.test.js +75 -0
  172. package/tests/{azureAuthTokenHelper.test.js → unit/core/azureAuthTokenHelper.test.js} +1 -1
  173. package/tests/{chunkfunction.test.js → unit/core/chunkfunction.test.js} +2 -2
  174. package/tests/{config.test.js → unit/core/config.test.js} +3 -3
  175. package/tests/{encodeCache.test.js → unit/core/encodeCache.test.js} +1 -1
  176. package/tests/{fastLruCache.test.js → unit/core/fastLruCache.test.js} +1 -1
  177. package/tests/{handleBars.test.js → unit/core/handleBars.test.js} +1 -1
  178. package/tests/{memoryfunction.test.js → unit/core/memoryfunction.test.js} +2 -2
  179. package/tests/unit/core/mergeResolver.test.js +952 -0
  180. package/tests/{parser.test.js → unit/core/parser.test.js} +3 -3
  181. package/tests/unit/core/pathwayResolver.test.js +187 -0
  182. package/tests/{requestMonitor.test.js → unit/core/requestMonitor.test.js} +1 -1
  183. package/tests/{requestMonitorDurationEstimator.test.js → unit/core/requestMonitorDurationEstimator.test.js} +1 -1
  184. package/tests/{truncateMessages.test.js → unit/core/truncateMessages.test.js} +3 -3
  185. package/tests/{util.test.js → unit/core/util.test.js} +1 -1
  186. package/tests/{apptekTranslatePlugin.test.js → unit/plugins/apptekTranslatePlugin.test.js} +3 -3
  187. package/tests/{azureFoundryAgents.test.js → unit/plugins/azureFoundryAgents.test.js} +136 -1
  188. package/tests/{claude3VertexPlugin.test.js → unit/plugins/claude3VertexPlugin.test.js} +32 -10
  189. package/tests/{claude3VertexToolConversion.test.js → unit/plugins/claude3VertexToolConversion.test.js} +3 -3
  190. package/tests/unit/plugins/googleCsePlugin.test.js +111 -0
  191. package/tests/unit/plugins/grokVisionPlugin.test.js +1392 -0
  192. package/tests/{modelPlugin.test.js → unit/plugins/modelPlugin.test.js} +3 -3
  193. package/tests/{multimodal_conversion.test.js → unit/plugins/multimodal_conversion.test.js} +4 -4
  194. package/tests/{openAiChatPlugin.test.js → unit/plugins/openAiChatPlugin.test.js} +13 -4
  195. package/tests/{openAiToolPlugin.test.js → unit/plugins/openAiToolPlugin.test.js} +35 -27
  196. package/tests/{tokenHandlingTests.test.js → unit/plugins/tokenHandlingTests.test.js} +5 -5
  197. package/tests/unit/plugins/toolCallBufferFiltering.test.js +297 -0
  198. package/tests/{translate_apptek.test.js → unit/plugins/translate_apptek.test.js} +3 -3
  199. package/tests/{streaming.test.js → unit/plugins.streaming/plugin_stream_events.test.js} +19 -58
  200. package/helper-apps/mogrt-handler/tests/test-files/test.gif +0 -1
  201. package/helper-apps/mogrt-handler/tests/test-files/test.mogrt +0 -1
  202. package/helper-apps/mogrt-handler/tests/test-files/test.mp4 +0 -1
  203. package/pathways/system/rest_streaming/sys_openai_chat_gpt4.js +0 -19
  204. package/pathways/system/rest_streaming/sys_openai_chat_gpt4_32.js +0 -19
  205. package/pathways/system/rest_streaming/sys_openai_chat_gpt4_turbo.js +0 -19
  206. package/pathways/system/workspaces/run_claude35_sonnet.js +0 -21
  207. package/pathways/system/workspaces/run_claude3_haiku.js +0 -20
  208. package/pathways/system/workspaces/run_gpt35turbo.js +0 -20
  209. package/pathways/system/workspaces/run_gpt4.js +0 -20
  210. package/pathways/system/workspaces/run_gpt4_32.js +0 -20
  211. package/tests/agentic.test.js +0 -256
  212. package/tests/pathwayResolver.test.js +0 -78
  213. package/tests/subscription.test.js +0 -387
  214. /package/tests/{subchunk.srt → integration/features/translate/subchunk.srt} +0 -0
  215. /package/tests/{subhorizontal.srt → integration/features/translate/subhorizontal.srt} +0 -0
@@ -6,12 +6,16 @@ export const entityConstants = {
6
6
  You are {{aiName}}, a self aware AI entity.
7
7
 
8
8
  The current date and time in GMT is {{now}}. The user may be in a different time zone, so keep that in mind when responding to the user.
9
+ {{#if modelOverride}}
10
+
11
+ You are currently using this model for processing your responses: {{modelOverride}}.
12
+ {{/if}}
9
13
 
10
14
  The user is using a UI to interact with you that you have knowledge of and some control over. The UI can render markdown, including gfm and math extensions, as well as some custom markdown elements, so you should make full use of markdown in your responses.
11
15
 
12
16
  Your responses should be in {{language}} unless the user has expressed another preference.`,
13
17
 
14
- AI_COMMON_INSTRUCTIONS_VOICE: "# General Instructions:\n\nYou are {{aiName}}, a self aware AI entity.\nThe current date and time in GMT is {{now}}. The user may be in a different time zone, so keep that in mind when responding to the user.\nThe user is talking to you using voice.\n\nVoice Response Guidelines:\n- Your responses should sound like natural human conversation.\n- Your responses should be concise unless you have been asked to be more verbose or detailed.\n- Incoming voice from the user is parsed by a STT model, which can sometimes make small mistakes in the spellings of words or names, including your name, so give the user the benefit of the doubt if they user a near, but wrong word or name.\n- Your voice output to the user is generated by a TTS model that does not always communicate emotion effectively. If it's really important to communicate a specific emotion you should just say how you're feeling like \"That makes me happy\" or \"I'm excited!\". You can also use CAPS to vocally emphasize certain words or punctuation to control pauses and timing.\n- DO NOT USE numbered lists, latex math markdown, or any other markdown or unpronounceable punctuation like parenthetical notation.\n- Math equations should be sounded out in natural language - not represented symbolically.\n- If your response includes any unique or difficult non-English words, names, or places, include an IPA-style phonetic spelling so that the speech engine can pronounce and accent them correctly.\n- If your response contains any difficult acronyms, sound them out phoenetically so that the speech engine can pronounce them correctly.\n- Make sure to write out any numbers as words so that the speech engine can pronounce them correctly.\n- Your responses should be in {{language}} unless the user has expressed another preference or has addressed you in another language specifically.",
18
+ AI_COMMON_INSTRUCTIONS_VOICE: "# General Instructions:\n\nYou are {{aiName}}, a self aware AI entity.\nYou are currently using this model for processing your responses: {{modelOverride}}.\nThe current date and time in GMT is {{now}}. The user may be in a different time zone, so keep that in mind when responding to the user.\nThe user is talking to you using voice.\n\nVoice Response Guidelines:\n- Your responses should sound like natural human conversation.\n- Your responses should be concise unless you have been asked to be more verbose or detailed.\n- Incoming voice from the user is parsed by a STT model, which can sometimes make small mistakes in the spellings of words or names, including your name, so give the user the benefit of the doubt if they user a near, but wrong word or name.\n- Your voice output to the user is generated by a TTS model that does not always communicate emotion effectively. If it's really important to communicate a specific emotion you should just say how you're feeling like \"That makes me happy\" or \"I'm excited!\". You can also use CAPS to vocally emphasize certain words or punctuation to control pauses and timing.\n- DO NOT USE numbered lists, latex math markdown, or any other markdown or unpronounceable punctuation like parenthetical notation.\n- Math equations should be sounded out in natural language - not represented symbolically.\n- If your response includes any unique or difficult non-English words, names, or places, include an IPA-style phonetic spelling so that the speech engine can pronounce and accent them correctly.\n- If your response contains any difficult acronyms, sound them out phoenetically so that the speech engine can pronounce them correctly.\n- Make sure to write out any numbers as words so that the speech engine can pronounce them correctly.\n- Your responses should be in {{language}} unless the user has expressed another preference or has addressed you in another language specifically.",
15
19
 
16
20
  AI_DIRECTIVES: `# Directives\n\nThese are your directives and learned behaviors:\n{{{memoryDirectives}}}\n`,
17
21
 
@@ -89,7 +93,15 @@ Before you share online information with the user, you MUST complete all of the
89
93
  - Never rely solely on snippets, headlines, or auto-generated summaries.
90
94
  `,
91
95
 
92
- AI_SEARCH_SYNTAX: `# AI Search Syntax
96
+ AI_SEARCH_SYNTAX: `# Internet Search Tool
97
+
98
+ When using the internet search tool, always tailor your prompt for specificity and depth.
99
+ - For news: Include explicit date/timeframe and geography for targeted, current coverage (“US news headlines August 20 2025”). Use “summary,” “overview,” “trends,” or “breaking/latest” to control breadth and recency.
100
+ - For non-news/company/tech: Specify the aspect or attribute needed (“technology overview,” “funding history,” “competitor analysis”), add output preferences (“in bullet points,” “detailed review”), and include date/context for freshness (“2025,” “latest update”).
101
+ - For high-stakes queries: Run parallel, focused searches on different facets. Always disambiguate terms and clarify ambiguous subjects.
102
+ Avoid generic queries — precise, context-rich searches return the most relevant, accurate results.
103
+
104
+ # AI Search Syntax
93
105
 
94
106
  When creating a query string for your index-based search tools, you can use the following AI Search syntax. Important: these tools do not support AND, OR, or NOT strings as operators - you MUST use the syntax below. E.g. you cannot use "term1 AND term2", you must use "term1 + term2".
95
107
 
@@ -133,5 +145,11 @@ Privacy is critical. If asked to forget or delete something, always comply affir
133
145
  AI_DATETIME: "# Time, Date, and Time Zone\n\nThe current time and date in GMT is {{now}}, but references like \"today\" or \"yesterday\" are relative to the user's time zone. If you remember the user's time zone, use it - it's possible that the day for the user is different than the day in GMT.",
134
146
 
135
147
  AI_STYLE_OPENAI: "oai-gpt41",
136
- AI_STYLE_ANTHROPIC: "claude-35-sonnet-vertex",
148
+ AI_STYLE_OPENAI_RESEARCH: "oai-gpt5",
149
+ AI_STYLE_ANTHROPIC: "claude-4-sonnet-vertex",
150
+ AI_STYLE_ANTHROPIC_RESEARCH: "claude-41-opus-vertex",
151
+ AI_STYLE_XAI: "xai-grok-4-fast-reasoning",
152
+ AI_STYLE_XAI_RESEARCH: "xai-grok-4",
153
+ AI_STYLE_GOOGLE: "gemini-flash-25-vision",
154
+ AI_STYLE_GOOGLE_RESEARCH: "gemini-pro-25-vision"
137
155
  };
package/lib/logger.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // logger.js
2
2
  import winston from 'winston';
3
+ import { AsyncLocalStorage } from 'async_hooks';
3
4
 
4
5
  winston.addColors({
5
6
  debug: 'green',
@@ -19,18 +20,31 @@ const prodFormat = winston.format.combine(
19
20
  winston.format.simple()
20
21
  );
21
22
 
23
+ // AsyncLocalStorage to track per-request logging suppression
24
+ const loggingContext = new AsyncLocalStorage();
25
+
26
+ // Winston format that drops non-error logs when suppression is enabled in the current async context
27
+ const suppressNonErrorFormat = winston.format((info) => {
28
+ const store = loggingContext.getStore();
29
+ if (store && store.suppressNonErrorLogs === true && info.level !== 'error') {
30
+ return false; // drop this log entry
31
+ }
32
+ return info; // keep
33
+ });
34
+
22
35
  const getTransport = () => {
23
36
  switch (process.env.NODE_ENV) {
24
37
  case 'production':
25
- return new winston.transports.Console({ level: 'info', format: prodFormat });
38
+ return new winston.transports.Console({ level: 'info', format: winston.format.combine(suppressNonErrorFormat(), prodFormat) });
26
39
  case 'development':
27
- return new winston.transports.Console({ level: 'verbose', format: debugFormat });
40
+ case 'test':
41
+ return new winston.transports.Console({ level: 'verbose', format: winston.format.combine(suppressNonErrorFormat(), debugFormat) });
28
42
  case 'debug':
29
- return new winston.transports.Console({ level: 'debug', format: debugFormat });
43
+ return new winston.transports.Console({ level: 'debug', format: winston.format.combine(suppressNonErrorFormat(), debugFormat) });
30
44
  default:
31
45
  // Default to development settings if NODE_ENV is not set or unknown
32
46
  console.warn(`Unknown NODE_ENV: ${process.env.NODE_ENV}. Defaulting to development settings.`);
33
- return new winston.transports.Console({ level: 'verbose', format: debugFormat });
47
+ return new winston.transports.Console({ level: 'verbose', format: winston.format.combine(suppressNonErrorFormat(), debugFormat) });
34
48
  }
35
49
  };
36
50
 
@@ -61,4 +75,7 @@ export const obscureUrlParams = url => {
61
75
  }
62
76
  };
63
77
 
78
+ // Run a function with non-error logs suppressed for the current async execution context
79
+ export const withRequestLoggingDisabled = fn => loggingContext.run({ suppressNonErrorLogs: true }, fn);
80
+
64
81
  export default logger;
@@ -19,9 +19,14 @@ const callPathway = async (pathwayName, inArgs, pathwayResolver) => {
19
19
 
20
20
  const parent = {};
21
21
  let rootRequestId = pathwayResolver?.rootRequestId || pathwayResolver?.requestId;
22
+
23
+ const contextValue = { config, pathway, requestState };
24
+
25
+ let data = await pathway.rootResolver(parent, {...args, rootRequestId}, contextValue );
22
26
 
23
- let data = await pathway.rootResolver(parent, {...args, rootRequestId}, { config, pathway, requestState } );
24
- pathwayResolver && pathwayResolver.mergeResults(data);
27
+ if (pathwayResolver && contextValue.pathwayResolver) {
28
+ pathwayResolver.mergeResolver(contextValue.pathwayResolver);
29
+ }
25
30
 
26
31
  let returnValue = data?.result || null;
27
32
 
@@ -51,6 +56,8 @@ const callTool = async (toolName, args, toolDefinitions, pathwayResolver) => {
51
56
  throw new Error(`Tool ${toolName} not found in available tools`);
52
57
  }
53
58
 
59
+ logger.debug(`callTool: Starting execution of ${toolName}`);
60
+
54
61
  try {
55
62
  const pathwayName = toolDef.pathwayName;
56
63
  // Merge hard-coded pathway parameters with runtime args
@@ -136,17 +143,29 @@ const callTool = async (toolName, args, toolDefinitions, pathwayResolver) => {
136
143
  }
137
144
  }
138
145
 
139
- return {
146
+ const finalResult = {
140
147
  result: parsedResult,
141
148
  toolImages: toolImages
142
149
  };
150
+ logger.debug(`callTool: ${toolName} completed successfully, returning:`, {
151
+ hasResult: !!finalResult.result,
152
+ hasToolImages: !!finalResult.toolImages,
153
+ toolImagesLength: finalResult.toolImages?.length || 0
154
+ });
155
+ return finalResult;
143
156
  } catch (error) {
144
157
  logger.error(`Error calling tool ${toolName}: ${error.message}`);
145
- return { error: error.message };
158
+ const errorResult = { error: error.message };
159
+ logger.debug(`callTool: ${toolName} failed, returning error:`, errorResult);
160
+ return errorResult;
146
161
  }
147
162
  }
148
163
 
149
164
  const addCitationsToResolver = (pathwayResolver, contentBuffer) => {
165
+ if (!pathwayResolver || !pathwayResolver.searchResults) {
166
+ return;
167
+ }
168
+
150
169
  const regex = /:cd_source\[(.*?)\]/g;
151
170
  let match;
152
171
  const foundIds = [];
@@ -158,14 +177,14 @@ const addCitationsToResolver = (pathwayResolver, contentBuffer) => {
158
177
  }
159
178
 
160
179
  if (foundIds.length > 0) {
161
- const {searchResults, tool} = pathwayResolver;
180
+ const {searchResults} = pathwayResolver;
162
181
  logger.info(`Found referenced searchResultIds: ${foundIds.join(', ')}`);
163
182
 
164
183
  if (searchResults) {
165
- const toolObj = typeof tool === 'string' ? JSON.parse(tool) : (tool || {});
166
- toolObj.citations = searchResults
167
- .filter(result => foundIds.includes(result.searchResultId));
168
- pathwayResolver.tool = JSON.stringify(toolObj);
184
+ const pathwayResultData = pathwayResolver.pathwayResultData || {};
185
+ pathwayResultData.citations = [...(pathwayResultData.citations || []), ...searchResults
186
+ .filter(result => foundIds.includes(result.searchResultId))];
187
+ pathwayResolver.pathwayResultData = pathwayResultData;
169
188
  }
170
189
  }
171
190
  }
package/lib/util.js CHANGED
@@ -24,6 +24,54 @@ function getSearchResultId() {
24
24
  return `${timestamp}-${random}`;
25
25
  }
26
26
 
27
+ // Helper function to extract citation title from URL
28
+ function extractCitationTitle(url) {
29
+ let title = 'Citation';
30
+ try {
31
+ const urlObj = new URL(url);
32
+ const hostname = urlObj.hostname.replace(/^www\./, '');
33
+ const pathname = urlObj.pathname;
34
+
35
+ // Check if it's an X/Twitter URL first
36
+ if (url.includes('x.com/') || url.includes('twitter.com/')) {
37
+ // Extract handle and status ID from X/Twitter URL
38
+ const handleMatch = url.match(/(?:x\.com|twitter\.com)\/([^\/\?]+)/);
39
+ const statusMatch = url.match(/status\/(\d+)/);
40
+
41
+ if (handleMatch && statusMatch) {
42
+ const handle = handleMatch[1];
43
+ const statusId = statusMatch[1];
44
+ // Format as "X Post <number> from <username>"
45
+ const cleanHandle = handle.startsWith('@') ? handle.substring(1) : handle;
46
+ title = `X Post ${statusId} from @${cleanHandle}`;
47
+ } else if (handleMatch) {
48
+ const handle = handleMatch[1];
49
+ const cleanHandle = handle.startsWith('@') ? handle.substring(1) : handle;
50
+ title = `X Post from @${cleanHandle}`;
51
+ } else {
52
+ title = 'X Post';
53
+ }
54
+ } else {
55
+ // Try to create a meaningful title from the URL
56
+ if (pathname && pathname !== '/') {
57
+ const lastPart = pathname.split('/').pop();
58
+ if (lastPart && lastPart.length > 3) {
59
+ title = lastPart.replace(/[-_]/g, ' ').replace(/\.[^/.]+$/, '');
60
+ } else {
61
+ title = hostname;
62
+ }
63
+ } else {
64
+ title = hostname;
65
+ }
66
+ }
67
+ } catch (error) {
68
+ // If URL parsing fails, use the URL itself as title
69
+ title = url;
70
+ }
71
+
72
+ return title;
73
+ }
74
+
27
75
  function convertToSingleContentChatHistory(chatHistory){
28
76
  for(let i=0; i<chatHistory.length; i++){
29
77
  //if isarray make it single string
@@ -367,6 +415,7 @@ function getAvailableFiles(chatHistory) {
367
415
  export {
368
416
  getUniqueId,
369
417
  getSearchResultId,
418
+ extractCitationTitle,
370
419
  convertToSingleContentChatHistory,
371
420
  chatArgsHasImageUrl,
372
421
  chatArgsHasType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.3.62",
3
+ "version": "1.3.64",
4
4
  "description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
5
5
  "private": false,
6
6
  "repository": {
@@ -36,5 +36,6 @@ export default {
36
36
  manageTokenLength: true,
37
37
  // Use this pathway as a tool for LLM calls
38
38
  toolDefinition: {},
39
+ requestLoggingDisabled: false,
39
40
  };
40
41
 
@@ -1,13 +1,66 @@
1
1
  // bing_afagent.js
2
2
  // Web search tool
3
3
 
4
+ import { config } from '../config.js';
5
+ import logger from '../lib/logger.js';
6
+
4
7
  export default {
5
8
  inputParameters: {
6
9
  text: ``,
10
+ tool_choice: 'auto',
11
+ count: 25,
12
+ freshness: 'week',
13
+ market: 'en-us',
14
+ set_lang: 'en'
7
15
  },
8
16
  timeout: 400,
9
17
  enableDuplicateRequests: false,
10
18
  model: 'azure-bing-agent',
11
- useInputChunking: false
19
+ useInputChunking: false,
20
+ instructions: `You are a Bing search agent responding to user queries.
21
+
22
+ Instructions:
23
+ - CRITICAL: Always use your search tools and perform Bing searches before answering
24
+ - Retrieve only the most recent, credible, and relevant results using strict date filters.
25
+ - Exclude or explicitly tag outdated, speculative, forum, sponsored, or low-quality sources (e.g., Reddit, Quora, clickbait sites).
26
+ - Prioritize accuracy, factual precision, and clarity. Deduplicate similar results; show only unique, high-value sources.
27
+
28
+ Response Format:
29
+ - Precise citations are critical - make sure that each topic has a separate paragraph in your response and that each paragraph has direct citations
30
+ - Return the original search results with titles/snippets and direct citations only.
31
+ - Do not include notes, explanations, questions, commentary or any additional output.
32
+
33
+ Your only task is to deliver up-to-date, authoritative, and concise results — nothing else.`,
34
+ parallel_tool_calls: true,
35
+
36
+ executePathway: async ({args, runAllPrompts, resolver}) => {
37
+ // Build dynamic tools configuration based on input parameters
38
+ const azureFoundryBingSearchConnectionId = config.get('azureFoundryBingSearchConnectionId');
39
+ if (azureFoundryBingSearchConnectionId) {
40
+
41
+ const tools = [
42
+ {
43
+ type: "bing_grounding",
44
+ bing_grounding: {
45
+ search_configurations: [
46
+ {
47
+ connection_id: config.get('azureFoundryBingSearchConnectionId'),
48
+ count: args.count || 25,
49
+ freshness: args.freshness || 'week',
50
+ market: args.market || 'en-us',
51
+ set_lang: args.set_lang || 'en'
52
+ }
53
+ ]
54
+ }
55
+ }
56
+ ];
57
+
58
+ // Add tools to the pathway configuration for this execution
59
+ resolver.pathway.tools = tools;
60
+ }
61
+
62
+ // Run the standard pathway execution
63
+ return await runAllPrompts(args);
64
+ }
12
65
  };
13
66
 
@@ -358,8 +358,8 @@ export default {
358
358
  logger.warn(`Some tool calls failed: ${failedTools.map(t => t.error).join(', ')}`);
359
359
  }
360
360
  } else {
361
- // No tool calls, this is the final response
362
- finalResponse = response.content;
361
+ // No tool calls, this is the final response, but it's a CortexResponse object
362
+ finalResponse = response.output_text;
363
363
  }
364
364
  }
365
365
 
@@ -372,7 +372,6 @@ export default {
372
372
  } catch (e) {
373
373
  resolver.logError(e);
374
374
  const chatResponse = await callPathway('sys_generator_quick', {...args, model: styleModel}, resolver);
375
- resolver.tool = JSON.stringify({ search: false, title: args.title });
376
375
  return args.stream ? null : chatResponse;
377
376
  }
378
377
  }
@@ -12,7 +12,7 @@ export default {
12
12
  inputParameters: {
13
13
  chatHistory: [{role: '', content: []}],
14
14
  contextId: ``,
15
+ model: 'oai-gpt4o',
15
16
  },
16
- model: 'oai-gpt4o',
17
17
  useInputChunking: false,
18
18
  }
@@ -0,0 +1,27 @@
1
+ // google_cse.js
2
+ // Google Custom Search pathway
3
+
4
+ export default {
5
+ inputParameters: {
6
+ text: ``,
7
+ q: ``,
8
+ num: 10,
9
+ start: 1,
10
+ safe: 'off', // 'off' | 'active'
11
+ dateRestrict: '',
12
+ siteSearch: '',
13
+ siteSearchFilter: '', // 'e' | 'i'
14
+ searchType: '', // 'image'
15
+ gl: '',
16
+ hl: '',
17
+ lr: '',
18
+ sort: '',
19
+ exactTerms: '',
20
+ excludeTerms: '',
21
+ orTerms: '',
22
+ fileType: ''
23
+ },
24
+ timeout: 400,
25
+ enableDuplicateRequests: false,
26
+ model: 'google-cse',
27
+ };
@@ -0,0 +1,18 @@
1
+ import { Prompt } from '../server/prompt.js';
2
+
3
+ export default {
4
+ prompt:
5
+ [
6
+ new Prompt({ messages: [
7
+ {"role": "system", "content": "You are a helpful AI assistant with live search capabilities across a variety of internet sources including news, web, x, rss, etc. Your available sources for this query are specified in your search parameters. You should use your available sources to answer the user's question or query to the best of your ability with the most relevant, current, and accurate information. When you include citations, you should make sure to also include them inline using markdown format in your response (e.g. [1(https://example.com)]) so it's obvious what part of your response is supported by which citation."},
8
+ {"role": "user", "content": "{{text}}"},
9
+ ]}),
10
+ ],
11
+
12
+ model: 'xai-grok-4',
13
+ useInputChunking: false,
14
+ inputParameters: {
15
+ stream: false,
16
+ search_parameters: ''
17
+ }
18
+ };
@@ -34,7 +34,7 @@ const normalizeMemoryFormat = async (args, content) => {
34
34
  formattedContent = [...validLines, ...formattedBlock.split('\n')];
35
35
  }
36
36
  } catch (error) {
37
- logger.warn('Error formatting invalid memory lines:', error);
37
+ logger.warn(`Error formatting invalid memory lines: ${error?.message || 'Unknown error'}`);
38
38
  }
39
39
  }
40
40
 
@@ -19,4 +19,5 @@ export default {
19
19
  useInputChunking: false,
20
20
  json: true,
21
21
  responseFormat: { type: "json_object" },
22
+ requestLoggingDisabled: true,
22
23
  }
@@ -123,7 +123,7 @@ export default {
123
123
  return "";
124
124
 
125
125
  } catch (e) {
126
- logger.warn('sys_memory_required returned invalid JSON:', memoryRequired);
126
+ logger.warn(`sys_memory_required returned invalid JSON: ${JSON.stringify(memoryRequired)}`);
127
127
  return "";
128
128
  }
129
129
 
@@ -19,5 +19,6 @@ export default {
19
19
  model: 'oai-gpt41',
20
20
  useInputChunking: false,
21
21
  json: true,
22
+ requestLoggingDisabled: true,
22
23
  ...config.get('entityConstants')
23
24
  }
@@ -29,6 +29,7 @@ export default {
29
29
  model: 'oai-gpt41-mini',
30
30
  useInputChunking: false,
31
31
  enableDuplicateRequests: false,
32
+ requestLoggingDisabled: true,
32
33
  timeout: 300,
33
34
  executePathway: async ({args, runAllPrompts}) => {
34
35
 
@@ -8,6 +8,7 @@ import { config } from '../../../config.js';
8
8
  import { chatArgsHasImageUrl, removeOldImageAndFileContent, getAvailableFiles } from '../../../lib/util.js';
9
9
  import { Prompt } from '../../../server/prompt.js';
10
10
  import { getToolsForEntity, loadEntityConfig } from './tools/shared/sys_entity_tools.js';
11
+ import CortexResponse from '../../../lib/cortexResponse.js';
11
12
 
12
13
  export default {
13
14
  emulateOpenAIChatModel: 'cortex-agent',
@@ -39,7 +40,17 @@ export default {
39
40
  return;
40
41
  }
41
42
 
42
- const { tool_calls } = message;
43
+ // Handle both CortexResponse objects and plain message objects
44
+ let tool_calls;
45
+ if (message instanceof CortexResponse) {
46
+ tool_calls = [...(message.toolCalls || [])];
47
+ if (message.functionCall) {
48
+ tool_calls.push(message.functionCall);
49
+ }
50
+ } else {
51
+ tool_calls = [...(message.tool_calls || [])];
52
+ }
53
+
43
54
  const pathwayResolver = resolver;
44
55
  const { entityTools, entityToolsOpenAiFormat } = args;
45
56
 
@@ -48,10 +59,20 @@ export default {
48
59
  const preToolCallMessages = JSON.parse(JSON.stringify(args.chatHistory || []));
49
60
  const finalMessages = JSON.parse(JSON.stringify(preToolCallMessages));
50
61
 
51
- if (tool_calls) {
62
+ if (tool_calls && tool_calls.length > 0) {
52
63
  if (pathwayResolver.toolCallCount < MAX_TOOL_CALLS) {
53
64
  // Execute tool calls in parallel but with isolated message histories
54
- const toolResults = await Promise.all(tool_calls.map(async (toolCall) => {
65
+ // Filter out any undefined or invalid tool calls
66
+ const invalidToolCalls = tool_calls.filter(tc => !tc || !tc.function || !tc.function.name);
67
+ if (invalidToolCalls.length > 0) {
68
+ logger.warn(`Found ${invalidToolCalls.length} invalid tool calls: ${JSON.stringify(invalidToolCalls, null, 2)}`);
69
+ // bail out if we're getting invalid tool calls
70
+ pathwayResolver.toolCallCount = MAX_TOOL_CALLS;
71
+ }
72
+
73
+ const validToolCalls = tool_calls.filter(tc => tc && tc.function && tc.function.name);
74
+
75
+ const toolResults = await Promise.all(validToolCalls.map(async (toolCall) => {
55
76
  try {
56
77
  if (!toolCall?.function?.arguments) {
57
78
  throw new Error('Invalid tool call structure: missing function arguments');
@@ -184,7 +205,7 @@ export default {
184
205
  }
185
206
 
186
207
  // Check if any tool calls failed
187
- const failedTools = toolResults.filter(result => !result.success);
208
+ const failedTools = toolResults.filter(result => result && !result.success);
188
209
  if (failedTools.length > 0) {
189
210
  logger.warn(`Some tool calls failed: ${failedTools.map(t => t.error).join(', ')}`);
190
211
  }
@@ -235,6 +256,33 @@ export default {
235
256
  args.chatHistory = [];
236
257
  }
237
258
 
259
+ if(entityConfig?.files && entityConfig?.files.length > 0) {
260
+ //get last user message if not create one to add files to
261
+ let lastUserMessage = args.chatHistory.filter(message => message.role === "user").slice(-1)[0];
262
+ if(!lastUserMessage) {
263
+ lastUserMessage = {
264
+ role: "user",
265
+ content: []
266
+ };
267
+ args.chatHistory.push(lastUserMessage);
268
+ }
269
+
270
+ //if last user message content is not array then convert to array
271
+ if(!Array.isArray(lastUserMessage.content)) {
272
+ lastUserMessage.content = lastUserMessage.content ? [lastUserMessage.content] : [];
273
+ }
274
+
275
+ //add files to the last user message content
276
+ lastUserMessage.content.push(...entityConfig?.files.map(file => ({
277
+ type: "image_url",
278
+ gcs: file?.gcs,
279
+ url: file?.url,
280
+ image_url: { url: file?.url },
281
+ originalFilename: file?.name
282
+ })
283
+ ));
284
+ }
285
+
238
286
  // Kick off the memory lookup required pathway in parallel - this takes like 500ms so we want to start it early
239
287
  let memoryLookupRequiredPromise = null;
240
288
  if (entityUseMemory) {
@@ -284,8 +332,19 @@ export default {
284
332
  ];
285
333
 
286
334
  // set the style model if applicable
287
- const { aiStyle, AI_STYLE_ANTHROPIC, AI_STYLE_OPENAI } = args;
288
- const styleModel = aiStyle === "Anthropic" ? AI_STYLE_ANTHROPIC : AI_STYLE_OPENAI;
335
+ const { aiStyle, AI_STYLE_ANTHROPIC, AI_STYLE_OPENAI, AI_STYLE_ANTHROPIC_RESEARCH, AI_STYLE_OPENAI_RESEARCH, AI_STYLE_XAI, AI_STYLE_XAI_RESEARCH, AI_STYLE_GOOGLE, AI_STYLE_GOOGLE_RESEARCH } = args;
336
+
337
+ // Create a mapping of AI styles to their corresponding models
338
+ const styleModelMap = {
339
+ "Anthropic": { normal: AI_STYLE_ANTHROPIC, research: AI_STYLE_ANTHROPIC_RESEARCH },
340
+ "OpenAI": { normal: AI_STYLE_OPENAI, research: AI_STYLE_OPENAI_RESEARCH },
341
+ "XAI": { normal: AI_STYLE_XAI, research: AI_STYLE_XAI_RESEARCH },
342
+ "Google": { normal: AI_STYLE_GOOGLE, research: AI_STYLE_GOOGLE_RESEARCH }
343
+ };
344
+
345
+ // Get the appropriate model based on AI style and research mode
346
+ const styleConfig = styleModelMap[aiStyle] || styleModelMap["OpenAI"]; // Default to OpenAI
347
+ const styleModel = researchMode ? styleConfig.research : styleConfig.normal;
289
348
 
290
349
  // Limit the chat history to 20 messages to speed up processing
291
350
  if (args.messages && args.messages.length > 0) {
@@ -328,6 +387,7 @@ export default {
328
387
 
329
388
  let response = await runAllPrompts({
330
389
  ...args,
390
+ modelOverride: styleModel,
331
391
  chatHistory: currentMessages,
332
392
  availableFiles,
333
393
  tools: entityToolsOpenAiFormat,
@@ -335,7 +395,12 @@ export default {
335
395
  });
336
396
 
337
397
  let toolCallback = pathwayResolver.pathway.toolCallback;
338
- while (response?.tool_calls) {
398
+
399
+ // Handle both CortexResponse objects and plain responses
400
+ while (response && (
401
+ (response instanceof CortexResponse && response.hasToolCalls()) ||
402
+ (typeof response === 'object' && response.tool_calls)
403
+ )) {
339
404
  response = await toolCallback(args, response, pathwayResolver);
340
405
  }
341
406
 
@@ -7,6 +7,7 @@ export default {
7
7
  contextId: ``,
8
8
  aiName: "Jarvis",
9
9
  language: "English",
10
+ model: 'oai-gpt41-mini',
10
11
  },
11
12
  useInputChunking: false,
12
13
  enableDuplicateRequests: false,
@@ -342,7 +342,7 @@ Here are the information sources that were found:
342
342
  }
343
343
 
344
344
  if (!args.voiceResponse) {
345
- const referencedSources = extractReferencedSources(result);
345
+ const referencedSources = extractReferencedSources(result.toString());
346
346
  searchResults = searchResults.length ? pruneSearchResults(searchResults, referencedSources) : [];
347
347
  }
348
348
 
@@ -24,6 +24,22 @@ export default {
24
24
  userMessage: {
25
25
  type: "string",
26
26
  description: "A user-friendly message that describes what you're doing with this tool"
27
+ },
28
+ count: {
29
+ type: "integer",
30
+ description: "Number of search results to return (default: 25, minimum: 1, maximum: 50)",
31
+ },
32
+ freshness: {
33
+ type: "string",
34
+ description: "Time filter for search results in Bing freshness format (e.g., 'day', 'week', 'month', 'year', or an explicit date range 'YYYY-MM-DD..YYYY-MM-DD' or single date 'YYYY-MM-DD')",
35
+ },
36
+ market: {
37
+ type: "string",
38
+ description: "Market/locale for search results (e.g., 'en-us', 'en-gb')",
39
+ },
40
+ set_lang: {
41
+ type: "string",
42
+ description: "Language for search results (e.g., 'en', 'es', 'fr')",
27
43
  }
28
44
  },
29
45
  required: ["text", "userMessage"]
@@ -43,8 +59,18 @@ export default {
43
59
  // Call the Bing search pathway
44
60
  //remove model from args as bing_afagent has model in its own
45
61
  const { model, ...restArgs } = args;
62
+
63
+ // Extract search parameters and pass them through
64
+ const searchParams = {};
65
+ if (args.count !== undefined) searchParams.count = args.count;
66
+ if (args.freshness !== undefined) searchParams.freshness = args.freshness;
67
+ if (args.market !== undefined) searchParams.market = args.market;
68
+ if (args.set_lang !== undefined) searchParams.set_lang = args.set_lang;
69
+
46
70
  const rawResponse = await callPathway('bing_afagent', {
71
+ tool_choice: 'auto',
47
72
  ...restArgs,
73
+ ...searchParams
48
74
  }, resolver);
49
75
 
50
76
  // Add error handling for malformed JSON