@librechat/agents 3.2.32 → 3.2.33

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 (573) hide show
  1. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  2. package/dist/cjs/agents/AgentContext.cjs +844 -1046
  3. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  4. package/dist/cjs/common/constants.cjs +13 -13
  5. package/dist/cjs/common/constants.cjs.map +1 -1
  6. package/dist/cjs/common/enum.cjs +233 -240
  7. package/dist/cjs/common/enum.cjs.map +1 -1
  8. package/dist/cjs/common/index.cjs +2 -0
  9. package/dist/cjs/events.cjs +121 -169
  10. package/dist/cjs/events.cjs.map +1 -1
  11. package/dist/cjs/graphs/Graph.cjs +1389 -1807
  12. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  13. package/dist/cjs/graphs/MultiAgentGraph.cjs +713 -945
  14. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  15. package/dist/cjs/graphs/index.cjs +2 -0
  16. package/dist/cjs/hitl/askUserQuestion.cjs +60 -62
  17. package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -1
  18. package/dist/cjs/hitl/index.cjs +1 -0
  19. package/dist/cjs/hooks/HookRegistry.cjs +176 -202
  20. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  21. package/dist/cjs/hooks/createToolPolicyHook.cjs +71 -101
  22. package/dist/cjs/hooks/createToolPolicyHook.cjs.map +1 -1
  23. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +170 -273
  24. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -1
  25. package/dist/cjs/hooks/executeHooks.cjs +227 -282
  26. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  27. package/dist/cjs/hooks/index.cjs +6 -0
  28. package/dist/cjs/hooks/matchers.cjs +196 -230
  29. package/dist/cjs/hooks/matchers.cjs.map +1 -1
  30. package/dist/cjs/hooks/types.cjs +24 -24
  31. package/dist/cjs/hooks/types.cjs.map +1 -1
  32. package/dist/cjs/instrumentation.cjs +110 -137
  33. package/dist/cjs/instrumentation.cjs.map +1 -1
  34. package/dist/cjs/langchain/google-common.cjs +0 -3
  35. package/dist/cjs/langchain/index.cjs +80 -43
  36. package/dist/cjs/langchain/language_models/chat_models.cjs +0 -3
  37. package/dist/cjs/langchain/messages/tool.cjs +0 -3
  38. package/dist/cjs/langchain/messages.cjs +35 -18
  39. package/dist/cjs/langchain/openai.cjs +0 -3
  40. package/dist/cjs/langchain/prompts.cjs +5 -8
  41. package/dist/cjs/langchain/runnables.cjs +11 -10
  42. package/dist/cjs/langchain/tools.cjs +14 -11
  43. package/dist/cjs/langchain/utils/env.cjs +5 -8
  44. package/dist/cjs/langfuse.cjs +60 -79
  45. package/dist/cjs/langfuse.cjs.map +1 -1
  46. package/dist/cjs/langfuseToolOutputTracing.cjs +267 -399
  47. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  48. package/dist/cjs/llm/anthropic/index.cjs +432 -562
  49. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  50. package/dist/cjs/llm/anthropic/types.cjs +23 -47
  51. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  52. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +441 -731
  53. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  54. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +171 -256
  55. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  56. package/dist/cjs/llm/anthropic/utils/output_parsers.cjs +2 -0
  57. package/dist/cjs/llm/anthropic/utils/tools.cjs +12 -26
  58. package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -1
  59. package/dist/cjs/llm/bedrock/index.cjs +195 -240
  60. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  61. package/dist/cjs/llm/bedrock/toolCache.cjs +84 -106
  62. package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
  63. package/dist/cjs/llm/bedrock/utils/index.cjs +2 -0
  64. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +357 -620
  65. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  66. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +105 -149
  67. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  68. package/dist/cjs/llm/fake.cjs +86 -96
  69. package/dist/cjs/llm/fake.cjs.map +1 -1
  70. package/dist/cjs/llm/google/index.cjs +183 -237
  71. package/dist/cjs/llm/google/index.cjs.map +1 -1
  72. package/dist/cjs/llm/google/utils/common.cjs +398 -674
  73. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  74. package/dist/cjs/llm/google/utils/zod_to_genai_parameters.cjs +2 -0
  75. package/dist/cjs/llm/init.cjs +44 -53
  76. package/dist/cjs/llm/init.cjs.map +1 -1
  77. package/dist/cjs/llm/invoke.cjs +142 -182
  78. package/dist/cjs/llm/invoke.cjs.map +1 -1
  79. package/dist/cjs/llm/openai/index.cjs +991 -1276
  80. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  81. package/dist/cjs/llm/openai/utils/index.cjs +189 -316
  82. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  83. package/dist/cjs/llm/openrouter/index.cjs +102 -153
  84. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  85. package/dist/cjs/llm/openrouter/toolCache.cjs +35 -44
  86. package/dist/cjs/llm/openrouter/toolCache.cjs.map +1 -1
  87. package/dist/cjs/llm/providers.cjs +29 -37
  88. package/dist/cjs/llm/providers.cjs.map +1 -1
  89. package/dist/cjs/llm/request.cjs +20 -33
  90. package/dist/cjs/llm/request.cjs.map +1 -1
  91. package/dist/cjs/llm/vertexai/index.cjs +427 -453
  92. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  93. package/dist/cjs/main.cjs +547 -528
  94. package/dist/cjs/messages/anthropicToolCache.cjs +68 -119
  95. package/dist/cjs/messages/anthropicToolCache.cjs.map +1 -1
  96. package/dist/cjs/messages/cache.cjs +305 -418
  97. package/dist/cjs/messages/cache.cjs.map +1 -1
  98. package/dist/cjs/messages/content.cjs +36 -49
  99. package/dist/cjs/messages/content.cjs.map +1 -1
  100. package/dist/cjs/messages/contextPruning.cjs +112 -145
  101. package/dist/cjs/messages/contextPruning.cjs.map +1 -1
  102. package/dist/cjs/messages/contextPruningSettings.cjs +36 -46
  103. package/dist/cjs/messages/contextPruningSettings.cjs.map +1 -1
  104. package/dist/cjs/messages/core.cjs +256 -397
  105. package/dist/cjs/messages/core.cjs.map +1 -1
  106. package/dist/cjs/messages/format.cjs +904 -1387
  107. package/dist/cjs/messages/format.cjs.map +1 -1
  108. package/dist/cjs/messages/ids.cjs +16 -20
  109. package/dist/cjs/messages/ids.cjs.map +1 -1
  110. package/dist/cjs/messages/index.cjs +12 -0
  111. package/dist/cjs/messages/langchain.cjs +18 -18
  112. package/dist/cjs/messages/langchain.cjs.map +1 -1
  113. package/dist/cjs/messages/prune.cjs +1054 -1517
  114. package/dist/cjs/messages/prune.cjs.map +1 -1
  115. package/dist/cjs/messages/recency.cjs +77 -95
  116. package/dist/cjs/messages/recency.cjs.map +1 -1
  117. package/dist/cjs/messages/reducer.cjs +63 -78
  118. package/dist/cjs/messages/reducer.cjs.map +1 -1
  119. package/dist/cjs/messages/tools.cjs +51 -79
  120. package/dist/cjs/messages/tools.cjs.map +1 -1
  121. package/dist/cjs/openai/index.cjs +171 -217
  122. package/dist/cjs/openai/index.cjs.map +1 -1
  123. package/dist/cjs/responses/index.cjs +302 -391
  124. package/dist/cjs/responses/index.cjs.map +1 -1
  125. package/dist/cjs/run.cjs +903 -1113
  126. package/dist/cjs/run.cjs.map +1 -1
  127. package/dist/cjs/session/AgentSession.cjs +805 -986
  128. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  129. package/dist/cjs/session/JsonlSessionStore.cjs +327 -410
  130. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  131. package/dist/cjs/session/handlers.cjs +192 -208
  132. package/dist/cjs/session/handlers.cjs.map +1 -1
  133. package/dist/cjs/session/ids.cjs +9 -10
  134. package/dist/cjs/session/ids.cjs.map +1 -1
  135. package/dist/cjs/session/index.cjs +4 -0
  136. package/dist/cjs/session/messageSerialization.cjs +94 -156
  137. package/dist/cjs/session/messageSerialization.cjs.map +1 -1
  138. package/dist/cjs/splitStream.cjs +147 -206
  139. package/dist/cjs/splitStream.cjs.map +1 -1
  140. package/dist/cjs/stream.cjs +856 -1344
  141. package/dist/cjs/stream.cjs.map +1 -1
  142. package/dist/cjs/summarization/index.cjs +57 -101
  143. package/dist/cjs/summarization/index.cjs.map +1 -1
  144. package/dist/cjs/summarization/node.cjs +643 -796
  145. package/dist/cjs/summarization/node.cjs.map +1 -1
  146. package/dist/cjs/tools/BashExecutor.cjs +110 -136
  147. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  148. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +165 -245
  149. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  150. package/dist/cjs/tools/Calculator.cjs +36 -57
  151. package/dist/cjs/tools/Calculator.cjs.map +1 -1
  152. package/dist/cjs/tools/CodeExecutor.cjs +126 -168
  153. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  154. package/dist/cjs/tools/CodeSessionFileSummary.cjs +36 -46
  155. package/dist/cjs/tools/CodeSessionFileSummary.cjs.map +1 -1
  156. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +459 -649
  157. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  158. package/dist/cjs/tools/ReadFile.cjs +17 -20
  159. package/dist/cjs/tools/ReadFile.cjs.map +1 -1
  160. package/dist/cjs/tools/SkillTool.cjs +26 -27
  161. package/dist/cjs/tools/SkillTool.cjs.map +1 -1
  162. package/dist/cjs/tools/SubagentTool.cjs +59 -61
  163. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  164. package/dist/cjs/tools/ToolNode.cjs +2109 -2686
  165. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  166. package/dist/cjs/tools/ToolSearch.cjs +663 -825
  167. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  168. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs +248 -340
  169. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs.map +1 -1
  170. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +170 -197
  171. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -1
  172. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +425 -520
  173. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
  174. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +91 -124
  175. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -1
  176. package/dist/cjs/tools/cloudflare/index.cjs +4 -0
  177. package/dist/cjs/tools/eagerEventExecution.cjs +75 -99
  178. package/dist/cjs/tools/eagerEventExecution.cjs.map +1 -1
  179. package/dist/cjs/tools/handlers.cjs +200 -262
  180. package/dist/cjs/tools/handlers.cjs.map +1 -1
  181. package/dist/cjs/tools/local/CompileCheckTool.cjs +150 -212
  182. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
  183. package/dist/cjs/tools/local/FileCheckpointer.cjs +77 -85
  184. package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -1
  185. package/dist/cjs/tools/local/LocalCodingTools.cjs +763 -1022
  186. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
  187. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +666 -941
  188. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
  189. package/dist/cjs/tools/local/LocalExecutionTools.cjs +49 -92
  190. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
  191. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +286 -354
  192. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  193. package/dist/cjs/tools/local/attachments.cjs +108 -165
  194. package/dist/cjs/tools/local/attachments.cjs.map +1 -1
  195. package/dist/cjs/tools/local/bashAst.cjs +99 -113
  196. package/dist/cjs/tools/local/bashAst.cjs.map +1 -1
  197. package/dist/cjs/tools/local/editStrategies.cjs +126 -169
  198. package/dist/cjs/tools/local/editStrategies.cjs.map +1 -1
  199. package/dist/cjs/tools/local/index.cjs +12 -0
  200. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +136 -218
  201. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
  202. package/dist/cjs/tools/local/syntaxCheck.cjs +142 -161
  203. package/dist/cjs/tools/local/syntaxCheck.cjs.map +1 -1
  204. package/dist/cjs/tools/local/textEncoding.cjs +25 -23
  205. package/dist/cjs/tools/local/textEncoding.cjs.map +1 -1
  206. package/dist/cjs/tools/local/workspaceFS.cjs +38 -46
  207. package/dist/cjs/tools/local/workspaceFS.cjs.map +1 -1
  208. package/dist/cjs/tools/ptcTimeout.cjs +27 -47
  209. package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
  210. package/dist/cjs/tools/schema.cjs +24 -23
  211. package/dist/cjs/tools/schema.cjs.map +1 -1
  212. package/dist/cjs/tools/search/anthropic.cjs +24 -33
  213. package/dist/cjs/tools/search/anthropic.cjs.map +1 -1
  214. package/dist/cjs/tools/search/content.cjs +95 -137
  215. package/dist/cjs/tools/search/content.cjs.map +1 -1
  216. package/dist/cjs/tools/search/firecrawl.cjs +141 -172
  217. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  218. package/dist/cjs/tools/search/format.cjs +128 -196
  219. package/dist/cjs/tools/search/format.cjs.map +1 -1
  220. package/dist/cjs/tools/search/highlights.cjs +165 -232
  221. package/dist/cjs/tools/search/highlights.cjs.map +1 -1
  222. package/dist/cjs/tools/search/index.cjs +2 -0
  223. package/dist/cjs/tools/search/rerankers.cjs +151 -174
  224. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  225. package/dist/cjs/tools/search/schema.cjs +40 -39
  226. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  227. package/dist/cjs/tools/search/search.cjs +428 -530
  228. package/dist/cjs/tools/search/search.cjs.map +1 -1
  229. package/dist/cjs/tools/search/serper-scraper.cjs +106 -127
  230. package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
  231. package/dist/cjs/tools/search/tavily-scraper.cjs +129 -181
  232. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -1
  233. package/dist/cjs/tools/search/tavily-search.cjs +295 -359
  234. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
  235. package/dist/cjs/tools/search/tool.cjs +260 -299
  236. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  237. package/dist/cjs/tools/search/utils.cjs +74 -117
  238. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  239. package/dist/cjs/tools/skillCatalog.cjs +54 -72
  240. package/dist/cjs/tools/skillCatalog.cjs.map +1 -1
  241. package/dist/cjs/tools/streamedToolCallSeals.cjs +19 -36
  242. package/dist/cjs/tools/streamedToolCallSeals.cjs.map +1 -1
  243. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +612 -771
  244. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  245. package/dist/cjs/tools/subagent/index.cjs +1 -0
  246. package/dist/cjs/tools/toolOutputReferences.cjs +523 -630
  247. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  248. package/dist/cjs/utils/callbacks.cjs +11 -21
  249. package/dist/cjs/utils/callbacks.cjs.map +1 -1
  250. package/dist/cjs/utils/errors.cjs +70 -95
  251. package/dist/cjs/utils/errors.cjs.map +1 -1
  252. package/dist/cjs/utils/events.cjs +32 -42
  253. package/dist/cjs/utils/events.cjs.map +1 -1
  254. package/dist/cjs/utils/graph.cjs +8 -12
  255. package/dist/cjs/utils/graph.cjs.map +1 -1
  256. package/dist/cjs/utils/handlers.cjs +60 -82
  257. package/dist/cjs/utils/handlers.cjs.map +1 -1
  258. package/dist/cjs/utils/index.cjs +9 -0
  259. package/dist/cjs/utils/llm.cjs +19 -27
  260. package/dist/cjs/utils/llm.cjs.map +1 -1
  261. package/dist/cjs/utils/misc.cjs +30 -46
  262. package/dist/cjs/utils/misc.cjs.map +1 -1
  263. package/dist/cjs/utils/run.cjs +50 -66
  264. package/dist/cjs/utils/run.cjs.map +1 -1
  265. package/dist/cjs/utils/schema.cjs +11 -19
  266. package/dist/cjs/utils/schema.cjs.map +1 -1
  267. package/dist/cjs/utils/title.cjs +71 -106
  268. package/dist/cjs/utils/title.cjs.map +1 -1
  269. package/dist/cjs/utils/tokens.cjs +186 -283
  270. package/dist/cjs/utils/tokens.cjs.map +1 -1
  271. package/dist/cjs/utils/truncation.cjs +95 -114
  272. package/dist/cjs/utils/truncation.cjs.map +1 -1
  273. package/dist/esm/agents/AgentContext.mjs +844 -1044
  274. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  275. package/dist/esm/common/constants.mjs +13 -11
  276. package/dist/esm/common/constants.mjs.map +1 -1
  277. package/dist/esm/common/enum.mjs +221 -238
  278. package/dist/esm/common/enum.mjs.map +1 -1
  279. package/dist/esm/common/index.mjs +3 -0
  280. package/dist/esm/events.mjs +121 -167
  281. package/dist/esm/events.mjs.map +1 -1
  282. package/dist/esm/graphs/Graph.mjs +1388 -1804
  283. package/dist/esm/graphs/Graph.mjs.map +1 -1
  284. package/dist/esm/graphs/MultiAgentGraph.mjs +713 -943
  285. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  286. package/dist/esm/graphs/index.mjs +3 -0
  287. package/dist/esm/hitl/askUserQuestion.mjs +60 -60
  288. package/dist/esm/hitl/askUserQuestion.mjs.map +1 -1
  289. package/dist/esm/hitl/index.mjs +2 -0
  290. package/dist/esm/hooks/HookRegistry.mjs +176 -200
  291. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  292. package/dist/esm/hooks/createToolPolicyHook.mjs +71 -99
  293. package/dist/esm/hooks/createToolPolicyHook.mjs.map +1 -1
  294. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +170 -271
  295. package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -1
  296. package/dist/esm/hooks/executeHooks.mjs +227 -280
  297. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  298. package/dist/esm/hooks/index.mjs +7 -0
  299. package/dist/esm/hooks/matchers.mjs +196 -228
  300. package/dist/esm/hooks/matchers.mjs.map +1 -1
  301. package/dist/esm/hooks/types.mjs +24 -22
  302. package/dist/esm/hooks/types.mjs.map +1 -1
  303. package/dist/esm/instrumentation.mjs +109 -132
  304. package/dist/esm/instrumentation.mjs.map +1 -1
  305. package/dist/esm/langchain/google-common.mjs +1 -2
  306. package/dist/esm/langchain/index.mjs +5 -5
  307. package/dist/esm/langchain/language_models/chat_models.mjs +1 -2
  308. package/dist/esm/langchain/messages/tool.mjs +1 -2
  309. package/dist/esm/langchain/messages.mjs +2 -2
  310. package/dist/esm/langchain/openai.mjs +1 -2
  311. package/dist/esm/langchain/prompts.mjs +2 -2
  312. package/dist/esm/langchain/runnables.mjs +2 -2
  313. package/dist/esm/langchain/tools.mjs +2 -2
  314. package/dist/esm/langchain/utils/env.mjs +2 -2
  315. package/dist/esm/langfuse.mjs +60 -76
  316. package/dist/esm/langfuse.mjs.map +1 -1
  317. package/dist/esm/langfuseToolOutputTracing.mjs +267 -395
  318. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  319. package/dist/esm/llm/anthropic/index.mjs +432 -559
  320. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  321. package/dist/esm/llm/anthropic/types.mjs +23 -45
  322. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  323. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +439 -725
  324. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  325. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +171 -253
  326. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  327. package/dist/esm/llm/anthropic/utils/output_parsers.mjs +3 -0
  328. package/dist/esm/llm/anthropic/utils/tools.mjs +12 -24
  329. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -1
  330. package/dist/esm/llm/bedrock/index.mjs +195 -238
  331. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  332. package/dist/esm/llm/bedrock/toolCache.mjs +84 -104
  333. package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
  334. package/dist/esm/llm/bedrock/utils/index.mjs +3 -0
  335. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +357 -618
  336. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  337. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +105 -147
  338. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  339. package/dist/esm/llm/fake.mjs +86 -94
  340. package/dist/esm/llm/fake.mjs.map +1 -1
  341. package/dist/esm/llm/google/index.mjs +183 -235
  342. package/dist/esm/llm/google/index.mjs.map +1 -1
  343. package/dist/esm/llm/google/utils/common.mjs +397 -666
  344. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  345. package/dist/esm/llm/google/utils/zod_to_genai_parameters.mjs +3 -0
  346. package/dist/esm/llm/init.mjs +44 -51
  347. package/dist/esm/llm/init.mjs.map +1 -1
  348. package/dist/esm/llm/invoke.mjs +142 -180
  349. package/dist/esm/llm/invoke.mjs.map +1 -1
  350. package/dist/esm/llm/openai/index.mjs +991 -1271
  351. package/dist/esm/llm/openai/index.mjs.map +1 -1
  352. package/dist/esm/llm/openai/utils/index.mjs +188 -312
  353. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  354. package/dist/esm/llm/openrouter/index.mjs +102 -151
  355. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  356. package/dist/esm/llm/openrouter/toolCache.mjs +35 -42
  357. package/dist/esm/llm/openrouter/toolCache.mjs.map +1 -1
  358. package/dist/esm/llm/providers.mjs +29 -34
  359. package/dist/esm/llm/providers.mjs.map +1 -1
  360. package/dist/esm/llm/request.mjs +20 -31
  361. package/dist/esm/llm/request.mjs.map +1 -1
  362. package/dist/esm/llm/vertexai/index.mjs +427 -449
  363. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  364. package/dist/esm/main.mjs +99 -87
  365. package/dist/esm/messages/anthropicToolCache.mjs +68 -117
  366. package/dist/esm/messages/anthropicToolCache.mjs.map +1 -1
  367. package/dist/esm/messages/cache.mjs +305 -416
  368. package/dist/esm/messages/cache.mjs.map +1 -1
  369. package/dist/esm/messages/content.mjs +36 -47
  370. package/dist/esm/messages/content.mjs.map +1 -1
  371. package/dist/esm/messages/contextPruning.mjs +112 -143
  372. package/dist/esm/messages/contextPruning.mjs.map +1 -1
  373. package/dist/esm/messages/contextPruningSettings.mjs +36 -44
  374. package/dist/esm/messages/contextPruningSettings.mjs.map +1 -1
  375. package/dist/esm/messages/core.mjs +254 -393
  376. package/dist/esm/messages/core.mjs.map +1 -1
  377. package/dist/esm/messages/format.mjs +902 -1383
  378. package/dist/esm/messages/format.mjs.map +1 -1
  379. package/dist/esm/messages/ids.mjs +16 -18
  380. package/dist/esm/messages/ids.mjs.map +1 -1
  381. package/dist/esm/messages/index.mjs +13 -0
  382. package/dist/esm/messages/langchain.mjs +18 -16
  383. package/dist/esm/messages/langchain.mjs.map +1 -1
  384. package/dist/esm/messages/prune.mjs +1053 -1514
  385. package/dist/esm/messages/prune.mjs.map +1 -1
  386. package/dist/esm/messages/recency.mjs +77 -93
  387. package/dist/esm/messages/recency.mjs.map +1 -1
  388. package/dist/esm/messages/reducer.mjs +63 -76
  389. package/dist/esm/messages/reducer.mjs.map +1 -1
  390. package/dist/esm/messages/tools.mjs +49 -75
  391. package/dist/esm/messages/tools.mjs.map +1 -1
  392. package/dist/esm/openai/index.mjs +170 -215
  393. package/dist/esm/openai/index.mjs.map +1 -1
  394. package/dist/esm/responses/index.mjs +301 -389
  395. package/dist/esm/responses/index.mjs.map +1 -1
  396. package/dist/esm/run.mjs +903 -1111
  397. package/dist/esm/run.mjs.map +1 -1
  398. package/dist/esm/session/AgentSession.mjs +806 -985
  399. package/dist/esm/session/AgentSession.mjs.map +1 -1
  400. package/dist/esm/session/JsonlSessionStore.mjs +326 -407
  401. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  402. package/dist/esm/session/handlers.mjs +192 -206
  403. package/dist/esm/session/handlers.mjs.map +1 -1
  404. package/dist/esm/session/ids.mjs +9 -8
  405. package/dist/esm/session/ids.mjs.map +1 -1
  406. package/dist/esm/session/index.mjs +5 -0
  407. package/dist/esm/session/messageSerialization.mjs +94 -154
  408. package/dist/esm/session/messageSerialization.mjs.map +1 -1
  409. package/dist/esm/splitStream.mjs +147 -204
  410. package/dist/esm/splitStream.mjs.map +1 -1
  411. package/dist/esm/stream.mjs +854 -1341
  412. package/dist/esm/stream.mjs.map +1 -1
  413. package/dist/esm/summarization/index.mjs +57 -99
  414. package/dist/esm/summarization/index.mjs.map +1 -1
  415. package/dist/esm/summarization/node.mjs +640 -790
  416. package/dist/esm/summarization/node.mjs.map +1 -1
  417. package/dist/esm/tools/BashExecutor.mjs +103 -129
  418. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  419. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +162 -239
  420. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  421. package/dist/esm/tools/Calculator.mjs +34 -36
  422. package/dist/esm/tools/Calculator.mjs.map +1 -1
  423. package/dist/esm/tools/CodeExecutor.mjs +123 -164
  424. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  425. package/dist/esm/tools/CodeSessionFileSummary.mjs +36 -44
  426. package/dist/esm/tools/CodeSessionFileSummary.mjs.map +1 -1
  427. package/dist/esm/tools/ProgrammaticToolCalling.mjs +454 -644
  428. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  429. package/dist/esm/tools/ReadFile.mjs +17 -18
  430. package/dist/esm/tools/ReadFile.mjs.map +1 -1
  431. package/dist/esm/tools/SkillTool.mjs +26 -25
  432. package/dist/esm/tools/SkillTool.mjs.map +1 -1
  433. package/dist/esm/tools/SubagentTool.mjs +59 -59
  434. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  435. package/dist/esm/tools/ToolNode.mjs +2107 -2684
  436. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  437. package/dist/esm/tools/ToolSearch.mjs +659 -804
  438. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  439. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs +248 -338
  440. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs.map +1 -1
  441. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +170 -195
  442. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -1
  443. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +424 -517
  444. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
  445. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +91 -122
  446. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -1
  447. package/dist/esm/tools/cloudflare/index.mjs +5 -0
  448. package/dist/esm/tools/eagerEventExecution.mjs +75 -96
  449. package/dist/esm/tools/eagerEventExecution.mjs.map +1 -1
  450. package/dist/esm/tools/handlers.mjs +200 -260
  451. package/dist/esm/tools/handlers.mjs.map +1 -1
  452. package/dist/esm/tools/local/CompileCheckTool.mjs +150 -210
  453. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
  454. package/dist/esm/tools/local/FileCheckpointer.mjs +77 -83
  455. package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -1
  456. package/dist/esm/tools/local/LocalCodingTools.mjs +760 -1017
  457. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
  458. package/dist/esm/tools/local/LocalExecutionEngine.mjs +663 -936
  459. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
  460. package/dist/esm/tools/local/LocalExecutionTools.mjs +49 -90
  461. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
  462. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +283 -349
  463. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  464. package/dist/esm/tools/local/attachments.mjs +108 -163
  465. package/dist/esm/tools/local/attachments.mjs.map +1 -1
  466. package/dist/esm/tools/local/bashAst.mjs +99 -111
  467. package/dist/esm/tools/local/bashAst.mjs.map +1 -1
  468. package/dist/esm/tools/local/editStrategies.mjs +126 -167
  469. package/dist/esm/tools/local/editStrategies.mjs.map +1 -1
  470. package/dist/esm/tools/local/index.mjs +13 -0
  471. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +136 -216
  472. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
  473. package/dist/esm/tools/local/syntaxCheck.mjs +138 -155
  474. package/dist/esm/tools/local/syntaxCheck.mjs.map +1 -1
  475. package/dist/esm/tools/local/textEncoding.mjs +25 -21
  476. package/dist/esm/tools/local/textEncoding.mjs.map +1 -1
  477. package/dist/esm/tools/local/workspaceFS.mjs +38 -44
  478. package/dist/esm/tools/local/workspaceFS.mjs.map +1 -1
  479. package/dist/esm/tools/ptcTimeout.mjs +27 -42
  480. package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
  481. package/dist/esm/tools/schema.mjs +24 -21
  482. package/dist/esm/tools/schema.mjs.map +1 -1
  483. package/dist/esm/tools/search/anthropic.mjs +24 -31
  484. package/dist/esm/tools/search/anthropic.mjs.map +1 -1
  485. package/dist/esm/tools/search/content.mjs +93 -116
  486. package/dist/esm/tools/search/content.mjs.map +1 -1
  487. package/dist/esm/tools/search/firecrawl.mjs +139 -169
  488. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  489. package/dist/esm/tools/search/format.mjs +128 -194
  490. package/dist/esm/tools/search/format.mjs.map +1 -1
  491. package/dist/esm/tools/search/highlights.mjs +165 -230
  492. package/dist/esm/tools/search/highlights.mjs.map +1 -1
  493. package/dist/esm/tools/search/index.mjs +3 -0
  494. package/dist/esm/tools/search/rerankers.mjs +149 -168
  495. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  496. package/dist/esm/tools/search/schema.mjs +39 -37
  497. package/dist/esm/tools/search/schema.mjs.map +1 -1
  498. package/dist/esm/tools/search/search.mjs +426 -528
  499. package/dist/esm/tools/search/search.mjs.map +1 -1
  500. package/dist/esm/tools/search/serper-scraper.mjs +104 -124
  501. package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
  502. package/dist/esm/tools/search/tavily-scraper.mjs +127 -178
  503. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -1
  504. package/dist/esm/tools/search/tavily-search.mjs +293 -357
  505. package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
  506. package/dist/esm/tools/search/tool.mjs +259 -297
  507. package/dist/esm/tools/search/tool.mjs.map +1 -1
  508. package/dist/esm/tools/search/utils.mjs +74 -115
  509. package/dist/esm/tools/search/utils.mjs.map +1 -1
  510. package/dist/esm/tools/skillCatalog.mjs +54 -70
  511. package/dist/esm/tools/skillCatalog.mjs.map +1 -1
  512. package/dist/esm/tools/streamedToolCallSeals.mjs +19 -31
  513. package/dist/esm/tools/streamedToolCallSeals.mjs.map +1 -1
  514. package/dist/esm/tools/subagent/SubagentExecutor.mjs +612 -768
  515. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  516. package/dist/esm/tools/subagent/index.mjs +2 -0
  517. package/dist/esm/tools/toolOutputReferences.mjs +523 -624
  518. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  519. package/dist/esm/utils/callbacks.mjs +11 -19
  520. package/dist/esm/utils/callbacks.mjs.map +1 -1
  521. package/dist/esm/utils/errors.mjs +70 -93
  522. package/dist/esm/utils/errors.mjs.map +1 -1
  523. package/dist/esm/utils/events.mjs +32 -40
  524. package/dist/esm/utils/events.mjs.map +1 -1
  525. package/dist/esm/utils/graph.mjs +8 -10
  526. package/dist/esm/utils/graph.mjs.map +1 -1
  527. package/dist/esm/utils/handlers.mjs +60 -80
  528. package/dist/esm/utils/handlers.mjs.map +1 -1
  529. package/dist/esm/utils/index.mjs +10 -0
  530. package/dist/esm/utils/llm.mjs +19 -25
  531. package/dist/esm/utils/llm.mjs.map +1 -1
  532. package/dist/esm/utils/misc.mjs +30 -44
  533. package/dist/esm/utils/misc.mjs.map +1 -1
  534. package/dist/esm/utils/run.mjs +50 -64
  535. package/dist/esm/utils/run.mjs.map +1 -1
  536. package/dist/esm/utils/schema.mjs +11 -17
  537. package/dist/esm/utils/schema.mjs.map +1 -1
  538. package/dist/esm/utils/title.mjs +71 -104
  539. package/dist/esm/utils/title.mjs.map +1 -1
  540. package/dist/esm/utils/tokens.mjs +186 -281
  541. package/dist/esm/utils/tokens.mjs.map +1 -1
  542. package/dist/esm/utils/truncation.mjs +95 -112
  543. package/dist/esm/utils/truncation.mjs.map +1 -1
  544. package/dist/types/tools/search/tool.d.ts +17 -0
  545. package/dist/types/tools/search/types.d.ts +4 -0
  546. package/package.json +4 -10
  547. package/src/tools/search/highlights.ts +9 -1
  548. package/src/tools/search/search.ts +41 -3
  549. package/src/tools/search/source-processing.test.ts +373 -0
  550. package/src/tools/search/tool.ts +22 -2
  551. package/src/tools/search/types.ts +4 -0
  552. package/dist/cjs/langchain/google-common.cjs.map +0 -1
  553. package/dist/cjs/langchain/index.cjs.map +0 -1
  554. package/dist/cjs/langchain/language_models/chat_models.cjs.map +0 -1
  555. package/dist/cjs/langchain/messages/tool.cjs.map +0 -1
  556. package/dist/cjs/langchain/messages.cjs.map +0 -1
  557. package/dist/cjs/langchain/openai.cjs.map +0 -1
  558. package/dist/cjs/langchain/prompts.cjs.map +0 -1
  559. package/dist/cjs/langchain/runnables.cjs.map +0 -1
  560. package/dist/cjs/langchain/tools.cjs.map +0 -1
  561. package/dist/cjs/langchain/utils/env.cjs.map +0 -1
  562. package/dist/cjs/main.cjs.map +0 -1
  563. package/dist/esm/langchain/google-common.mjs.map +0 -1
  564. package/dist/esm/langchain/index.mjs.map +0 -1
  565. package/dist/esm/langchain/language_models/chat_models.mjs.map +0 -1
  566. package/dist/esm/langchain/messages/tool.mjs.map +0 -1
  567. package/dist/esm/langchain/messages.mjs.map +0 -1
  568. package/dist/esm/langchain/openai.mjs.map +0 -1
  569. package/dist/esm/langchain/prompts.mjs.map +0 -1
  570. package/dist/esm/langchain/runnables.mjs.map +0 -1
  571. package/dist/esm/langchain/tools.mjs.map +0 -1
  572. package/dist/esm/langchain/utils/env.mjs.map +0 -1
  573. package/dist/esm/main.mjs.map +0 -1
@@ -1,1456 +1,975 @@
1
- import { HumanMessage, AIMessage, AIMessageChunk, SystemMessage, ToolMessage } from '@langchain/core/messages';
2
- import { normalizeAnthropicToolCallId } from '../llm/anthropic/utils/message_inputs.mjs';
3
- import { toLangChainContent, toLangChainMessageFields } from './langchain.mjs';
4
- import { ContentTypes, Constants, Providers } from '../common/enum.mjs';
5
- import { emitAgentLog } from '../utils/events.mjs';
6
-
7
- /* eslint-disable @typescript-eslint/no-explicit-any */
1
+ import "../common/enum.mjs";
2
+ import "../common/index.mjs";
3
+ import { toLangChainContent, toLangChainMessageFields } from "./langchain.mjs";
4
+ import { normalizeAnthropicToolCallId } from "../llm/anthropic/utils/message_inputs.mjs";
5
+ import { emitAgentLog } from "../utils/events.mjs";
6
+ import { AIMessage, AIMessageChunk, HumanMessage, SystemMessage, ToolMessage } from "@langchain/core/messages";
7
+ //#region src/messages/format.ts
8
8
  /**
9
- * Formats a message with media content (images, documents, videos, audios) to API payload format.
10
- *
11
- * @param params - The parameters for formatting.
12
- * @returns - The formatted message.
13
- */
14
- const formatMediaMessage = ({ message, endpoint, mediaParts, }) => {
15
- // Create a new object to avoid mutating the input
16
- const result = {
17
- ...message,
18
- content: [],
19
- };
20
- if (endpoint === Providers.ANTHROPIC) {
21
- result.content = [
22
- ...mediaParts,
23
- { type: ContentTypes.TEXT, text: message.content },
24
- ];
25
- return result;
26
- }
27
- result.content = [
28
- { type: ContentTypes.TEXT, text: message.content },
29
- ...mediaParts,
30
- ];
31
- return result;
9
+ * Formats a message with media content (images, documents, videos, audios) to API payload format.
10
+ *
11
+ * @param params - The parameters for formatting.
12
+ * @returns - The formatted message.
13
+ */
14
+ const formatMediaMessage = ({ message, endpoint, mediaParts }) => {
15
+ const result = {
16
+ ...message,
17
+ content: []
18
+ };
19
+ if (endpoint === "anthropic") {
20
+ result.content = [...mediaParts, {
21
+ type: "text",
22
+ text: message.content
23
+ }];
24
+ return result;
25
+ }
26
+ result.content = [{
27
+ type: "text",
28
+ text: message.content
29
+ }, ...mediaParts];
30
+ return result;
32
31
  };
33
32
  function withMessageRole(message, role) {
34
- const roleMessage = message;
35
- if (roleMessage.role === role) {
36
- return roleMessage;
37
- }
38
- Object.defineProperty(roleMessage, 'role', {
39
- value: role,
40
- writable: true,
41
- enumerable: false,
42
- configurable: true,
43
- });
44
- return roleMessage;
33
+ const roleMessage = message;
34
+ if (roleMessage.role === role) return roleMessage;
35
+ Object.defineProperty(roleMessage, "role", {
36
+ value: role,
37
+ writable: true,
38
+ enumerable: false,
39
+ configurable: true
40
+ });
41
+ return roleMessage;
45
42
  }
46
43
  /**
47
- * Formats a message to OpenAI payload format based on the provided options.
48
- *
49
- * @param params - The parameters for formatting.
50
- * @returns - The formatted message.
51
- */
52
- const formatMessage = ({ message, userName, endpoint, assistantName, langChain = false, }) => {
53
- // eslint-disable-next-line prefer-const
54
- let { role: _role, _name, sender, text, content: _content, lc_id } = message;
55
- if (lc_id && lc_id[2] && !langChain) {
56
- const roleMapping = {
57
- SystemMessage: 'system',
58
- HumanMessage: 'user',
59
- AIMessage: 'assistant',
60
- };
61
- _role = roleMapping[lc_id[2]] || _role;
62
- }
63
- const role = _role ??
64
- (sender != null && sender && sender.toLowerCase() === 'user'
65
- ? 'user'
66
- : 'assistant');
67
- const content = _content ?? text ?? '';
68
- const formattedMessage = {
69
- role,
70
- content,
71
- };
72
- // Set name fields first
73
- if (_name != null && _name) {
74
- formattedMessage.name = _name;
75
- }
76
- if (userName != null && userName && formattedMessage.role === 'user') {
77
- formattedMessage.name = userName;
78
- }
79
- if (assistantName != null &&
80
- assistantName &&
81
- formattedMessage.role === 'assistant') {
82
- formattedMessage.name = assistantName;
83
- }
84
- if (formattedMessage.name != null && formattedMessage.name) {
85
- // Conform to API regex: ^[a-zA-Z0-9_-]{1,64}$
86
- // https://community.openai.com/t/the-format-of-the-name-field-in-the-documentation-is-incorrect/175684/2
87
- formattedMessage.name = formattedMessage.name.replace(/[^a-zA-Z0-9_-]/g, '_');
88
- if (formattedMessage.name.length > 64) {
89
- formattedMessage.name = formattedMessage.name.substring(0, 64);
90
- }
91
- }
92
- const { image_urls, documents, videos, audios } = message;
93
- const mediaParts = [];
94
- if (Array.isArray(documents) && documents.length > 0) {
95
- mediaParts.push(...documents);
96
- }
97
- if (Array.isArray(videos) && videos.length > 0) {
98
- mediaParts.push(...videos);
99
- }
100
- if (Array.isArray(audios) && audios.length > 0) {
101
- mediaParts.push(...audios);
102
- }
103
- if (Array.isArray(image_urls) && image_urls.length > 0) {
104
- mediaParts.push(...image_urls);
105
- }
106
- if (mediaParts.length > 0 && role === 'user') {
107
- const mediaMessage = formatMediaMessage({
108
- message: {
109
- ...formattedMessage,
110
- content: typeof formattedMessage.content === 'string'
111
- ? formattedMessage.content
112
- : '',
113
- },
114
- mediaParts,
115
- endpoint,
116
- });
117
- if (!langChain) {
118
- return mediaMessage;
119
- }
120
- return withMessageRole(new HumanMessage(toLangChainMessageFields(mediaMessage)), 'user');
121
- }
122
- if (!langChain) {
123
- return formattedMessage;
124
- }
125
- if (role === 'user') {
126
- return withMessageRole(new HumanMessage(toLangChainMessageFields(formattedMessage)), 'user');
127
- }
128
- else if (role === 'assistant') {
129
- return withMessageRole(new AIMessage(toLangChainMessageFields(formattedMessage)), 'assistant');
130
- }
131
- else {
132
- return withMessageRole(new SystemMessage(toLangChainMessageFields(formattedMessage)), 'system');
133
- }
44
+ * Formats a message to OpenAI payload format based on the provided options.
45
+ *
46
+ * @param params - The parameters for formatting.
47
+ * @returns - The formatted message.
48
+ */
49
+ const formatMessage = ({ message, userName, endpoint, assistantName, langChain = false }) => {
50
+ let { role: _role, _name, sender, text, content: _content, lc_id } = message;
51
+ if (lc_id && lc_id[2] && !langChain) _role = {
52
+ SystemMessage: "system",
53
+ HumanMessage: "user",
54
+ AIMessage: "assistant"
55
+ }[lc_id[2]] || _role;
56
+ const role = _role ?? (sender != null && sender && sender.toLowerCase() === "user" ? "user" : "assistant");
57
+ const formattedMessage = {
58
+ role,
59
+ content: _content ?? text ?? ""
60
+ };
61
+ if (_name != null && _name) formattedMessage.name = _name;
62
+ if (userName != null && userName && formattedMessage.role === "user") formattedMessage.name = userName;
63
+ if (assistantName != null && assistantName && formattedMessage.role === "assistant") formattedMessage.name = assistantName;
64
+ if (formattedMessage.name != null && formattedMessage.name) {
65
+ formattedMessage.name = formattedMessage.name.replace(/[^a-zA-Z0-9_-]/g, "_");
66
+ if (formattedMessage.name.length > 64) formattedMessage.name = formattedMessage.name.substring(0, 64);
67
+ }
68
+ const { image_urls, documents, videos, audios } = message;
69
+ const mediaParts = [];
70
+ if (Array.isArray(documents) && documents.length > 0) mediaParts.push(...documents);
71
+ if (Array.isArray(videos) && videos.length > 0) mediaParts.push(...videos);
72
+ if (Array.isArray(audios) && audios.length > 0) mediaParts.push(...audios);
73
+ if (Array.isArray(image_urls) && image_urls.length > 0) mediaParts.push(...image_urls);
74
+ if (mediaParts.length > 0 && role === "user") {
75
+ const mediaMessage = formatMediaMessage({
76
+ message: {
77
+ ...formattedMessage,
78
+ content: typeof formattedMessage.content === "string" ? formattedMessage.content : ""
79
+ },
80
+ mediaParts,
81
+ endpoint
82
+ });
83
+ if (!langChain) return mediaMessage;
84
+ return withMessageRole(new HumanMessage(toLangChainMessageFields(mediaMessage)), "user");
85
+ }
86
+ if (!langChain) return formattedMessage;
87
+ if (role === "user") return withMessageRole(new HumanMessage(toLangChainMessageFields(formattedMessage)), "user");
88
+ else if (role === "assistant") return withMessageRole(new AIMessage(toLangChainMessageFields(formattedMessage)), "assistant");
89
+ else return withMessageRole(new SystemMessage(toLangChainMessageFields(formattedMessage)), "system");
134
90
  };
135
91
  /**
136
- * Formats an array of messages for LangChain.
137
- *
138
- * @param messages - The array of messages to format.
139
- * @param formatOptions - The options for formatting each message.
140
- * @returns - The array of formatted LangChain messages.
141
- */
92
+ * Formats an array of messages for LangChain.
93
+ *
94
+ * @param messages - The array of messages to format.
95
+ * @param formatOptions - The options for formatting each message.
96
+ * @returns - The array of formatted LangChain messages.
97
+ */
142
98
  const formatLangChainMessages = (messages, formatOptions) => {
143
- return messages.map((msg) => {
144
- const formatted = formatMessage({
145
- ...formatOptions,
146
- message: msg,
147
- langChain: true,
148
- });
149
- return formatted;
150
- });
99
+ return messages.map((msg) => {
100
+ return formatMessage({
101
+ ...formatOptions,
102
+ message: msg,
103
+ langChain: true
104
+ });
105
+ });
151
106
  };
152
107
  /**
153
- * Formats a LangChain message object by merging properties from `lc_kwargs` or `kwargs` and `additional_kwargs`.
154
- *
155
- * @param message - The message object to format.
156
- * @returns - The formatted LangChain message.
157
- */
108
+ * Formats a LangChain message object by merging properties from `lc_kwargs` or `kwargs` and `additional_kwargs`.
109
+ *
110
+ * @param message - The message object to format.
111
+ * @returns - The formatted LangChain message.
112
+ */
158
113
  const formatFromLangChain = (message) => {
159
- const kwargs = message.lc_kwargs ?? message.kwargs ?? {};
160
- const { additional_kwargs = {}, ...message_kwargs } = kwargs;
161
- return {
162
- ...message_kwargs,
163
- ...additional_kwargs,
164
- };
114
+ const { additional_kwargs = {}, ...message_kwargs } = message.lc_kwargs ?? message.kwargs ?? {};
115
+ return {
116
+ ...message_kwargs,
117
+ ...additional_kwargs
118
+ };
165
119
  };
166
120
  function extractReasoningContent(part) {
167
- if (part == null || typeof part !== 'object') {
168
- return '';
169
- }
170
- if (part.type === ContentTypes.THINK) {
171
- const think = part.think;
172
- return typeof think === 'string' ? think : '';
173
- }
174
- if (part.type === ContentTypes.THINKING) {
175
- const thinking = part.thinking;
176
- return typeof thinking === 'string' ? thinking : '';
177
- }
178
- if (part.type === ContentTypes.REASONING) {
179
- const reasoning = part.reasoning;
180
- return typeof reasoning === 'string' ? reasoning : '';
181
- }
182
- if (part.type === ContentTypes.REASONING_CONTENT) {
183
- const reasoningText = part.reasoningText;
184
- return typeof reasoningText.text === 'string' ? reasoningText.text : '';
185
- }
186
- return '';
121
+ if (part == null || typeof part !== "object") return "";
122
+ if (part.type === "think") {
123
+ const think = part.think;
124
+ return typeof think === "string" ? think : "";
125
+ }
126
+ if (part.type === "thinking") {
127
+ const thinking = part.thinking;
128
+ return typeof thinking === "string" ? thinking : "";
129
+ }
130
+ if (part.type === "reasoning") {
131
+ const reasoning = part.reasoning;
132
+ return typeof reasoning === "string" ? reasoning : "";
133
+ }
134
+ if (part.type === "reasoning_content") {
135
+ const reasoningText = part.reasoningText;
136
+ return typeof reasoningText.text === "string" ? reasoningText.text : "";
137
+ }
138
+ return "";
187
139
  }
188
140
  function parseServerToolInput(args) {
189
- if (typeof args === 'string') {
190
- try {
191
- const parsed = JSON.parse(args);
192
- return parsed != null &&
193
- typeof parsed === 'object' &&
194
- !Array.isArray(parsed)
195
- ? parsed
196
- : {};
197
- }
198
- catch {
199
- return {};
200
- }
201
- }
202
- return args != null && typeof args === 'object' ? args : {};
141
+ if (typeof args === "string") try {
142
+ const parsed = JSON.parse(args);
143
+ return parsed != null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
144
+ } catch {
145
+ return {};
146
+ }
147
+ return args != null && typeof args === "object" ? args : {};
203
148
  }
204
149
  function getTextContent(part) {
205
- const { text } = part;
206
- return typeof text === 'string' ? text : '';
150
+ const { text } = part;
151
+ return typeof text === "string" ? text : "";
207
152
  }
208
153
  function hasMeaningfulAssistantContent(part) {
209
- if (part.type === ContentTypes.TEXT) {
210
- return getTextContent(part).trim().length > 0;
211
- }
212
- if (part.type === ContentTypes.TOOL_CALL ||
213
- part.type === ContentTypes.ERROR ||
214
- part.type === ContentTypes.AGENT_UPDATE ||
215
- part.type === ContentTypes.SUMMARY) {
216
- return false;
217
- }
218
- if (part.type === ContentTypes.THINK ||
219
- part.type === ContentTypes.THINKING ||
220
- part.type === ContentTypes.REASONING ||
221
- part.type === ContentTypes.REASONING_CONTENT ||
222
- part.type === 'redacted_thinking') {
223
- return extractReasoningContent(part).trim().length > 0;
224
- }
225
- return part.type != null && part.type !== '';
154
+ if (part.type === "text") return getTextContent(part).trim().length > 0;
155
+ if (part.type === "tool_call" || part.type === "error" || part.type === "agent_update" || part.type === "summary") return false;
156
+ if (part.type === "think" || part.type === "thinking" || part.type === "reasoning" || part.type === "reasoning_content" || part.type === "redacted_thinking") return extractReasoningContent(part).trim().length > 0;
157
+ return part.type != null && part.type !== "";
226
158
  }
227
159
  function getToolUseId(part) {
228
- if (!('tool_use_id' in part) || typeof part.tool_use_id !== 'string') {
229
- return undefined;
230
- }
231
- return part.tool_use_id;
160
+ if (!("tool_use_id" in part) || typeof part.tool_use_id !== "string") return;
161
+ return part.tool_use_id;
232
162
  }
233
163
  function isValidServerToolResult(part) {
234
- const toolUseId = getToolUseId(part);
235
- if (toolUseId?.startsWith(Constants.ANTHROPIC_SERVER_TOOL_PREFIX) !== true ||
236
- !('content' in part)) {
237
- return false;
238
- }
239
- const { content } = part;
240
- return (Array.isArray(content) ||
241
- (content != null &&
242
- typeof content === 'object' &&
243
- 'type' in content &&
244
- content.type === 'web_search_tool_result_error'));
164
+ if (getToolUseId(part)?.startsWith("srvtoolu_") !== true || !("content" in part)) return false;
165
+ const { content } = part;
166
+ return Array.isArray(content) || content != null && typeof content === "object" && "type" in content && content.type === "web_search_tool_result_error";
245
167
  }
246
168
  function getToolCallId(part) {
247
- if (part.type !== ContentTypes.TOOL_CALL) {
248
- return undefined;
249
- }
250
- const id = part.tool_call?.id;
251
- return typeof id === 'string' && id !== '' ? id : undefined;
169
+ if (part.type !== "tool_call") return;
170
+ const id = part.tool_call?.id;
171
+ return typeof id === "string" && id !== "" ? id : void 0;
252
172
  }
253
173
  function hasToolCallOutput(part) {
254
- if (part.type !== ContentTypes.TOOL_CALL) {
255
- return false;
256
- }
257
- const output = part.tool_call?.output;
258
- return output != null && output !== '';
174
+ if (part.type !== "tool_call") return false;
175
+ const output = part.tool_call?.output;
176
+ return output != null && output !== "";
259
177
  }
260
178
  /**
261
- * Helper function to format an assistant message
262
- * @param message The message to format
263
- * @param options Optional formatting options
264
- * @returns Array of formatted messages
265
- */
179
+ * Helper function to format an assistant message
180
+ * @param message The message to format
181
+ * @param options Optional formatting options
182
+ * @returns Array of formatted messages
183
+ */
266
184
  function formatAssistantMessage(message, options) {
267
- const formattedMessages = [];
268
- let currentContent = [];
269
- let lastAIMessage = null;
270
- let hasReasoning = false;
271
- let pendingReasoningContent = '';
272
- const emittedServerToolUseIds = new Set();
273
- const pendingServerToolUses = new Map();
274
- const shouldPreserveReasoningContent = options?.preserveReasoningContent === true;
275
- const serverToolResultIds = new Set();
276
- const preferredToolCallParts = new Map();
277
- const takePendingReasoningContent = () => {
278
- if (!shouldPreserveReasoningContent || !pendingReasoningContent) {
279
- return undefined;
280
- }
281
- const reasoningContent = pendingReasoningContent;
282
- pendingReasoningContent = '';
283
- return reasoningContent;
284
- };
285
- const createAIMessage = (content) => {
286
- const reasoningContent = takePendingReasoningContent();
287
- return withMessageRole(new AIMessage({
288
- content,
289
- ...(reasoningContent != null && {
290
- additional_kwargs: { reasoning_content: reasoningContent },
291
- }),
292
- }), 'assistant');
293
- };
294
- const attachPendingReasoningContent = (aiMessage) => {
295
- const reasoningContent = takePendingReasoningContent();
296
- if (reasoningContent == null) {
297
- return;
298
- }
299
- aiMessage.additional_kwargs.reasoning_content =
300
- typeof aiMessage.additional_kwargs.reasoning_content === 'string'
301
- ? `${aiMessage.additional_kwargs.reasoning_content}${reasoningContent}`
302
- : reasoningContent;
303
- };
304
- const flushPendingServerToolUse = (toolUseId) => {
305
- for (const [id, content] of pendingServerToolUses) {
306
- pendingServerToolUses.delete(id);
307
- if (id === toolUseId) {
308
- currentContent.push(content);
309
- emittedServerToolUseIds.add(id);
310
- return;
311
- }
312
- }
313
- };
314
- if (Array.isArray(message.content)) {
315
- const contentParts = message.content;
316
- for (const part of contentParts) {
317
- if (part == null) {
318
- continue;
319
- }
320
- if (isValidServerToolResult(part)) {
321
- serverToolResultIds.add(getToolUseId(part) ?? '');
322
- }
323
- if (options?.provider === Providers.ANTHROPIC) {
324
- const toolCallId = getToolCallId(part);
325
- if (toolCallId == null) {
326
- continue;
327
- }
328
- const preferredPart = preferredToolCallParts.get(toolCallId);
329
- if (preferredPart == null ||
330
- (!hasToolCallOutput(preferredPart) && hasToolCallOutput(part))) {
331
- preferredToolCallParts.set(toolCallId, part);
332
- }
333
- }
334
- }
335
- for (const part of contentParts) {
336
- if (part == null) {
337
- continue;
338
- }
339
- const toolUseId = getToolUseId(part);
340
- if (toolUseId != null) {
341
- const isServerToolResult = isValidServerToolResult(part);
342
- if (toolUseId.startsWith(Constants.ANTHROPIC_SERVER_TOOL_PREFIX) &&
343
- !isServerToolResult) {
344
- continue;
345
- }
346
- flushPendingServerToolUse(toolUseId);
347
- if (isServerToolResult) {
348
- currentContent.push(part);
349
- continue;
350
- }
351
- }
352
- else if (hasMeaningfulAssistantContent(part)) {
353
- for (const id of pendingServerToolUses.keys()) {
354
- if (!serverToolResultIds.has(id)) {
355
- pendingServerToolUses.delete(id);
356
- }
357
- }
358
- }
359
- if (part.type === ContentTypes.TEXT && part.tool_call_ids) {
360
- /*
361
- If there's pending content, it needs to be aggregated as a single string to prepare for tool calls.
362
- For Anthropic models, the "tool_calls" field on a message is only respected if content is a string.
363
- */
364
- if (currentContent.length > 0) {
365
- if (currentContent.some((content) => content.type !== ContentTypes.TEXT)) {
366
- currentContent.push(part);
367
- lastAIMessage = createAIMessage(toLangChainContent(currentContent));
368
- formattedMessages.push(lastAIMessage);
369
- currentContent = [];
370
- continue;
371
- }
372
- let content = currentContent.reduce((acc, curr) => {
373
- if (curr.type === ContentTypes.TEXT) {
374
- return `${acc}${getTextContent(curr)}\n`;
375
- }
376
- return acc;
377
- }, '');
378
- content = `${content}\n${getTextContent(part)}`.trim();
379
- lastAIMessage = createAIMessage(content);
380
- formattedMessages.push(lastAIMessage);
381
- currentContent = [];
382
- continue;
383
- }
384
- // Create a new AIMessage with this text and prepare for tool calls
385
- lastAIMessage = createAIMessage(getTextContent(part));
386
- formattedMessages.push(lastAIMessage);
387
- }
388
- else if (part.type === ContentTypes.TOOL_CALL) {
389
- // Skip malformed tool call entries without tool_call property
390
- if (part.tool_call == null) {
391
- continue;
392
- }
393
- const toolCallId = getToolCallId(part);
394
- if (options?.provider === Providers.ANTHROPIC &&
395
- toolCallId != null &&
396
- preferredToolCallParts.get(toolCallId) !== part) {
397
- continue;
398
- }
399
- // Note: `tool_calls` list is defined when constructed by `AIMessage` class, and outputs should be excluded from it
400
- const { output, args: _args, ..._tool_call } = part.tool_call;
401
- // Skip invalid tool calls that have no name AND no output
402
- if (_tool_call.name == null ||
403
- (_tool_call.name === '' && (output == null || output === ''))) {
404
- continue;
405
- }
406
- if (options?.provider === Providers.ANTHROPIC &&
407
- typeof _tool_call.id === 'string' &&
408
- _tool_call.id.startsWith(Constants.ANTHROPIC_SERVER_TOOL_PREFIX)) {
409
- if (!serverToolResultIds.has(_tool_call.id) &&
410
- options.preserveUnpairedServerToolUses !== true) {
411
- continue;
412
- }
413
- if (emittedServerToolUseIds.has(_tool_call.id) ||
414
- pendingServerToolUses.has(_tool_call.id)) {
415
- continue;
416
- }
417
- pendingServerToolUses.set(_tool_call.id, {
418
- type: 'server_tool_use',
419
- id: _tool_call.id,
420
- name: _tool_call.name,
421
- input: parseServerToolInput(_args),
422
- });
423
- continue;
424
- }
425
- if (!lastAIMessage) {
426
- // "Heal" the payload by creating an AIMessage to precede the tool call
427
- lastAIMessage = createAIMessage('');
428
- formattedMessages.push(lastAIMessage);
429
- }
430
- else {
431
- attachPendingReasoningContent(lastAIMessage);
432
- }
433
- const tool_call = _tool_call;
434
- // TODO: investigate; args as dictionary may need to be providers-or-tool-specific
435
- let args = _args;
436
- try {
437
- if (typeof _args === 'string') {
438
- args = JSON.parse(_args);
439
- }
440
- }
441
- catch {
442
- if (typeof _args === 'string') {
443
- args = { input: _args };
444
- }
445
- }
446
- tool_call.args = args;
447
- if (options?.provider === Providers.ANTHROPIC &&
448
- Array.isArray(lastAIMessage.content)) {
449
- const content = lastAIMessage.content;
450
- content.push({
451
- type: 'tool_use',
452
- id: normalizeAnthropicToolCallId(tool_call.id ?? ''),
453
- name: tool_call.name,
454
- input: args,
455
- });
456
- lastAIMessage.content = content;
457
- }
458
- else {
459
- if (!lastAIMessage.tool_calls) {
460
- lastAIMessage.tool_calls = [];
461
- }
462
- lastAIMessage.tool_calls.push(tool_call);
463
- }
464
- formattedMessages.push(withMessageRole(new ToolMessage({
465
- tool_call_id: tool_call.id ?? '',
466
- name: tool_call.name,
467
- content: output != null ? output : '',
468
- }), 'tool'));
469
- }
470
- else if (part.type === ContentTypes.THINK ||
471
- part.type === ContentTypes.THINKING ||
472
- part.type === ContentTypes.REASONING ||
473
- part.type === ContentTypes.REASONING_CONTENT ||
474
- part.type === 'redacted_thinking') {
475
- hasReasoning = true;
476
- pendingReasoningContent += extractReasoningContent(part);
477
- continue;
478
- }
479
- else if (part.type === ContentTypes.ERROR ||
480
- part.type === ContentTypes.AGENT_UPDATE ||
481
- part.type === ContentTypes.SUMMARY) {
482
- continue;
483
- }
484
- else {
485
- if (part.type === ContentTypes.TEXT && !getTextContent(part).trim()) {
486
- continue;
487
- }
488
- currentContent.push(part);
489
- }
490
- }
491
- for (const content of pendingServerToolUses.values()) {
492
- currentContent.push(content);
493
- }
494
- }
495
- if (hasReasoning && currentContent.length > 0) {
496
- let content = '';
497
- for (const part of currentContent) {
498
- if (part.type !== ContentTypes.TEXT) {
499
- formattedMessages.push(createAIMessage(toLangChainContent(currentContent)));
500
- return formattedMessages;
501
- }
502
- content += `${getTextContent(part)}\n`;
503
- }
504
- content = content.trim();
505
- if (content) {
506
- formattedMessages.push(createAIMessage(content));
507
- }
508
- }
509
- else if (currentContent.length > 0) {
510
- formattedMessages.push(createAIMessage(toLangChainContent(currentContent)));
511
- }
512
- return formattedMessages;
185
+ const formattedMessages = [];
186
+ let currentContent = [];
187
+ let lastAIMessage = null;
188
+ let hasReasoning = false;
189
+ let pendingReasoningContent = "";
190
+ const emittedServerToolUseIds = /* @__PURE__ */ new Set();
191
+ const pendingServerToolUses = /* @__PURE__ */ new Map();
192
+ const shouldPreserveReasoningContent = options?.preserveReasoningContent === true;
193
+ const serverToolResultIds = /* @__PURE__ */ new Set();
194
+ const preferredToolCallParts = /* @__PURE__ */ new Map();
195
+ const takePendingReasoningContent = () => {
196
+ if (!shouldPreserveReasoningContent || !pendingReasoningContent) return;
197
+ const reasoningContent = pendingReasoningContent;
198
+ pendingReasoningContent = "";
199
+ return reasoningContent;
200
+ };
201
+ const createAIMessage = (content) => {
202
+ const reasoningContent = takePendingReasoningContent();
203
+ return withMessageRole(new AIMessage({
204
+ content,
205
+ ...reasoningContent != null && { additional_kwargs: { reasoning_content: reasoningContent } }
206
+ }), "assistant");
207
+ };
208
+ const attachPendingReasoningContent = (aiMessage) => {
209
+ const reasoningContent = takePendingReasoningContent();
210
+ if (reasoningContent == null) return;
211
+ aiMessage.additional_kwargs.reasoning_content = typeof aiMessage.additional_kwargs.reasoning_content === "string" ? `${aiMessage.additional_kwargs.reasoning_content}${reasoningContent}` : reasoningContent;
212
+ };
213
+ const flushPendingServerToolUse = (toolUseId) => {
214
+ for (const [id, content] of pendingServerToolUses) {
215
+ pendingServerToolUses.delete(id);
216
+ if (id === toolUseId) {
217
+ currentContent.push(content);
218
+ emittedServerToolUseIds.add(id);
219
+ return;
220
+ }
221
+ }
222
+ };
223
+ if (Array.isArray(message.content)) {
224
+ const contentParts = message.content;
225
+ for (const part of contentParts) {
226
+ if (part == null) continue;
227
+ if (isValidServerToolResult(part)) serverToolResultIds.add(getToolUseId(part) ?? "");
228
+ if (options?.provider === "anthropic") {
229
+ const toolCallId = getToolCallId(part);
230
+ if (toolCallId == null) continue;
231
+ const preferredPart = preferredToolCallParts.get(toolCallId);
232
+ if (preferredPart == null || !hasToolCallOutput(preferredPart) && hasToolCallOutput(part)) preferredToolCallParts.set(toolCallId, part);
233
+ }
234
+ }
235
+ for (const part of contentParts) {
236
+ if (part == null) continue;
237
+ const toolUseId = getToolUseId(part);
238
+ if (toolUseId != null) {
239
+ const isServerToolResult = isValidServerToolResult(part);
240
+ if (toolUseId.startsWith("srvtoolu_") && !isServerToolResult) continue;
241
+ flushPendingServerToolUse(toolUseId);
242
+ if (isServerToolResult) {
243
+ currentContent.push(part);
244
+ continue;
245
+ }
246
+ } else if (hasMeaningfulAssistantContent(part)) {
247
+ for (const id of pendingServerToolUses.keys()) if (!serverToolResultIds.has(id)) pendingServerToolUses.delete(id);
248
+ }
249
+ if (part.type === "text" && part.tool_call_ids) {
250
+ if (currentContent.length > 0) {
251
+ if (currentContent.some((content) => content.type !== "text")) {
252
+ currentContent.push(part);
253
+ lastAIMessage = createAIMessage(toLangChainContent(currentContent));
254
+ formattedMessages.push(lastAIMessage);
255
+ currentContent = [];
256
+ continue;
257
+ }
258
+ let content = currentContent.reduce((acc, curr) => {
259
+ if (curr.type === "text") return `${acc}${getTextContent(curr)}\n`;
260
+ return acc;
261
+ }, "");
262
+ content = `${content}\n${getTextContent(part)}`.trim();
263
+ lastAIMessage = createAIMessage(content);
264
+ formattedMessages.push(lastAIMessage);
265
+ currentContent = [];
266
+ continue;
267
+ }
268
+ lastAIMessage = createAIMessage(getTextContent(part));
269
+ formattedMessages.push(lastAIMessage);
270
+ } else if (part.type === "tool_call") {
271
+ if (part.tool_call == null) continue;
272
+ const toolCallId = getToolCallId(part);
273
+ if (options?.provider === "anthropic" && toolCallId != null && preferredToolCallParts.get(toolCallId) !== part) continue;
274
+ const { output, args: _args, ..._tool_call } = part.tool_call;
275
+ if (_tool_call.name == null || _tool_call.name === "" && (output == null || output === "")) continue;
276
+ if (options?.provider === "anthropic" && typeof _tool_call.id === "string" && _tool_call.id.startsWith("srvtoolu_")) {
277
+ if (!serverToolResultIds.has(_tool_call.id) && options.preserveUnpairedServerToolUses !== true) continue;
278
+ if (emittedServerToolUseIds.has(_tool_call.id) || pendingServerToolUses.has(_tool_call.id)) continue;
279
+ pendingServerToolUses.set(_tool_call.id, {
280
+ type: "server_tool_use",
281
+ id: _tool_call.id,
282
+ name: _tool_call.name,
283
+ input: parseServerToolInput(_args)
284
+ });
285
+ continue;
286
+ }
287
+ if (!lastAIMessage) {
288
+ lastAIMessage = createAIMessage("");
289
+ formattedMessages.push(lastAIMessage);
290
+ } else attachPendingReasoningContent(lastAIMessage);
291
+ const tool_call = _tool_call;
292
+ let args = _args;
293
+ try {
294
+ if (typeof _args === "string") args = JSON.parse(_args);
295
+ } catch {
296
+ if (typeof _args === "string") args = { input: _args };
297
+ }
298
+ tool_call.args = args;
299
+ if (options?.provider === "anthropic" && Array.isArray(lastAIMessage.content)) {
300
+ const content = lastAIMessage.content;
301
+ content.push({
302
+ type: "tool_use",
303
+ id: normalizeAnthropicToolCallId(tool_call.id ?? ""),
304
+ name: tool_call.name,
305
+ input: args
306
+ });
307
+ lastAIMessage.content = content;
308
+ } else {
309
+ if (!lastAIMessage.tool_calls) lastAIMessage.tool_calls = [];
310
+ lastAIMessage.tool_calls.push(tool_call);
311
+ }
312
+ formattedMessages.push(withMessageRole(new ToolMessage({
313
+ tool_call_id: tool_call.id ?? "",
314
+ name: tool_call.name,
315
+ content: output != null ? output : ""
316
+ }), "tool"));
317
+ } else if (part.type === "think" || part.type === "thinking" || part.type === "reasoning" || part.type === "reasoning_content" || part.type === "redacted_thinking") {
318
+ hasReasoning = true;
319
+ pendingReasoningContent += extractReasoningContent(part);
320
+ continue;
321
+ } else if (part.type === "error" || part.type === "agent_update" || part.type === "summary") continue;
322
+ else {
323
+ if (part.type === "text" && !getTextContent(part).trim()) continue;
324
+ currentContent.push(part);
325
+ }
326
+ }
327
+ for (const content of pendingServerToolUses.values()) currentContent.push(content);
328
+ }
329
+ if (hasReasoning && currentContent.length > 0) {
330
+ let content = "";
331
+ for (const part of currentContent) {
332
+ if (part.type !== "text") {
333
+ formattedMessages.push(createAIMessage(toLangChainContent(currentContent)));
334
+ return formattedMessages;
335
+ }
336
+ content += `${getTextContent(part)}\n`;
337
+ }
338
+ content = content.trim();
339
+ if (content) formattedMessages.push(createAIMessage(content));
340
+ } else if (currentContent.length > 0) formattedMessages.push(createAIMessage(toLangChainContent(currentContent)));
341
+ return formattedMessages;
513
342
  }
514
343
  function getSourceMessageId(message) {
515
- const candidate = message.messageId ??
516
- message.id;
517
- if (typeof candidate !== 'string') {
518
- return undefined;
519
- }
520
- const normalized = candidate.trim();
521
- return normalized.length > 0 ? normalized : undefined;
344
+ const candidate = message.messageId ?? message.id;
345
+ if (typeof candidate !== "string") return;
346
+ const normalized = candidate.trim();
347
+ return normalized.length > 0 ? normalized : void 0;
522
348
  }
523
349
  /**
524
- * Labels all agent content for parallel patterns (fan-out/fan-in)
525
- * Groups consecutive content by agent and wraps with clear labels
526
- */
350
+ * Labels all agent content for parallel patterns (fan-out/fan-in)
351
+ * Groups consecutive content by agent and wraps with clear labels
352
+ */
527
353
  function labelAllAgentContent(contentParts, agentIdMap, agentNames) {
528
- const result = [];
529
- let currentAgentId;
530
- let agentContentBuffer = [];
531
- const flushAgentBuffer = () => {
532
- if (agentContentBuffer.length === 0) {
533
- return;
534
- }
535
- if (currentAgentId != null && currentAgentId !== '') {
536
- const agentName = (agentNames?.[currentAgentId] ?? '') || currentAgentId;
537
- const formattedParts = [];
538
- formattedParts.push(`--- ${agentName} ---`);
539
- for (const part of agentContentBuffer) {
540
- if (part.type === ContentTypes.THINK) {
541
- const thinkContent = part.think || '';
542
- if (thinkContent) {
543
- formattedParts.push(`${agentName}: ${JSON.stringify({
544
- type: 'think',
545
- think: thinkContent,
546
- })}`);
547
- }
548
- }
549
- else if (part.type === ContentTypes.TEXT) {
550
- const textContent = part.text ?? '';
551
- if (textContent) {
552
- formattedParts.push(`${agentName}: ${textContent}`);
553
- }
554
- }
555
- else if (part.type === ContentTypes.TOOL_CALL) {
556
- formattedParts.push(`${agentName}: ${JSON.stringify({
557
- type: 'tool_call',
558
- tool_call: part.tool_call,
559
- })}`);
560
- }
561
- }
562
- formattedParts.push(`--- End of ${agentName} ---`);
563
- // Create a single text content part with all agent content
564
- result.push({
565
- type: ContentTypes.TEXT,
566
- text: formattedParts.join('\n\n'),
567
- });
568
- }
569
- else {
570
- // No agent ID, pass through as-is
571
- result.push(...agentContentBuffer);
572
- }
573
- agentContentBuffer = [];
574
- };
575
- for (let i = 0; i < contentParts.length; i++) {
576
- const part = contentParts[i];
577
- const agentId = agentIdMap[i];
578
- // If agent changed, flush previous buffer
579
- if (agentId !== currentAgentId && currentAgentId !== undefined) {
580
- flushAgentBuffer();
581
- }
582
- currentAgentId = agentId;
583
- agentContentBuffer.push(part);
584
- }
585
- // Flush any remaining content
586
- flushAgentBuffer();
587
- return result;
354
+ const result = [];
355
+ let currentAgentId;
356
+ let agentContentBuffer = [];
357
+ const flushAgentBuffer = () => {
358
+ if (agentContentBuffer.length === 0) return;
359
+ if (currentAgentId != null && currentAgentId !== "") {
360
+ const agentName = (agentNames?.[currentAgentId] ?? "") || currentAgentId;
361
+ const formattedParts = [];
362
+ formattedParts.push(`--- ${agentName} ---`);
363
+ for (const part of agentContentBuffer) if (part.type === "think") {
364
+ const thinkContent = part.think || "";
365
+ if (thinkContent) formattedParts.push(`${agentName}: ${JSON.stringify({
366
+ type: "think",
367
+ think: thinkContent
368
+ })}`);
369
+ } else if (part.type === "text") {
370
+ const textContent = part.text ?? "";
371
+ if (textContent) formattedParts.push(`${agentName}: ${textContent}`);
372
+ } else if (part.type === "tool_call") formattedParts.push(`${agentName}: ${JSON.stringify({
373
+ type: "tool_call",
374
+ tool_call: part.tool_call
375
+ })}`);
376
+ formattedParts.push(`--- End of ${agentName} ---`);
377
+ result.push({
378
+ type: "text",
379
+ text: formattedParts.join("\n\n")
380
+ });
381
+ } else result.push(...agentContentBuffer);
382
+ agentContentBuffer = [];
383
+ };
384
+ for (let i = 0; i < contentParts.length; i++) {
385
+ const part = contentParts[i];
386
+ const agentId = agentIdMap[i];
387
+ if (agentId !== currentAgentId && currentAgentId !== void 0) flushAgentBuffer();
388
+ currentAgentId = agentId;
389
+ agentContentBuffer.push(part);
390
+ }
391
+ flushAgentBuffer();
392
+ return result;
588
393
  }
589
394
  /**
590
- * Groups content parts by agent and formats them with agent labels
591
- * This preprocesses multi-agent content to prevent identity confusion
592
- *
593
- * @param contentParts - The content parts from a run
594
- * @param agentIdMap - Map of content part index to agent ID
595
- * @param agentNames - Optional map of agent ID to display name
596
- * @param options - Configuration options
597
- * @param options.labelNonTransferContent - If true, labels all agent transitions (for parallel patterns)
598
- * @returns Modified content parts with agent labels where appropriate
599
- */
395
+ * Groups content parts by agent and formats them with agent labels
396
+ * This preprocesses multi-agent content to prevent identity confusion
397
+ *
398
+ * @param contentParts - The content parts from a run
399
+ * @param agentIdMap - Map of content part index to agent ID
400
+ * @param agentNames - Optional map of agent ID to display name
401
+ * @param options - Configuration options
402
+ * @param options.labelNonTransferContent - If true, labels all agent transitions (for parallel patterns)
403
+ * @returns Modified content parts with agent labels where appropriate
404
+ */
600
405
  const labelContentByAgent = (contentParts, agentIdMap, agentNames, options) => {
601
- if (!agentIdMap || Object.keys(agentIdMap).length === 0) {
602
- return contentParts;
603
- }
604
- // If labelNonTransferContent is true, use a different strategy for parallel patterns
605
- if (options?.labelNonTransferContent === true) {
606
- return labelAllAgentContent(contentParts, agentIdMap, agentNames);
607
- }
608
- const result = [];
609
- let currentAgentId;
610
- let agentContentBuffer = [];
611
- let transferToolCallIndex;
612
- let transferToolCallId;
613
- const flushAgentBuffer = () => {
614
- if (agentContentBuffer.length === 0) {
615
- return;
616
- }
617
- // If this is content from a transferred agent, format it specially
618
- if (currentAgentId != null &&
619
- currentAgentId !== '' &&
620
- transferToolCallIndex !== undefined) {
621
- const agentName = (agentNames?.[currentAgentId] ?? '') || currentAgentId;
622
- const formattedParts = [];
623
- formattedParts.push(`--- Transfer to ${agentName} ---`);
624
- for (const part of agentContentBuffer) {
625
- if (part.type === ContentTypes.THINK) {
626
- formattedParts.push(`${agentName}: ${JSON.stringify({
627
- type: 'think',
628
- think: part.think,
629
- })}`);
630
- }
631
- else if ('text' in part && part.type === ContentTypes.TEXT) {
632
- const textContent = part.text ?? '';
633
- if (textContent) {
634
- formattedParts.push(`${agentName}: ${JSON.stringify({
635
- type: 'text',
636
- text: textContent,
637
- })}`);
638
- }
639
- }
640
- else if (part.type === ContentTypes.TOOL_CALL) {
641
- formattedParts.push(`${agentName}: ${JSON.stringify({
642
- type: 'tool_call',
643
- tool_call: part.tool_call,
644
- })}`);
645
- }
646
- }
647
- formattedParts.push(`--- End of ${agentName} response ---`);
648
- // Find the tool call that triggered this transfer and update its output
649
- if (transferToolCallIndex < result.length) {
650
- const transferToolCall = result[transferToolCallIndex];
651
- if (transferToolCall.type === ContentTypes.TOOL_CALL &&
652
- transferToolCall.tool_call?.id === transferToolCallId) {
653
- transferToolCall.tool_call.output = formattedParts.join('\n\n');
654
- }
655
- }
656
- }
657
- else {
658
- // Not from a transfer, add as-is
659
- result.push(...agentContentBuffer);
660
- }
661
- agentContentBuffer = [];
662
- transferToolCallIndex = undefined;
663
- transferToolCallId = undefined;
664
- };
665
- for (let i = 0; i < contentParts.length; i++) {
666
- const part = contentParts[i];
667
- const agentId = agentIdMap[i];
668
- // Check if this is a transfer tool call
669
- const isTransferTool = (part.type === ContentTypes.TOOL_CALL &&
670
- part.tool_call?.name?.startsWith('lc_transfer_to_')) ??
671
- false;
672
- // If agent changed, flush previous buffer
673
- if (agentId !== currentAgentId && currentAgentId !== undefined) {
674
- flushAgentBuffer();
675
- }
676
- currentAgentId = agentId;
677
- if (isTransferTool) {
678
- // Flush any existing buffer first
679
- flushAgentBuffer();
680
- // Add the transfer tool call to result
681
- result.push(part);
682
- // Mark that the next agent's content should be captured
683
- transferToolCallIndex = result.length - 1;
684
- transferToolCallId = part.tool_call?.id;
685
- currentAgentId = undefined; // Reset to capture the next agent
686
- }
687
- else {
688
- agentContentBuffer.push(part);
689
- }
690
- }
691
- flushAgentBuffer();
692
- return result;
406
+ if (!agentIdMap || Object.keys(agentIdMap).length === 0) return contentParts;
407
+ if (options?.labelNonTransferContent === true) return labelAllAgentContent(contentParts, agentIdMap, agentNames);
408
+ const result = [];
409
+ let currentAgentId;
410
+ let agentContentBuffer = [];
411
+ let transferToolCallIndex;
412
+ let transferToolCallId;
413
+ const flushAgentBuffer = () => {
414
+ if (agentContentBuffer.length === 0) return;
415
+ if (currentAgentId != null && currentAgentId !== "" && transferToolCallIndex !== void 0) {
416
+ const agentName = (agentNames?.[currentAgentId] ?? "") || currentAgentId;
417
+ const formattedParts = [];
418
+ formattedParts.push(`--- Transfer to ${agentName} ---`);
419
+ for (const part of agentContentBuffer) if (part.type === "think") formattedParts.push(`${agentName}: ${JSON.stringify({
420
+ type: "think",
421
+ think: part.think
422
+ })}`);
423
+ else if ("text" in part && part.type === "text") {
424
+ const textContent = part.text ?? "";
425
+ if (textContent) formattedParts.push(`${agentName}: ${JSON.stringify({
426
+ type: "text",
427
+ text: textContent
428
+ })}`);
429
+ } else if (part.type === "tool_call") formattedParts.push(`${agentName}: ${JSON.stringify({
430
+ type: "tool_call",
431
+ tool_call: part.tool_call
432
+ })}`);
433
+ formattedParts.push(`--- End of ${agentName} response ---`);
434
+ if (transferToolCallIndex < result.length) {
435
+ const transferToolCall = result[transferToolCallIndex];
436
+ if (transferToolCall.type === "tool_call" && transferToolCall.tool_call?.id === transferToolCallId) transferToolCall.tool_call.output = formattedParts.join("\n\n");
437
+ }
438
+ } else result.push(...agentContentBuffer);
439
+ agentContentBuffer = [];
440
+ transferToolCallIndex = void 0;
441
+ transferToolCallId = void 0;
442
+ };
443
+ for (let i = 0; i < contentParts.length; i++) {
444
+ const part = contentParts[i];
445
+ const agentId = agentIdMap[i];
446
+ const isTransferTool = (part.type === "tool_call" && part.tool_call?.name?.startsWith("lc_transfer_to_")) ?? false;
447
+ if (agentId !== currentAgentId && currentAgentId !== void 0) flushAgentBuffer();
448
+ currentAgentId = agentId;
449
+ if (isTransferTool) {
450
+ flushAgentBuffer();
451
+ result.push(part);
452
+ transferToolCallIndex = result.length - 1;
453
+ transferToolCallId = part.tool_call?.id;
454
+ currentAgentId = void 0;
455
+ } else agentContentBuffer.push(part);
456
+ }
457
+ flushAgentBuffer();
458
+ return result;
693
459
  };
694
460
  /** Extracts tool names from a tool_search output JSON string. */
695
461
  function extractToolNamesFromSearchOutput(output) {
696
- try {
697
- const parsed = JSON.parse(output);
698
- if (typeof parsed === 'object' &&
699
- parsed !== null &&
700
- Array.isArray(parsed.tools)) {
701
- return parsed.tools
702
- .map((t) => t.name)
703
- .filter((name) => typeof name === 'string');
704
- }
705
- }
706
- catch {
707
- /** Output may have warnings prepended, try to find JSON within it */
708
- const jsonMatch = output.match(/\{[\s\S]*\}/);
709
- if (jsonMatch) {
710
- try {
711
- const parsed = JSON.parse(jsonMatch[0]);
712
- if (typeof parsed === 'object' &&
713
- parsed !== null &&
714
- Array.isArray(parsed.tools)) {
715
- return parsed.tools
716
- .map((t) => t.name)
717
- .filter((name) => typeof name === 'string');
718
- }
719
- }
720
- catch {
721
- /* ignore */
722
- }
723
- }
724
- }
725
- return [];
462
+ try {
463
+ const parsed = JSON.parse(output);
464
+ if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.tools)) return parsed.tools.map((t) => t.name).filter((name) => typeof name === "string");
465
+ } catch {
466
+ /** Output may have warnings prepended, try to find JSON within it */
467
+ const jsonMatch = output.match(/\{[\s\S]*\}/);
468
+ if (jsonMatch) try {
469
+ const parsed = JSON.parse(jsonMatch[0]);
470
+ if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.tools)) return parsed.tools.map((t) => t.name).filter((name) => typeof name === "string");
471
+ } catch {}
472
+ }
473
+ return [];
726
474
  }
727
475
  function getLatestSummaryBoundary(payload) {
728
- let summaryBoundary;
729
- for (let i = 0; i < payload.length; i++) {
730
- const message = payload[i];
731
- if (!Array.isArray(message.content)) {
732
- continue;
733
- }
734
- for (let j = 0; j < message.content.length; j++) {
735
- const part = message.content[j];
736
- if (part == null || part.type !== ContentTypes.SUMMARY) {
737
- continue;
738
- }
739
- const summaryPart = part;
740
- // Try content array first (new format), then direct text (legacy format)
741
- let summaryText = (summaryPart.content ?? [])
742
- .map((block) => 'text' in block ? block.text : '')
743
- .join('')
744
- .trim();
745
- // Fallback: legacy format where text was a direct field on the block
746
- if (summaryText.length === 0 && typeof summaryPart.text === 'string') {
747
- summaryText = summaryPart.text.trim();
748
- }
749
- if (summaryText.length === 0) {
750
- continue;
751
- }
752
- summaryBoundary = {
753
- messageIndex: i,
754
- contentIndex: j,
755
- text: summaryText,
756
- tokenCount: typeof summaryPart.tokenCount === 'number' &&
757
- Number.isFinite(summaryPart.tokenCount)
758
- ? summaryPart.tokenCount
759
- : 0,
760
- };
761
- }
762
- }
763
- return summaryBoundary;
476
+ let summaryBoundary;
477
+ for (let i = 0; i < payload.length; i++) {
478
+ const message = payload[i];
479
+ if (!Array.isArray(message.content)) continue;
480
+ for (let j = 0; j < message.content.length; j++) {
481
+ const part = message.content[j];
482
+ if (part == null || part.type !== "summary") continue;
483
+ const summaryPart = part;
484
+ let summaryText = (summaryPart.content ?? []).map((block) => "text" in block ? block.text : "").join("").trim();
485
+ if (summaryText.length === 0 && typeof summaryPart.text === "string") summaryText = summaryPart.text.trim();
486
+ if (summaryText.length === 0) continue;
487
+ summaryBoundary = {
488
+ messageIndex: i,
489
+ contentIndex: j,
490
+ text: summaryText,
491
+ tokenCount: typeof summaryPart.tokenCount === "number" && Number.isFinite(summaryPart.tokenCount) ? summaryPart.tokenCount : 0
492
+ };
493
+ }
494
+ }
495
+ return summaryBoundary;
764
496
  }
765
497
  function applySummaryBoundary(message, messageIndex, summaryBoundary) {
766
- if (!summaryBoundary) {
767
- return message;
768
- }
769
- if (messageIndex < summaryBoundary.messageIndex) {
770
- return null;
771
- }
772
- if (messageIndex !== summaryBoundary.messageIndex ||
773
- !Array.isArray(message.content)) {
774
- return message;
775
- }
776
- return {
777
- ...message,
778
- content: message.content.slice(summaryBoundary.contentIndex + 1),
779
- };
498
+ if (!summaryBoundary) return message;
499
+ if (messageIndex < summaryBoundary.messageIndex) return null;
500
+ if (messageIndex !== summaryBoundary.messageIndex || !Array.isArray(message.content)) return message;
501
+ return {
502
+ ...message,
503
+ content: message.content.slice(summaryBoundary.contentIndex + 1)
504
+ };
780
505
  }
781
506
  function contentPartCharLength(part) {
782
- const record = part;
783
- let len = 0;
784
- if (typeof record.text === 'string') {
785
- len += record.text.length;
786
- }
787
- if (typeof record.thinking === 'string') {
788
- len += record.thinking.length;
789
- }
790
- const { input } = record;
791
- if (typeof input === 'string') {
792
- len += input.length;
793
- }
794
- else if (input != null && typeof input === 'object') {
795
- len += JSON.stringify(input).length;
796
- }
797
- return len;
507
+ const record = part;
508
+ let len = 0;
509
+ if (typeof record.text === "string") len += record.text.length;
510
+ if (typeof record.thinking === "string") len += record.thinking.length;
511
+ const { input } = record;
512
+ if (typeof input === "string") len += input.length;
513
+ else if (input != null && typeof input === "object") len += JSON.stringify(input).length;
514
+ return len;
798
515
  }
799
516
  /** Extracts the skillName from a skill tool_call's args (string or object). */
800
517
  function extractSkillName(args) {
801
- let parsed;
802
- if (typeof args === 'string') {
803
- try {
804
- parsed = JSON.parse(args);
805
- }
806
- catch {
807
- /* malformed args skip */
808
- }
809
- }
810
- else {
811
- parsed = args;
812
- }
813
- const name = parsed?.skillName;
814
- return typeof name === 'string' && name !== '' ? name : undefined;
518
+ let parsed;
519
+ if (typeof args === "string") try {
520
+ parsed = JSON.parse(args);
521
+ } catch {}
522
+ else parsed = args;
523
+ const name = parsed?.skillName;
524
+ return typeof name === "string" && name !== "" ? name : void 0;
815
525
  }
816
526
  /**
817
- * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
818
- *
819
- * @param payload - The array of messages to format.
820
- * @param indexTokenCountMap - Optional map of message indices to token counts.
821
- * @param tools - Optional set of tool names that are allowed in the request.
822
- * @param skills - Optional map of skill name to body for reconstructing skill HumanMessages.
823
- * @param options - Optional formatting options (provider, skipSkillBodyNames).
824
- * @returns - Object containing formatted messages and updated indexTokenCountMap if provided.
825
- */
826
- const formatAgentMessages = (payload, indexTokenCountMap, tools,
827
- /** Pre-resolved skill bodies keyed by skill name. When present, HumanMessages
828
- * are reconstructed after skill ToolMessages to restore skill instructions
829
- * that were only in LangGraph state during the original run. */
830
- skills, options) => {
831
- const messages = [];
832
- // If indexTokenCountMap is provided, create a new map to track the updated indices
833
- const updatedIndexTokenCountMap = {};
834
- let boundaryTokenAdjustment;
835
- // Keep track of the mapping from original payload indices to result indices
836
- const indexMapping = {};
837
- const summaryBoundary = getLatestSummaryBoundary(payload);
838
- // Summary metadata is returned to the caller so it can be forwarded to the
839
- // agent run and included in the single system message via AgentContext.
840
- // We intentionally do NOT create a SystemMessage here — that would conflict
841
- // with the agent's own system message (instructions + summary combined).
842
- /**
843
- * Create a mutable copy of the tools set that can be expanded dynamically.
844
- * When we encounter tool_search results, we add discovered tools to this set,
845
- * making their subsequent tool calls valid.
846
- */
847
- const discoveredTools = tools ? new Set(tools) : undefined;
848
- // Process messages with tool conversion if tools set is provided
849
- for (let i = 0; i < payload.length; i++) {
850
- const rawMessage = payload[i];
851
- const sourceMessageId = getSourceMessageId(rawMessage);
852
- let message = applySummaryBoundary(rawMessage, i, summaryBoundary);
853
- if (!message) {
854
- indexMapping[i] = [];
855
- continue;
856
- }
857
- // Q: Store the current length of messages to track where this payload message starts in the result?
858
- // const startIndex = messages.length;
859
- if (typeof message.content === 'string') {
860
- message = {
861
- ...message,
862
- content: [
863
- { type: ContentTypes.TEXT, [ContentTypes.TEXT]: message.content },
864
- ],
865
- };
866
- }
867
- else if (Array.isArray(message.content) && message.content.length === 0) {
868
- indexMapping[i] = [];
869
- continue;
870
- }
871
- if (message.role !== 'assistant') {
872
- const formattedMessage = formatMessage({
873
- message: message,
874
- langChain: true,
875
- });
876
- if (sourceMessageId != null && sourceMessageId !== '') {
877
- formattedMessage.id = sourceMessageId;
878
- }
879
- messages.push(formattedMessage);
880
- // Update the index mapping for this message
881
- indexMapping[i] = [messages.length - 1];
882
- continue;
883
- }
884
- // For assistant messages, track the starting index before processing
885
- const startMessageIndex = messages.length;
886
- /**
887
- * If tools set is provided, process tool_calls:
888
- * - Keep valid tool_calls (tools in the set or dynamically discovered)
889
- * - Convert invalid tool_calls to string representation for context preservation
890
- * - Dynamically expand the set when tool_search results are encountered
891
- */
892
- let processedMessage = message;
893
- let pendingSkillNames;
894
- if (discoveredTools) {
895
- const content = message.content;
896
- if (content != null && Array.isArray(content)) {
897
- const filteredContent = [];
898
- const invalidToolCallIds = new Set();
899
- const invalidToolStrings = [];
900
- for (const part of content) {
901
- if (part.type !== ContentTypes.TOOL_CALL) {
902
- filteredContent.push(part);
903
- continue;
904
- }
905
- /** Skip malformed tool_call entries */
906
- if (part.tool_call == null ||
907
- part.tool_call.name == null ||
908
- part.tool_call.name === '') {
909
- if (typeof part.tool_call?.id === 'string' &&
910
- part.tool_call.id !== '') {
911
- invalidToolCallIds.add(part.tool_call.id);
912
- }
913
- continue;
914
- }
915
- const toolName = part.tool_call.name;
916
- /**
917
- * If this is a tool_search result with output, extract discovered tool names
918
- * and add them to the discoveredTools set for subsequent validation.
919
- */
920
- if (toolName === Constants.TOOL_SEARCH &&
921
- typeof part.tool_call.output === 'string' &&
922
- part.tool_call.output !== '') {
923
- const extracted = extractToolNamesFromSearchOutput(part.tool_call.output);
924
- for (const name of extracted) {
925
- discoveredTools.add(name);
926
- }
927
- }
928
- if (discoveredTools.has(toolName)) {
929
- filteredContent.push(part);
930
- if (toolName === Constants.SKILL_TOOL &&
931
- skills?.size != null &&
932
- skills.size > 0) {
933
- const skillName = extractSkillName(part.tool_call.args) ?? '';
934
- if (skillName) {
935
- (pendingSkillNames ??= new Set()).add(skillName);
936
- }
937
- }
938
- }
939
- else {
940
- /** Invalid tool - convert to string for context preservation */
941
- if (typeof part.tool_call.id === 'string' &&
942
- part.tool_call.id !== '') {
943
- invalidToolCallIds.add(part.tool_call.id);
944
- }
945
- const output = part.tool_call.output ?? '';
946
- invalidToolStrings.push(`Tool: ${toolName}, ${output}`);
947
- }
948
- }
949
- /** Remove tool_call_ids references to invalid tools from text parts */
950
- if (invalidToolCallIds.size > 0) {
951
- for (const part of filteredContent) {
952
- if (part.type === ContentTypes.TEXT &&
953
- Array.isArray(part.tool_call_ids)) {
954
- part.tool_call_ids = part.tool_call_ids.filter((id) => !invalidToolCallIds.has(id));
955
- if (part.tool_call_ids.length === 0) {
956
- delete part.tool_call_ids;
957
- }
958
- }
959
- }
960
- }
961
- /** Append invalid tool strings to the content for context preservation */
962
- if (invalidToolStrings.length > 0) {
963
- /** Find the last text part or create one */
964
- let lastTextPartIndex = -1;
965
- for (let j = filteredContent.length - 1; j >= 0; j--) {
966
- if (filteredContent[j].type === ContentTypes.TEXT) {
967
- lastTextPartIndex = j;
968
- break;
969
- }
970
- }
971
- const invalidToolText = invalidToolStrings.join('\n');
972
- if (lastTextPartIndex >= 0) {
973
- const lastTextPart = filteredContent[lastTextPartIndex];
974
- const existingText = lastTextPart[ContentTypes.TEXT] ?? lastTextPart.text ?? '';
975
- filteredContent[lastTextPartIndex] = {
976
- ...lastTextPart,
977
- [ContentTypes.TEXT]: existingText
978
- ? `${existingText}\n${invalidToolText}`
979
- : invalidToolText,
980
- };
981
- }
982
- else {
983
- /** No text part exists, create one */
984
- filteredContent.push({
985
- type: ContentTypes.TEXT,
986
- [ContentTypes.TEXT]: invalidToolText,
987
- });
988
- }
989
- }
990
- /** Use filtered content if we made any changes */
991
- if (filteredContent.length !== content.length ||
992
- invalidToolStrings.length > 0) {
993
- processedMessage = { ...message, content: filteredContent };
994
- }
995
- }
996
- }
997
- /** When tools filtering is off, still detect skill tool_calls for body reconstruction */
998
- if (!discoveredTools && skills?.size != null && skills.size > 0) {
999
- const content = processedMessage.content;
1000
- if (Array.isArray(content)) {
1001
- for (const part of content) {
1002
- if (part.type !== ContentTypes.TOOL_CALL ||
1003
- part.tool_call?.name !== Constants.SKILL_TOOL) {
1004
- continue;
1005
- }
1006
- const skillName = extractSkillName(part.tool_call.args) ?? '';
1007
- if (skillName) {
1008
- (pendingSkillNames ??= new Set()).add(skillName);
1009
- }
1010
- }
1011
- }
1012
- }
1013
- const formattedMessages = formatAssistantMessage(processedMessage, {
1014
- preserveUnpairedServerToolUses: i === payload.length - 1,
1015
- preserveReasoningContent: options?.provider === Providers.DEEPSEEK,
1016
- provider: options?.provider,
1017
- });
1018
- if (sourceMessageId != null && sourceMessageId !== '') {
1019
- for (const formattedMessage of formattedMessages) {
1020
- formattedMessage.id = sourceMessageId;
1021
- }
1022
- }
1023
- messages.push(...formattedMessages);
1024
- // Capture index range BEFORE skill body injection so injected
1025
- // HumanMessages are excluded from the assistant's token distribution.
1026
- const endMessageIndex = messages.length;
1027
- if (pendingSkillNames?.size != null && pendingSkillNames.size > 0) {
1028
- const skipSkillBodyNames = options?.skipSkillBodyNames;
1029
- for (const skillName of pendingSkillNames) {
1030
- if (skipSkillBodyNames != null && skipSkillBodyNames.has(skillName)) {
1031
- continue;
1032
- }
1033
- const body = skills?.get(skillName) ?? '';
1034
- if (body) {
1035
- messages.push(withMessageRole(new HumanMessage({
1036
- content: body,
1037
- additional_kwargs: {
1038
- role: 'user',
1039
- isMeta: true,
1040
- source: 'skill',
1041
- skillName,
1042
- },
1043
- }), 'user'));
1044
- }
1045
- }
1046
- }
1047
- const resultIndices = [];
1048
- for (let j = startMessageIndex; j < endMessageIndex; j++) {
1049
- resultIndices.push(j);
1050
- }
1051
- indexMapping[i] = resultIndices;
1052
- }
1053
- if (indexTokenCountMap) {
1054
- for (let originalIndex = 0; originalIndex < payload.length; originalIndex++) {
1055
- const resultIndices = indexMapping[originalIndex] || [];
1056
- let tokenCount = indexTokenCountMap[originalIndex];
1057
- if (tokenCount === undefined) {
1058
- continue;
1059
- }
1060
- if (summaryBoundary &&
1061
- originalIndex === summaryBoundary.messageIndex &&
1062
- Array.isArray(payload[originalIndex].content)) {
1063
- const content = payload[originalIndex]
1064
- .content;
1065
- const { contentIndex } = summaryBoundary;
1066
- if (contentIndex >= 0 && contentIndex < content.length - 1) {
1067
- let totalCharLen = 0;
1068
- let remainingCharLen = 0;
1069
- for (let p = 0; p < content.length; p++) {
1070
- const charLen = contentPartCharLength(content[p]);
1071
- totalCharLen += charLen;
1072
- if (p > contentIndex) {
1073
- remainingCharLen += charLen;
1074
- }
1075
- }
1076
- if (totalCharLen > 0) {
1077
- const original = tokenCount;
1078
- tokenCount = Math.max(1, Math.round(tokenCount * (remainingCharLen / totalCharLen)));
1079
- boundaryTokenAdjustment = {
1080
- original,
1081
- adjusted: tokenCount,
1082
- remainingChars: remainingCharLen,
1083
- totalChars: totalCharLen,
1084
- };
1085
- }
1086
- }
1087
- }
1088
- const msgCount = resultIndices.length;
1089
- if (msgCount === 1) {
1090
- updatedIndexTokenCountMap[resultIndices[0]] = tokenCount;
1091
- continue;
1092
- }
1093
- if (msgCount < 2) {
1094
- continue;
1095
- }
1096
- let totalLength = 0;
1097
- const lastIdx = msgCount - 1;
1098
- const lengths = new Array(msgCount);
1099
- for (let k = 0; k < msgCount; k++) {
1100
- const msg = messages[resultIndices[k]];
1101
- const { content } = msg;
1102
- let len = 0;
1103
- if (typeof content === 'string') {
1104
- len = content.length;
1105
- }
1106
- else if (Array.isArray(content)) {
1107
- for (const part of content) {
1108
- if (typeof part === 'string') {
1109
- len += part.length;
1110
- }
1111
- else if (part != null && typeof part === 'object') {
1112
- const val = part.text ?? part.content;
1113
- if (typeof val === 'string') {
1114
- len += val.length;
1115
- }
1116
- }
1117
- }
1118
- }
1119
- const toolCalls = msg.tool_calls;
1120
- if (Array.isArray(toolCalls)) {
1121
- for (const tc of toolCalls) {
1122
- if (typeof tc.name === 'string') {
1123
- len += tc.name.length;
1124
- }
1125
- const { args } = tc;
1126
- if (typeof args === 'string') {
1127
- len += args.length;
1128
- }
1129
- else if (args != null) {
1130
- len += JSON.stringify(args).length;
1131
- }
1132
- }
1133
- }
1134
- lengths[k] = len;
1135
- totalLength += len;
1136
- }
1137
- if (totalLength === 0) {
1138
- const countPerMessage = Math.floor(tokenCount / msgCount);
1139
- for (let k = 0; k < lastIdx; k++) {
1140
- updatedIndexTokenCountMap[resultIndices[k]] = countPerMessage;
1141
- }
1142
- updatedIndexTokenCountMap[resultIndices[lastIdx]] =
1143
- tokenCount - countPerMessage * lastIdx;
1144
- }
1145
- else {
1146
- let distributed = 0;
1147
- for (let k = 0; k < lastIdx; k++) {
1148
- const share = Math.floor((lengths[k] / totalLength) * tokenCount);
1149
- updatedIndexTokenCountMap[resultIndices[k]] = share;
1150
- distributed += share;
1151
- }
1152
- updatedIndexTokenCountMap[resultIndices[lastIdx]] =
1153
- tokenCount - distributed;
1154
- }
1155
- }
1156
- }
1157
- return {
1158
- messages,
1159
- indexTokenCountMap: indexTokenCountMap
1160
- ? updatedIndexTokenCountMap
1161
- : undefined,
1162
- summary: summaryBoundary
1163
- ? { text: summaryBoundary.text, tokenCount: summaryBoundary.tokenCount }
1164
- : undefined,
1165
- boundaryTokenAdjustment,
1166
- };
527
+ * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
528
+ *
529
+ * @param payload - The array of messages to format.
530
+ * @param indexTokenCountMap - Optional map of message indices to token counts.
531
+ * @param tools - Optional set of tool names that are allowed in the request.
532
+ * @param skills - Optional map of skill name to body for reconstructing skill HumanMessages.
533
+ * @param options - Optional formatting options (provider, skipSkillBodyNames).
534
+ * @returns - Object containing formatted messages and updated indexTokenCountMap if provided.
535
+ */
536
+ const formatAgentMessages = (payload, indexTokenCountMap, tools, skills, options) => {
537
+ const messages = [];
538
+ const updatedIndexTokenCountMap = {};
539
+ let boundaryTokenAdjustment;
540
+ const indexMapping = {};
541
+ const summaryBoundary = getLatestSummaryBoundary(payload);
542
+ /**
543
+ * Create a mutable copy of the tools set that can be expanded dynamically.
544
+ * When we encounter tool_search results, we add discovered tools to this set,
545
+ * making their subsequent tool calls valid.
546
+ */
547
+ const discoveredTools = tools ? new Set(tools) : void 0;
548
+ for (let i = 0; i < payload.length; i++) {
549
+ const rawMessage = payload[i];
550
+ const sourceMessageId = getSourceMessageId(rawMessage);
551
+ let message = applySummaryBoundary(rawMessage, i, summaryBoundary);
552
+ if (!message) {
553
+ indexMapping[i] = [];
554
+ continue;
555
+ }
556
+ if (typeof message.content === "string") message = {
557
+ ...message,
558
+ content: [{
559
+ type: "text",
560
+ ["text"]: message.content
561
+ }]
562
+ };
563
+ else if (Array.isArray(message.content) && message.content.length === 0) {
564
+ indexMapping[i] = [];
565
+ continue;
566
+ }
567
+ if (message.role !== "assistant") {
568
+ const formattedMessage = formatMessage({
569
+ message,
570
+ langChain: true
571
+ });
572
+ if (sourceMessageId != null && sourceMessageId !== "") formattedMessage.id = sourceMessageId;
573
+ messages.push(formattedMessage);
574
+ indexMapping[i] = [messages.length - 1];
575
+ continue;
576
+ }
577
+ const startMessageIndex = messages.length;
578
+ /**
579
+ * If tools set is provided, process tool_calls:
580
+ * - Keep valid tool_calls (tools in the set or dynamically discovered)
581
+ * - Convert invalid tool_calls to string representation for context preservation
582
+ * - Dynamically expand the set when tool_search results are encountered
583
+ */
584
+ let processedMessage = message;
585
+ let pendingSkillNames;
586
+ if (discoveredTools) {
587
+ const content = message.content;
588
+ if (content != null && Array.isArray(content)) {
589
+ const filteredContent = [];
590
+ const invalidToolCallIds = /* @__PURE__ */ new Set();
591
+ const invalidToolStrings = [];
592
+ for (const part of content) {
593
+ if (part.type !== "tool_call") {
594
+ filteredContent.push(part);
595
+ continue;
596
+ }
597
+ /** Skip malformed tool_call entries */
598
+ if (part.tool_call == null || part.tool_call.name == null || part.tool_call.name === "") {
599
+ if (typeof part.tool_call?.id === "string" && part.tool_call.id !== "") invalidToolCallIds.add(part.tool_call.id);
600
+ continue;
601
+ }
602
+ const toolName = part.tool_call.name;
603
+ /**
604
+ * If this is a tool_search result with output, extract discovered tool names
605
+ * and add them to the discoveredTools set for subsequent validation.
606
+ */
607
+ if (toolName === "tool_search" && typeof part.tool_call.output === "string" && part.tool_call.output !== "") {
608
+ const extracted = extractToolNamesFromSearchOutput(part.tool_call.output);
609
+ for (const name of extracted) discoveredTools.add(name);
610
+ }
611
+ if (discoveredTools.has(toolName)) {
612
+ filteredContent.push(part);
613
+ if (toolName === "skill" && skills?.size != null && skills.size > 0) {
614
+ const skillName = extractSkillName(part.tool_call.args) ?? "";
615
+ if (skillName) (pendingSkillNames ??= /* @__PURE__ */ new Set()).add(skillName);
616
+ }
617
+ } else {
618
+ /** Invalid tool - convert to string for context preservation */
619
+ if (typeof part.tool_call.id === "string" && part.tool_call.id !== "") invalidToolCallIds.add(part.tool_call.id);
620
+ const output = part.tool_call.output ?? "";
621
+ invalidToolStrings.push(`Tool: ${toolName}, ${output}`);
622
+ }
623
+ }
624
+ /** Remove tool_call_ids references to invalid tools from text parts */
625
+ if (invalidToolCallIds.size > 0) {
626
+ for (const part of filteredContent) if (part.type === "text" && Array.isArray(part.tool_call_ids)) {
627
+ part.tool_call_ids = part.tool_call_ids.filter((id) => !invalidToolCallIds.has(id));
628
+ if (part.tool_call_ids.length === 0) delete part.tool_call_ids;
629
+ }
630
+ }
631
+ /** Append invalid tool strings to the content for context preservation */
632
+ if (invalidToolStrings.length > 0) {
633
+ /** Find the last text part or create one */
634
+ let lastTextPartIndex = -1;
635
+ for (let j = filteredContent.length - 1; j >= 0; j--) if (filteredContent[j].type === "text") {
636
+ lastTextPartIndex = j;
637
+ break;
638
+ }
639
+ const invalidToolText = invalidToolStrings.join("\n");
640
+ if (lastTextPartIndex >= 0) {
641
+ const lastTextPart = filteredContent[lastTextPartIndex];
642
+ const existingText = lastTextPart["text"] ?? lastTextPart.text ?? "";
643
+ filteredContent[lastTextPartIndex] = {
644
+ ...lastTextPart,
645
+ ["text"]: existingText ? `${existingText}\n${invalidToolText}` : invalidToolText
646
+ };
647
+ } else
648
+ /** No text part exists, create one */
649
+ filteredContent.push({
650
+ type: "text",
651
+ ["text"]: invalidToolText
652
+ });
653
+ }
654
+ /** Use filtered content if we made any changes */
655
+ if (filteredContent.length !== content.length || invalidToolStrings.length > 0) processedMessage = {
656
+ ...message,
657
+ content: filteredContent
658
+ };
659
+ }
660
+ }
661
+ /** When tools filtering is off, still detect skill tool_calls for body reconstruction */
662
+ if (!discoveredTools && skills?.size != null && skills.size > 0) {
663
+ const content = processedMessage.content;
664
+ if (Array.isArray(content)) for (const part of content) {
665
+ if (part.type !== "tool_call" || part.tool_call?.name !== "skill") continue;
666
+ const skillName = extractSkillName(part.tool_call.args) ?? "";
667
+ if (skillName) (pendingSkillNames ??= /* @__PURE__ */ new Set()).add(skillName);
668
+ }
669
+ }
670
+ const formattedMessages = formatAssistantMessage(processedMessage, {
671
+ preserveUnpairedServerToolUses: i === payload.length - 1,
672
+ preserveReasoningContent: options?.provider === "deepseek",
673
+ provider: options?.provider
674
+ });
675
+ if (sourceMessageId != null && sourceMessageId !== "") for (const formattedMessage of formattedMessages) formattedMessage.id = sourceMessageId;
676
+ messages.push(...formattedMessages);
677
+ const endMessageIndex = messages.length;
678
+ if (pendingSkillNames?.size != null && pendingSkillNames.size > 0) {
679
+ const skipSkillBodyNames = options?.skipSkillBodyNames;
680
+ for (const skillName of pendingSkillNames) {
681
+ if (skipSkillBodyNames != null && skipSkillBodyNames.has(skillName)) continue;
682
+ const body = skills?.get(skillName) ?? "";
683
+ if (body) messages.push(withMessageRole(new HumanMessage({
684
+ content: body,
685
+ additional_kwargs: {
686
+ role: "user",
687
+ isMeta: true,
688
+ source: "skill",
689
+ skillName
690
+ }
691
+ }), "user"));
692
+ }
693
+ }
694
+ const resultIndices = [];
695
+ for (let j = startMessageIndex; j < endMessageIndex; j++) resultIndices.push(j);
696
+ indexMapping[i] = resultIndices;
697
+ }
698
+ if (indexTokenCountMap) for (let originalIndex = 0; originalIndex < payload.length; originalIndex++) {
699
+ const resultIndices = indexMapping[originalIndex] || [];
700
+ let tokenCount = indexTokenCountMap[originalIndex];
701
+ if (tokenCount === void 0) continue;
702
+ if (summaryBoundary && originalIndex === summaryBoundary.messageIndex && Array.isArray(payload[originalIndex].content)) {
703
+ const content = payload[originalIndex].content;
704
+ const { contentIndex } = summaryBoundary;
705
+ if (contentIndex >= 0 && contentIndex < content.length - 1) {
706
+ let totalCharLen = 0;
707
+ let remainingCharLen = 0;
708
+ for (let p = 0; p < content.length; p++) {
709
+ const charLen = contentPartCharLength(content[p]);
710
+ totalCharLen += charLen;
711
+ if (p > contentIndex) remainingCharLen += charLen;
712
+ }
713
+ if (totalCharLen > 0) {
714
+ const original = tokenCount;
715
+ tokenCount = Math.max(1, Math.round(tokenCount * (remainingCharLen / totalCharLen)));
716
+ boundaryTokenAdjustment = {
717
+ original,
718
+ adjusted: tokenCount,
719
+ remainingChars: remainingCharLen,
720
+ totalChars: totalCharLen
721
+ };
722
+ }
723
+ }
724
+ }
725
+ const msgCount = resultIndices.length;
726
+ if (msgCount === 1) {
727
+ updatedIndexTokenCountMap[resultIndices[0]] = tokenCount;
728
+ continue;
729
+ }
730
+ if (msgCount < 2) continue;
731
+ let totalLength = 0;
732
+ const lastIdx = msgCount - 1;
733
+ const lengths = new Array(msgCount);
734
+ for (let k = 0; k < msgCount; k++) {
735
+ const msg = messages[resultIndices[k]];
736
+ const { content } = msg;
737
+ let len = 0;
738
+ if (typeof content === "string") len = content.length;
739
+ else if (Array.isArray(content)) {
740
+ for (const part of content) if (typeof part === "string") len += part.length;
741
+ else if (part != null && typeof part === "object") {
742
+ const val = part.text ?? part.content;
743
+ if (typeof val === "string") len += val.length;
744
+ }
745
+ }
746
+ const toolCalls = msg.tool_calls;
747
+ if (Array.isArray(toolCalls)) for (const tc of toolCalls) {
748
+ if (typeof tc.name === "string") len += tc.name.length;
749
+ const { args } = tc;
750
+ if (typeof args === "string") len += args.length;
751
+ else if (args != null) len += JSON.stringify(args).length;
752
+ }
753
+ lengths[k] = len;
754
+ totalLength += len;
755
+ }
756
+ if (totalLength === 0) {
757
+ const countPerMessage = Math.floor(tokenCount / msgCount);
758
+ for (let k = 0; k < lastIdx; k++) updatedIndexTokenCountMap[resultIndices[k]] = countPerMessage;
759
+ updatedIndexTokenCountMap[resultIndices[lastIdx]] = tokenCount - countPerMessage * lastIdx;
760
+ } else {
761
+ let distributed = 0;
762
+ for (let k = 0; k < lastIdx; k++) {
763
+ const share = Math.floor(lengths[k] / totalLength * tokenCount);
764
+ updatedIndexTokenCountMap[resultIndices[k]] = share;
765
+ distributed += share;
766
+ }
767
+ updatedIndexTokenCountMap[resultIndices[lastIdx]] = tokenCount - distributed;
768
+ }
769
+ }
770
+ return {
771
+ messages,
772
+ indexTokenCountMap: indexTokenCountMap ? updatedIndexTokenCountMap : void 0,
773
+ summary: summaryBoundary ? {
774
+ text: summaryBoundary.text,
775
+ tokenCount: summaryBoundary.tokenCount
776
+ } : void 0,
777
+ boundaryTokenAdjustment
778
+ };
1167
779
  };
1168
780
  /**
1169
- * Adds a value at key 0 for system messages and shifts all key indices by one in an indexTokenCountMap.
1170
- * This is useful when adding a system message at the beginning of a conversation.
1171
- *
1172
- * @param indexTokenCountMap - The original map of message indices to token counts
1173
- * @param instructionsTokenCount - The token count for the system message to add at index 0
1174
- * @returns A new map with the system message at index 0 and all other indices shifted by 1
1175
- */
781
+ * Adds a value at key 0 for system messages and shifts all key indices by one in an indexTokenCountMap.
782
+ * This is useful when adding a system message at the beginning of a conversation.
783
+ *
784
+ * @param indexTokenCountMap - The original map of message indices to token counts
785
+ * @param instructionsTokenCount - The token count for the system message to add at index 0
786
+ * @returns A new map with the system message at index 0 and all other indices shifted by 1
787
+ */
1176
788
  function shiftIndexTokenCountMap(indexTokenCountMap, instructionsTokenCount) {
1177
- // Create a new map to avoid modifying the original
1178
- const shiftedMap = {};
1179
- shiftedMap[0] = instructionsTokenCount;
1180
- // Shift all existing indices by 1
1181
- for (const [indexStr, tokenCount] of Object.entries(indexTokenCountMap)) {
1182
- const index = Number(indexStr);
1183
- shiftedMap[index + 1] = tokenCount;
1184
- }
1185
- return shiftedMap;
789
+ const shiftedMap = {};
790
+ shiftedMap[0] = instructionsTokenCount;
791
+ for (const [indexStr, tokenCount] of Object.entries(indexTokenCountMap)) {
792
+ const index = Number(indexStr);
793
+ shiftedMap[index + 1] = tokenCount;
794
+ }
795
+ return shiftedMap;
1186
796
  }
1187
797
  /** Block types that contain binary image data and must be preserved structurally. */
1188
- const IMAGE_BLOCK_TYPES = new Set(['image_url', 'image']);
798
+ const IMAGE_BLOCK_TYPES = new Set(["image_url", "image"]);
1189
799
  /** Checks whether a BaseMessage is a tool-role message. */
1190
- const isToolMessage = (m) => m instanceof ToolMessage || ('role' in m && m.role === 'tool');
800
+ const isToolMessage$1 = (m) => m instanceof ToolMessage || "role" in m && m.role === "tool";
1191
801
  /** Flushes accumulated text chunks into `parts` as a single text block. */
1192
802
  function flushTextChunks(textChunks, parts) {
1193
- if (textChunks.length === 0) {
1194
- return;
1195
- }
1196
- parts.push({
1197
- type: ContentTypes.TEXT,
1198
- text: textChunks.join('\n'),
1199
- });
1200
- textChunks.length = 0;
803
+ if (textChunks.length === 0) return;
804
+ parts.push({
805
+ type: "text",
806
+ text: textChunks.join("\n")
807
+ });
808
+ textChunks.length = 0;
1201
809
  }
1202
810
  /**
1203
- * Appends a single message's content to the running `textChunks` / `parts`
1204
- * accumulators. Image blocks are shallow-copied into `parts` as-is so that
1205
- * binary data (base64 images) never becomes text tokens. All other block
1206
- * types are serialized to text — unrecognized types are JSON-serialized
1207
- * rather than silently dropped.
1208
- *
1209
- * When `content` is an array containing tool_use blocks, `tool_calls` is NOT
1210
- * additionally serialized (avoiding double output). `tool_calls` is used as
1211
- * a fallback when `content` is a plain string or an array with no tool_use.
1212
- */
811
+ * Appends a single message's content to the running `textChunks` / `parts`
812
+ * accumulators. Image blocks are shallow-copied into `parts` as-is so that
813
+ * binary data (base64 images) never becomes text tokens. All other block
814
+ * types are serialized to text — unrecognized types are JSON-serialized
815
+ * rather than silently dropped.
816
+ *
817
+ * When `content` is an array containing tool_use blocks, `tool_calls` is NOT
818
+ * additionally serialized (avoiding double output). `tool_calls` is used as
819
+ * a fallback when `content` is a plain string or an array with no tool_use.
820
+ */
1213
821
  function appendMessageContent(msg, role, textChunks, parts) {
1214
- const { content } = msg;
1215
- if (typeof content === 'string') {
1216
- if (content) {
1217
- textChunks.push(`${role}: ${content}`);
1218
- }
1219
- appendToolCalls(msg, role, textChunks);
1220
- return;
1221
- }
1222
- if (!Array.isArray(content)) {
1223
- appendToolCalls(msg, role, textChunks);
1224
- return;
1225
- }
1226
- let hasToolUseBlock = false;
1227
- for (const block of content) {
1228
- if (IMAGE_BLOCK_TYPES.has(block.type ?? '')) {
1229
- flushTextChunks(textChunks, parts);
1230
- parts.push({ ...block });
1231
- continue;
1232
- }
1233
- if (block.type === 'tool_use') {
1234
- hasToolUseBlock = true;
1235
- textChunks.push(`${role}: [tool_use] ${String(block.name ?? '')} ${JSON.stringify(block.input ?? {})}`);
1236
- continue;
1237
- }
1238
- const text = block.text ?? block.input;
1239
- if (typeof text === 'string' && text) {
1240
- textChunks.push(`${role}: ${text}`);
1241
- continue;
1242
- }
1243
- // Fallback: serialize unrecognized block types to preserve context
1244
- if (block.type != null && block.type !== '') {
1245
- textChunks.push(`${role}: [${block.type}] ${JSON.stringify(block)}`);
1246
- }
1247
- }
1248
- // If content array had no tool_use blocks, fall back to tool_calls metadata
1249
- // (handles edge case: empty content array with tool_calls populated)
1250
- if (!hasToolUseBlock) {
1251
- appendToolCalls(msg, role, textChunks);
1252
- }
822
+ const { content } = msg;
823
+ if (typeof content === "string") {
824
+ if (content) textChunks.push(`${role}: ${content}`);
825
+ appendToolCalls(msg, role, textChunks);
826
+ return;
827
+ }
828
+ if (!Array.isArray(content)) {
829
+ appendToolCalls(msg, role, textChunks);
830
+ return;
831
+ }
832
+ let hasToolUseBlock = false;
833
+ for (const block of content) {
834
+ if (IMAGE_BLOCK_TYPES.has(block.type ?? "")) {
835
+ flushTextChunks(textChunks, parts);
836
+ parts.push({ ...block });
837
+ continue;
838
+ }
839
+ if (block.type === "tool_use") {
840
+ hasToolUseBlock = true;
841
+ textChunks.push(`${role}: [tool_use] ${String(block.name ?? "")} ${JSON.stringify(block.input ?? {})}`);
842
+ continue;
843
+ }
844
+ const text = block.text ?? block.input;
845
+ if (typeof text === "string" && text) {
846
+ textChunks.push(`${role}: ${text}`);
847
+ continue;
848
+ }
849
+ if (block.type != null && block.type !== "") textChunks.push(`${role}: [${block.type}] ${JSON.stringify(block)}`);
850
+ }
851
+ if (!hasToolUseBlock) appendToolCalls(msg, role, textChunks);
1253
852
  }
1254
853
  function appendToolCalls(msg, role, textChunks) {
1255
- if (role !== 'AI') {
1256
- return;
1257
- }
1258
- const aiMsg = msg;
1259
- if (!aiMsg.tool_calls || aiMsg.tool_calls.length === 0) {
1260
- return;
1261
- }
1262
- for (const tc of aiMsg.tool_calls) {
1263
- textChunks.push(`AI: [tool_call] ${tc.name}(${JSON.stringify(tc.args)})`);
1264
- }
854
+ if (role !== "AI") return;
855
+ const aiMsg = msg;
856
+ if (!aiMsg.tool_calls || aiMsg.tool_calls.length === 0) return;
857
+ for (const tc of aiMsg.tool_calls) textChunks.push(`AI: [tool_call] ${tc.name}(${JSON.stringify(tc.args)})`);
1265
858
  }
1266
859
  /**
1267
- * Ensures compatibility when switching from a non-thinking agent to a thinking-enabled agent.
1268
- * Converts AI messages with tool calls (that lack thinking/reasoning blocks) into buffer strings,
1269
- * avoiding the thinking block signature requirement.
1270
- *
1271
- * Recognizes the following as valid thinking/reasoning blocks:
1272
- * - ContentTypes.THINKING (Anthropic)
1273
- * - ContentTypes.REASONING_CONTENT (Bedrock)
1274
- * - ContentTypes.REASONING (VertexAI / Google)
1275
- * - 'redacted_thinking'
1276
- *
1277
- * @param messages - Array of messages to process
1278
- * @param provider - The provider being used (unused but kept for future compatibility)
1279
- * @param config - Optional RunnableConfig for structured agent logging
1280
- * @param runStartIndex - Index in `messages` where the CURRENT run's own
1281
- * appended AI/Tool messages begin (i.e. anything at this index or later
1282
- * was just produced by this run's own iterations, not historical
1283
- * context). When provided, AI messages at or after this index are
1284
- * never converted to `[Previous agent context]` placeholders — Claude
1285
- * can validly skip a thinking block before a tool_use (cf. PR #116),
1286
- * so the agent's own in-run iterations must not be misclassified as
1287
- * foreign history. Without the signal the function falls back to its
1288
- * prior heuristic (`chainHasThinkingBlock`), preserving backward
1289
- * compatibility for callers that don't yet pass the boundary.
1290
- * @returns The messages array with tool sequences converted to buffer strings if necessary
1291
- */
860
+ * Ensures compatibility when switching from a non-thinking agent to a thinking-enabled agent.
861
+ * Converts AI messages with tool calls (that lack thinking/reasoning blocks) into buffer strings,
862
+ * avoiding the thinking block signature requirement.
863
+ *
864
+ * Recognizes the following as valid thinking/reasoning blocks:
865
+ * - ContentTypes.THINKING (Anthropic)
866
+ * - ContentTypes.REASONING_CONTENT (Bedrock)
867
+ * - ContentTypes.REASONING (VertexAI / Google)
868
+ * - 'redacted_thinking'
869
+ *
870
+ * @param messages - Array of messages to process
871
+ * @param provider - The provider being used (unused but kept for future compatibility)
872
+ * @param config - Optional RunnableConfig for structured agent logging
873
+ * @param runStartIndex - Index in `messages` where the CURRENT run's own
874
+ * appended AI/Tool messages begin (i.e. anything at this index or later
875
+ * was just produced by this run's own iterations, not historical
876
+ * context). When provided, AI messages at or after this index are
877
+ * never converted to `[Previous agent context]` placeholders — Claude
878
+ * can validly skip a thinking block before a tool_use (cf. PR #116),
879
+ * so the agent's own in-run iterations must not be misclassified as
880
+ * foreign history. Without the signal the function falls back to its
881
+ * prior heuristic (`chainHasThinkingBlock`), preserving backward
882
+ * compatibility for callers that don't yet pass the boundary.
883
+ * @returns The messages array with tool sequences converted to buffer strings if necessary
884
+ */
1292
885
  function ensureThinkingBlockInMessages(messages, _provider, config, runStartIndex) {
1293
- if (messages.length === 0) {
1294
- return messages;
1295
- }
1296
- // Find the last HumanMessage. Only the trailing sequence after it needs
1297
- // validation earlier messages are history already accepted by the provider.
1298
- let lastHumanIndex = -1;
1299
- for (let k = messages.length - 1; k >= 0; k--) {
1300
- const m = messages[k];
1301
- if (m instanceof HumanMessage ||
1302
- ('role' in m && m.role === 'user')) {
1303
- lastHumanIndex = k;
1304
- break;
1305
- }
1306
- }
1307
- if (lastHumanIndex === messages.length - 1) {
1308
- return messages;
1309
- }
1310
- const result = lastHumanIndex >= 0 ? messages.slice(0, lastHumanIndex + 1) : [];
1311
- let i = lastHumanIndex + 1;
1312
- while (i < messages.length) {
1313
- const msg = messages[i];
1314
- /** Detect AI messages by instanceof OR by role, in case cache-control cloning
1315
- produced a plain object that lost the LangChain prototype. */
1316
- const isAI = msg instanceof AIMessage ||
1317
- msg instanceof AIMessageChunk ||
1318
- ('role' in msg && msg.role === 'assistant');
1319
- if (!isAI) {
1320
- result.push(msg);
1321
- i++;
1322
- continue;
1323
- }
1324
- const aiMsg = msg;
1325
- const hasToolCalls = aiMsg.tool_calls && aiMsg.tool_calls.length > 0;
1326
- const contentIsArray = Array.isArray(aiMsg.content);
1327
- // Check if the message has tool calls or tool_use content
1328
- let hasToolUse = hasToolCalls ?? false;
1329
- let hasThinkingBlock = false;
1330
- if (contentIsArray && aiMsg.content.length > 0) {
1331
- for (const c of aiMsg.content) {
1332
- if (typeof c !== 'object') {
1333
- continue;
1334
- }
1335
- if (c.type === 'tool_use') {
1336
- hasToolUse = true;
1337
- }
1338
- else if (c.type === ContentTypes.THINKING ||
1339
- c.type === ContentTypes.REASONING_CONTENT ||
1340
- c.type === ContentTypes.REASONING ||
1341
- c.type === 'redacted_thinking') {
1342
- hasThinkingBlock = true;
1343
- }
1344
- if (hasToolUse && hasThinkingBlock) {
1345
- break;
1346
- }
1347
- }
1348
- }
1349
- // Bedrock also stores reasoning in additional_kwargs (may not be in content array)
1350
- if (!hasThinkingBlock &&
1351
- aiMsg.additional_kwargs.reasoning_content != null) {
1352
- hasThinkingBlock = true;
1353
- }
1354
- // If message has tool use but no thinking block, check whether this is a
1355
- // continuation of a thinking-enabled agent's chain before converting.
1356
- // Bedrock reasoning models can produce multiple AI→Tool rounds after an
1357
- // initial reasoning response: the first AI message has reasoning_content,
1358
- // but follow-ups have content: "" with only tool_calls. These are the
1359
- // same agent's turn and must NOT be converted to HumanMessages.
1360
- if (hasToolUse && !hasThinkingBlock) {
1361
- // Current-run boundary check: anything at or after `runStartIndex`
1362
- // is the current run's own work — preserve it. Claude is allowed
1363
- // to skip a thinking block before a tool_use (cf. PR #116 in the
1364
- // agents repo), so the agent's own first-iteration AI message can
1365
- // legitimately have tool_calls without reasoning. Converting it to
1366
- // a `[Previous agent context]` placeholder pollutes the next
1367
- // iteration's prompt — the LLM sees the placeholder, treats it as
1368
- // suspicious injected content, ignores its own real prior tool
1369
- // result, and re-runs the tool to verify (which then often fails
1370
- // because subsequent calls land in fresh sandboxes without the
1371
- // file). Skip the conversion when we know this is in-run.
1372
- if (runStartIndex !== undefined && i >= runStartIndex) {
1373
- result.push(msg);
1374
- i++;
1375
- continue;
1376
- }
1377
- // Walk backwards — if an earlier AI message in the same chain (before
1378
- // the nearest HumanMessage) has a thinking/reasoning block, this is a
1379
- // continuation of a thinking-enabled turn, not a non-thinking handoff.
1380
- if (chainHasThinkingBlock(messages, i)) {
1381
- result.push(msg);
1382
- i++;
1383
- continue;
1384
- }
1385
- // Build structured content in a single pass over the AI + following
1386
- // ToolMessages — preserves image blocks as-is to avoid serializing
1387
- // binary data as text (which caused 174× token amplification).
1388
- const parts = [];
1389
- const textChunks = ['[Previous agent context]'];
1390
- appendMessageContent(msg, 'AI', textChunks, parts);
1391
- let j = i + 1;
1392
- while (j < messages.length && isToolMessage(messages[j])) {
1393
- appendMessageContent(messages[j], 'Tool', textChunks, parts);
1394
- j++;
1395
- }
1396
- flushTextChunks(textChunks, parts);
1397
- emitAgentLog(config, 'warn', 'format', 'ensureThinkingBlockInMessages: injecting [Previous agent context] HumanMessage' +
1398
- ` (${parts.length} msgs at index ${i}, no thinking block in chain)`);
1399
- result.push(withMessageRole(new HumanMessage({ content: toLangChainContent(parts) }), 'user'));
1400
- i = j;
1401
- }
1402
- else {
1403
- // Keep the message as is
1404
- result.push(msg);
1405
- i++;
1406
- }
1407
- }
1408
- return result;
886
+ if (messages.length === 0) return messages;
887
+ let lastHumanIndex = -1;
888
+ for (let k = messages.length - 1; k >= 0; k--) {
889
+ const m = messages[k];
890
+ if (m instanceof HumanMessage || "role" in m && m.role === "user") {
891
+ lastHumanIndex = k;
892
+ break;
893
+ }
894
+ }
895
+ if (lastHumanIndex === messages.length - 1) return messages;
896
+ const result = lastHumanIndex >= 0 ? messages.slice(0, lastHumanIndex + 1) : [];
897
+ let i = lastHumanIndex + 1;
898
+ while (i < messages.length) {
899
+ const msg = messages[i];
900
+ if (!(msg instanceof AIMessage || msg instanceof AIMessageChunk || "role" in msg && msg.role === "assistant")) {
901
+ result.push(msg);
902
+ i++;
903
+ continue;
904
+ }
905
+ const aiMsg = msg;
906
+ const hasToolCalls = aiMsg.tool_calls && aiMsg.tool_calls.length > 0;
907
+ const contentIsArray = Array.isArray(aiMsg.content);
908
+ let hasToolUse = hasToolCalls ?? false;
909
+ let hasThinkingBlock = false;
910
+ if (contentIsArray && aiMsg.content.length > 0) for (const c of aiMsg.content) {
911
+ if (typeof c !== "object") continue;
912
+ if (c.type === "tool_use") hasToolUse = true;
913
+ else if (c.type === "thinking" || c.type === "reasoning_content" || c.type === "reasoning" || c.type === "redacted_thinking") hasThinkingBlock = true;
914
+ if (hasToolUse && hasThinkingBlock) break;
915
+ }
916
+ if (!hasThinkingBlock && aiMsg.additional_kwargs.reasoning_content != null) hasThinkingBlock = true;
917
+ if (hasToolUse && !hasThinkingBlock) {
918
+ if (runStartIndex !== void 0 && i >= runStartIndex) {
919
+ result.push(msg);
920
+ i++;
921
+ continue;
922
+ }
923
+ if (chainHasThinkingBlock(messages, i)) {
924
+ result.push(msg);
925
+ i++;
926
+ continue;
927
+ }
928
+ const parts = [];
929
+ const textChunks = ["[Previous agent context]"];
930
+ appendMessageContent(msg, "AI", textChunks, parts);
931
+ let j = i + 1;
932
+ while (j < messages.length && isToolMessage$1(messages[j])) {
933
+ appendMessageContent(messages[j], "Tool", textChunks, parts);
934
+ j++;
935
+ }
936
+ flushTextChunks(textChunks, parts);
937
+ emitAgentLog(config, "warn", "format", `ensureThinkingBlockInMessages: injecting [Previous agent context] HumanMessage (${parts.length} msgs at index ${i}, no thinking block in chain)`);
938
+ result.push(withMessageRole(new HumanMessage({ content: toLangChainContent(parts) }), "user"));
939
+ i = j;
940
+ } else {
941
+ result.push(msg);
942
+ i++;
943
+ }
944
+ }
945
+ return result;
1409
946
  }
1410
947
  /**
1411
- * Walks backwards from `currentIndex` through the message array to check
1412
- * whether an earlier AI message in the same "chain" (no HumanMessage boundary)
1413
- * contains a thinking/reasoning block.
1414
- *
1415
- * A "chain" is a contiguous sequence of AI + Tool messages with no intervening
1416
- * HumanMessage. Bedrock reasoning models produce reasoning on the first AI
1417
- * response, then issue follow-up tool calls with `content: ""` and no
1418
- * reasoning block. These follow-ups are part of the same thinking-enabled
1419
- * turn and should not be converted.
1420
- */
948
+ * Walks backwards from `currentIndex` through the message array to check
949
+ * whether an earlier AI message in the same "chain" (no HumanMessage boundary)
950
+ * contains a thinking/reasoning block.
951
+ *
952
+ * A "chain" is a contiguous sequence of AI + Tool messages with no intervening
953
+ * HumanMessage. Bedrock reasoning models produce reasoning on the first AI
954
+ * response, then issue follow-up tool calls with `content: ""` and no
955
+ * reasoning block. These follow-ups are part of the same thinking-enabled
956
+ * turn and should not be converted.
957
+ */
1421
958
  function chainHasThinkingBlock(messages, currentIndex) {
1422
- for (let k = currentIndex - 1; k >= 0; k--) {
1423
- const prev = messages[k];
1424
- // HumanMessage = turn boundary stop searching
1425
- if (prev instanceof HumanMessage ||
1426
- ('role' in prev && prev.role === 'user')) {
1427
- return false;
1428
- }
1429
- // Check AI messages for thinking/reasoning blocks
1430
- const isPrevAI = prev instanceof AIMessage ||
1431
- prev instanceof AIMessageChunk ||
1432
- ('role' in prev && prev.role === 'assistant');
1433
- if (isPrevAI) {
1434
- const prevAiMsg = prev;
1435
- if (Array.isArray(prevAiMsg.content) && prevAiMsg.content.length > 0) {
1436
- const content = prevAiMsg.content;
1437
- if (content.some((c) => typeof c === 'object' &&
1438
- (c.type === ContentTypes.THINKING ||
1439
- c.type === ContentTypes.REASONING_CONTENT ||
1440
- c.type === ContentTypes.REASONING ||
1441
- c.type === 'redacted_thinking'))) {
1442
- return true;
1443
- }
1444
- }
1445
- // Bedrock also stores reasoning in additional_kwargs
1446
- if (prevAiMsg.additional_kwargs.reasoning_content != null) {
1447
- return true;
1448
- }
1449
- }
1450
- // ToolMessages are part of the chain — keep walking back
1451
- }
1452
- return false;
959
+ for (let k = currentIndex - 1; k >= 0; k--) {
960
+ const prev = messages[k];
961
+ if (prev instanceof HumanMessage || "role" in prev && prev.role === "user") return false;
962
+ if (prev instanceof AIMessage || prev instanceof AIMessageChunk || "role" in prev && prev.role === "assistant") {
963
+ const prevAiMsg = prev;
964
+ if (Array.isArray(prevAiMsg.content) && prevAiMsg.content.length > 0) {
965
+ if (prevAiMsg.content.some((c) => typeof c === "object" && (c.type === "thinking" || c.type === "reasoning_content" || c.type === "reasoning" || c.type === "redacted_thinking"))) return true;
966
+ }
967
+ if (prevAiMsg.additional_kwargs.reasoning_content != null) return true;
968
+ }
969
+ }
970
+ return false;
1453
971
  }
1454
-
972
+ //#endregion
1455
973
  export { ensureThinkingBlockInMessages, formatAgentMessages, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, labelContentByAgent, shiftIndexTokenCountMap, withMessageRole };
1456
- //# sourceMappingURL=format.mjs.map
974
+
975
+ //# sourceMappingURL=format.mjs.map