@librechat/agents 3.2.21 → 3.2.31

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 (398) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +3 -2
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/events.cjs.map +1 -1
  4. package/dist/cjs/graphs/Graph.cjs +200 -54
  5. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +13 -7
  8. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -1
  9. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  10. package/dist/cjs/hooks/types.cjs.map +1 -1
  11. package/dist/cjs/instrumentation.cjs +2 -2
  12. package/dist/cjs/instrumentation.cjs.map +1 -1
  13. package/dist/cjs/langfuse.cjs +17 -1
  14. package/dist/cjs/langfuse.cjs.map +1 -1
  15. package/dist/cjs/langfuseToolOutputTracing.cjs +2 -2
  16. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  17. package/dist/cjs/llm/anthropic/index.cjs +1 -1
  18. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  19. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  20. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +1 -1
  21. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  22. package/dist/cjs/llm/bedrock/index.cjs +2 -2
  23. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  24. package/dist/cjs/llm/bedrock/toolCache.cjs +8 -5
  25. package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
  26. package/dist/cjs/llm/fake.cjs +16 -14
  27. package/dist/cjs/llm/fake.cjs.map +1 -1
  28. package/dist/cjs/llm/google/index.cjs +22 -0
  29. package/dist/cjs/llm/google/index.cjs.map +1 -1
  30. package/dist/cjs/llm/google/utils/common.cjs +88 -27
  31. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  32. package/dist/cjs/llm/init.cjs +2 -2
  33. package/dist/cjs/llm/invoke.cjs +108 -11
  34. package/dist/cjs/llm/invoke.cjs.map +1 -1
  35. package/dist/cjs/llm/openai/index.cjs +1 -1
  36. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  37. package/dist/cjs/llm/openai/utils/index.cjs +1 -1
  38. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  39. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  40. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  41. package/dist/cjs/main.cjs +1 -0
  42. package/dist/cjs/main.cjs.map +1 -1
  43. package/dist/cjs/messages/cache.cjs +8 -7
  44. package/dist/cjs/messages/cache.cjs.map +1 -1
  45. package/dist/cjs/messages/content.cjs.map +1 -1
  46. package/dist/cjs/messages/contextPruning.cjs.map +1 -1
  47. package/dist/cjs/messages/format.cjs +124 -17
  48. package/dist/cjs/messages/format.cjs.map +1 -1
  49. package/dist/cjs/messages/prune.cjs.map +1 -1
  50. package/dist/cjs/messages/reducer.cjs +1 -1
  51. package/dist/cjs/messages/reducer.cjs.map +1 -1
  52. package/dist/cjs/messages/tools.cjs +1 -1
  53. package/dist/cjs/messages/tools.cjs.map +1 -1
  54. package/dist/cjs/openai/index.cjs.map +1 -1
  55. package/dist/cjs/responses/index.cjs.map +1 -1
  56. package/dist/cjs/run.cjs +41 -20
  57. package/dist/cjs/run.cjs.map +1 -1
  58. package/dist/cjs/session/AgentSession.cjs +4 -4
  59. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  60. package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
  61. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  62. package/dist/cjs/session/handlers.cjs +2 -2
  63. package/dist/cjs/session/handlers.cjs.map +1 -1
  64. package/dist/cjs/stream.cjs +248 -25
  65. package/dist/cjs/stream.cjs.map +1 -1
  66. package/dist/cjs/summarization/node.cjs.map +1 -1
  67. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +1 -1
  68. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  69. package/dist/cjs/tools/Calculator.cjs +1 -1
  70. package/dist/cjs/tools/Calculator.cjs.map +1 -1
  71. package/dist/cjs/tools/CodeExecutor.cjs +1 -1
  72. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  73. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  74. package/dist/cjs/tools/ToolNode.cjs +37 -18
  75. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  76. package/dist/cjs/tools/ToolSearch.cjs +1 -1
  77. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  78. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +7 -4
  79. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
  80. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +4 -4
  81. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -1
  82. package/dist/cjs/tools/handlers.cjs +2 -1
  83. package/dist/cjs/tools/handlers.cjs.map +1 -1
  84. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
  85. package/dist/cjs/tools/local/FileCheckpointer.cjs +2 -1
  86. package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -1
  87. package/dist/cjs/tools/local/LocalCodingTools.cjs +45 -19
  88. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
  89. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +3 -3
  90. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
  91. package/dist/cjs/tools/local/LocalExecutionTools.cjs +2 -2
  92. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
  93. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +4 -3
  94. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  95. package/dist/cjs/tools/local/attachments.cjs +0 -5
  96. package/dist/cjs/tools/local/attachments.cjs.map +1 -1
  97. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +4 -4
  98. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
  99. package/dist/cjs/tools/search/firecrawl.cjs +1 -1
  100. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  101. package/dist/cjs/tools/search/rerankers.cjs +7 -3
  102. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  103. package/dist/cjs/tools/search/tavily-search.cjs +1 -1
  104. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
  105. package/dist/cjs/tools/search/utils.cjs +76 -8
  106. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  107. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -1
  108. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  109. package/dist/cjs/utils/handlers.cjs +1 -1
  110. package/dist/cjs/utils/handlers.cjs.map +1 -1
  111. package/dist/cjs/utils/run.cjs +1 -1
  112. package/dist/cjs/utils/run.cjs.map +1 -1
  113. package/dist/esm/agents/AgentContext.mjs +3 -2
  114. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  115. package/dist/esm/events.mjs.map +1 -1
  116. package/dist/esm/graphs/Graph.mjs +200 -54
  117. package/dist/esm/graphs/Graph.mjs.map +1 -1
  118. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  119. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +13 -7
  120. package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -1
  121. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  122. package/dist/esm/hooks/types.mjs.map +1 -1
  123. package/dist/esm/instrumentation.mjs +2 -2
  124. package/dist/esm/instrumentation.mjs.map +1 -1
  125. package/dist/esm/langfuse.mjs +17 -2
  126. package/dist/esm/langfuse.mjs.map +1 -1
  127. package/dist/esm/langfuseToolOutputTracing.mjs +2 -2
  128. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  129. package/dist/esm/llm/anthropic/index.mjs +1 -1
  130. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  131. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  132. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +1 -1
  133. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  134. package/dist/esm/llm/bedrock/index.mjs +2 -2
  135. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  136. package/dist/esm/llm/bedrock/toolCache.mjs +8 -5
  137. package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
  138. package/dist/esm/llm/fake.mjs +16 -14
  139. package/dist/esm/llm/fake.mjs.map +1 -1
  140. package/dist/esm/llm/google/index.mjs +23 -1
  141. package/dist/esm/llm/google/index.mjs.map +1 -1
  142. package/dist/esm/llm/google/utils/common.mjs +88 -27
  143. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  144. package/dist/esm/llm/init.mjs +2 -2
  145. package/dist/esm/llm/invoke.mjs +104 -7
  146. package/dist/esm/llm/invoke.mjs.map +1 -1
  147. package/dist/esm/llm/openai/index.mjs +1 -1
  148. package/dist/esm/llm/openai/index.mjs.map +1 -1
  149. package/dist/esm/llm/openai/utils/index.mjs +1 -1
  150. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  151. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  152. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  153. package/dist/esm/main.mjs +1 -1
  154. package/dist/esm/messages/cache.mjs +8 -7
  155. package/dist/esm/messages/cache.mjs.map +1 -1
  156. package/dist/esm/messages/content.mjs.map +1 -1
  157. package/dist/esm/messages/contextPruning.mjs.map +1 -1
  158. package/dist/esm/messages/format.mjs +124 -18
  159. package/dist/esm/messages/format.mjs.map +1 -1
  160. package/dist/esm/messages/prune.mjs.map +1 -1
  161. package/dist/esm/messages/reducer.mjs +1 -1
  162. package/dist/esm/messages/reducer.mjs.map +1 -1
  163. package/dist/esm/messages/tools.mjs +1 -1
  164. package/dist/esm/messages/tools.mjs.map +1 -1
  165. package/dist/esm/openai/index.mjs.map +1 -1
  166. package/dist/esm/responses/index.mjs.map +1 -1
  167. package/dist/esm/run.mjs +41 -20
  168. package/dist/esm/run.mjs.map +1 -1
  169. package/dist/esm/session/AgentSession.mjs +4 -4
  170. package/dist/esm/session/AgentSession.mjs.map +1 -1
  171. package/dist/esm/session/JsonlSessionStore.mjs +2 -2
  172. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  173. package/dist/esm/session/handlers.mjs +2 -2
  174. package/dist/esm/session/handlers.mjs.map +1 -1
  175. package/dist/esm/stream.mjs +248 -25
  176. package/dist/esm/stream.mjs.map +1 -1
  177. package/dist/esm/summarization/node.mjs.map +1 -1
  178. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +1 -1
  179. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  180. package/dist/esm/tools/Calculator.mjs +1 -1
  181. package/dist/esm/tools/Calculator.mjs.map +1 -1
  182. package/dist/esm/tools/CodeExecutor.mjs +1 -1
  183. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  184. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  185. package/dist/esm/tools/ToolNode.mjs +37 -18
  186. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  187. package/dist/esm/tools/ToolSearch.mjs +1 -1
  188. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  189. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +7 -4
  190. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
  191. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +4 -4
  192. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -1
  193. package/dist/esm/tools/handlers.mjs +2 -1
  194. package/dist/esm/tools/handlers.mjs.map +1 -1
  195. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
  196. package/dist/esm/tools/local/FileCheckpointer.mjs +2 -1
  197. package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -1
  198. package/dist/esm/tools/local/LocalCodingTools.mjs +45 -19
  199. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
  200. package/dist/esm/tools/local/LocalExecutionEngine.mjs +3 -3
  201. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
  202. package/dist/esm/tools/local/LocalExecutionTools.mjs +2 -2
  203. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
  204. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +4 -3
  205. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  206. package/dist/esm/tools/local/attachments.mjs +0 -5
  207. package/dist/esm/tools/local/attachments.mjs.map +1 -1
  208. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +4 -4
  209. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
  210. package/dist/esm/tools/search/firecrawl.mjs +1 -1
  211. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  212. package/dist/esm/tools/search/rerankers.mjs +8 -4
  213. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  214. package/dist/esm/tools/search/tavily-search.mjs +1 -1
  215. package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
  216. package/dist/esm/tools/search/utils.mjs +76 -9
  217. package/dist/esm/tools/search/utils.mjs.map +1 -1
  218. package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -1
  219. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  220. package/dist/esm/utils/handlers.mjs +1 -1
  221. package/dist/esm/utils/handlers.mjs.map +1 -1
  222. package/dist/esm/utils/run.mjs +1 -1
  223. package/dist/esm/utils/run.mjs.map +1 -1
  224. package/dist/types/agents/__tests__/promptCacheLiveHelpers.d.ts +1 -1
  225. package/dist/types/events.d.ts +1 -1
  226. package/dist/types/graphs/Graph.d.ts +7 -1
  227. package/dist/types/hooks/executeHooks.d.ts +1 -1
  228. package/dist/types/hooks/types.d.ts +5 -0
  229. package/dist/types/langfuse.d.ts +4 -0
  230. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
  231. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -1
  232. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +2 -2
  233. package/dist/types/llm/bedrock/index.d.ts +2 -2
  234. package/dist/types/llm/fake.d.ts +3 -3
  235. package/dist/types/llm/google/index.d.ts +1 -0
  236. package/dist/types/llm/google/types.d.ts +1 -1
  237. package/dist/types/llm/google/utils/common.d.ts +2 -2
  238. package/dist/types/llm/google/utils/tools.d.ts +1 -1
  239. package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +1 -1
  240. package/dist/types/llm/openai/index.d.ts +2 -2
  241. package/dist/types/llm/openai/utils/index.d.ts +1 -1
  242. package/dist/types/llm/openrouter/index.d.ts +4 -4
  243. package/dist/types/messages/contextPruning.d.ts +1 -1
  244. package/dist/types/messages/format.d.ts +9 -4
  245. package/dist/types/messages/prune.d.ts +1 -1
  246. package/dist/types/session/JsonlSessionStore.d.ts +1 -1
  247. package/dist/types/session/handlers.d.ts +1 -1
  248. package/dist/types/session/types.d.ts +1 -1
  249. package/dist/types/summarization/node.d.ts +1 -1
  250. package/dist/types/tools/SubagentTool.d.ts +2 -2
  251. package/dist/types/tools/ToolNode.d.ts +9 -2
  252. package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +1 -1
  253. package/dist/types/tools/search/types.d.ts +1 -1
  254. package/dist/types/tools/search/utils.d.ts +11 -0
  255. package/dist/types/types/graph.d.ts +4 -4
  256. package/dist/types/types/llm.d.ts +4 -3
  257. package/dist/types/types/messages.d.ts +1 -1
  258. package/dist/types/types/run.d.ts +6 -6
  259. package/dist/types/types/stream.d.ts +2 -2
  260. package/dist/types/types/tools.d.ts +5 -1
  261. package/dist/types/utils/handlers.d.ts +2 -2
  262. package/dist/types/utils/run.d.ts +1 -1
  263. package/package.json +6 -3
  264. package/src/__tests__/stream.eagerEventExecution.test.ts +543 -6
  265. package/src/agents/AgentContext.ts +2 -2
  266. package/src/agents/__tests__/AgentContext.test.ts +3 -3
  267. package/src/agents/__tests__/promptCacheLiveHelpers.ts +1 -1
  268. package/src/events.ts +1 -1
  269. package/src/graphs/Graph.ts +329 -72
  270. package/src/graphs/MultiAgentGraph.ts +1 -1
  271. package/src/graphs/__tests__/Graph.reasoning.test.ts +919 -6
  272. package/src/graphs/__tests__/MultiAgentGraph.test.ts +1 -1
  273. package/src/graphs/__tests__/composition.smoke.test.ts +1 -1
  274. package/src/hooks/__tests__/HookRegistry.test.ts +1 -1
  275. package/src/hooks/__tests__/compactHooks.test.ts +8 -8
  276. package/src/hooks/__tests__/createWorkspacePolicyHook.test.ts +34 -22
  277. package/src/hooks/__tests__/executeHooks.test.ts +3 -3
  278. package/src/hooks/__tests__/integration.test.ts +3 -3
  279. package/src/hooks/__tests__/toolHooks.test.ts +10 -10
  280. package/src/hooks/createWorkspacePolicyHook.ts +17 -14
  281. package/src/hooks/executeHooks.ts +1 -1
  282. package/src/hooks/types.ts +5 -0
  283. package/src/instrumentation.ts +11 -11
  284. package/src/langfuse.ts +35 -1
  285. package/src/langfuseToolOutputTracing.ts +2 -2
  286. package/src/llm/anthropic/index.ts +1 -1
  287. package/src/llm/anthropic/utils/message_inputs.ts +1 -1
  288. package/src/llm/anthropic/utils/message_outputs.ts +3 -5
  289. package/src/llm/anthropic/utils/output_parsers.ts +5 -5
  290. package/src/llm/bedrock/index.ts +4 -4
  291. package/src/llm/bedrock/toolCache.test.ts +48 -9
  292. package/src/llm/bedrock/toolCache.ts +11 -6
  293. package/src/llm/fake.ts +30 -25
  294. package/src/llm/google/index.ts +43 -1
  295. package/src/llm/google/llm.spec.ts +173 -1
  296. package/src/llm/google/types.ts +1 -1
  297. package/src/llm/google/utils/common.ts +154 -45
  298. package/src/llm/google/utils/tools.ts +8 -8
  299. package/src/llm/google/utils/zod_to_genai_parameters.ts +4 -4
  300. package/src/llm/invoke.test.ts +3 -3
  301. package/src/llm/invoke.ts +170 -10
  302. package/src/llm/openai/index.ts +4 -4
  303. package/src/llm/openai/utils/index.ts +14 -14
  304. package/src/llm/openrouter/index.ts +4 -4
  305. package/src/llm/openrouter/reasoning.test.ts +2 -2
  306. package/src/llm/vertexai/fixThoughtSignatures.test.ts +1 -1
  307. package/src/llm/vertexai/index.ts +1 -1
  308. package/src/messages/cache.test.ts +22 -0
  309. package/src/messages/cache.ts +25 -12
  310. package/src/messages/content.ts +1 -1
  311. package/src/messages/contextPruning.ts +1 -1
  312. package/src/messages/format.ts +227 -43
  313. package/src/messages/formatAgentMessages.skills.test.ts +105 -26
  314. package/src/messages/formatAgentMessages.test.ts +841 -10
  315. package/src/messages/labelContentByAgent.test.ts +2 -2
  316. package/src/messages/prune.ts +1 -1
  317. package/src/messages/reducer.ts +1 -1
  318. package/src/messages/tools.ts +1 -1
  319. package/src/openai/__tests__/openai.test.ts +2 -2
  320. package/src/openai/index.ts +1 -1
  321. package/src/responses/__tests__/responses.test.ts +2 -2
  322. package/src/responses/index.ts +1 -1
  323. package/src/run.ts +68 -41
  324. package/src/session/AgentSession.ts +6 -6
  325. package/src/session/JsonlSessionStore.ts +3 -3
  326. package/src/session/__tests__/JsonlSessionStore.test.ts +5 -5
  327. package/src/session/__tests__/handlers.test.ts +2 -2
  328. package/src/session/handlers.ts +5 -5
  329. package/src/session/types.ts +1 -1
  330. package/src/specs/agent-handoffs.test.ts +1 -1
  331. package/src/specs/langfuse-callbacks.test.ts +2 -2
  332. package/src/specs/langfuse-metadata.test.ts +39 -0
  333. package/src/specs/langfuse-tool-output-tracing.test.ts +1 -1
  334. package/src/specs/multi-agent-summarization.test.ts +4 -4
  335. package/src/specs/subagent.test.ts +3 -3
  336. package/src/specs/summarization-unit.test.ts +1 -1
  337. package/src/specs/thinking-handoff.test.ts +1 -1
  338. package/src/splitStream.test.ts +48 -0
  339. package/src/stream.test.ts +53 -3
  340. package/src/stream.ts +450 -39
  341. package/src/summarization/__tests__/aggregator.test.ts +2 -2
  342. package/src/summarization/__tests__/node.test.ts +2 -2
  343. package/src/summarization/node.ts +1 -1
  344. package/src/tools/BashProgrammaticToolCalling.ts +5 -5
  345. package/src/tools/Calculator.ts +1 -1
  346. package/src/tools/CodeExecutor.ts +2 -4
  347. package/src/tools/SubagentTool.ts +2 -2
  348. package/src/tools/ToolNode.ts +37 -16
  349. package/src/tools/ToolSearch.ts +1 -1
  350. package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +4 -4
  351. package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +12 -12
  352. package/src/tools/__tests__/LocalExecutionTools.test.ts +125 -93
  353. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +29 -5
  354. package/src/tools/__tests__/ReadFile.test.ts +1 -1
  355. package/src/tools/__tests__/SkillTool.test.ts +4 -4
  356. package/src/tools/__tests__/SubagentExecutor.test.ts +17 -13
  357. package/src/tools/__tests__/SubagentTool.test.ts +2 -2
  358. package/src/tools/__tests__/ToolNode.eagerEventExecution.test.ts +1 -1
  359. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +2 -5
  360. package/src/tools/__tests__/ToolNode.session.test.ts +1 -1
  361. package/src/tools/__tests__/ToolSearch.test.ts +1 -1
  362. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +1 -1
  363. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +35 -32
  364. package/src/tools/__tests__/directToolHooks.test.ts +41 -0
  365. package/src/tools/__tests__/handlers.test.ts +2 -2
  366. package/src/tools/__tests__/hitl.test.ts +11 -11
  367. package/src/tools/__tests__/localToolNames.test.ts +8 -6
  368. package/src/tools/__tests__/skillCatalog.test.ts +1 -1
  369. package/src/tools/__tests__/subagentHooks.test.ts +20 -10
  370. package/src/tools/__tests__/workspaceSeam.test.ts +20 -7
  371. package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +9 -6
  372. package/src/tools/cloudflare/CloudflareSandboxTools.ts +19 -19
  373. package/src/tools/handlers.ts +5 -5
  374. package/src/tools/local/CompileCheckTool.ts +4 -7
  375. package/src/tools/local/FileCheckpointer.ts +6 -5
  376. package/src/tools/local/LocalCodingTools.ts +100 -45
  377. package/src/tools/local/LocalExecutionEngine.ts +5 -5
  378. package/src/tools/local/LocalExecutionTools.ts +9 -9
  379. package/src/tools/local/LocalProgrammaticToolCalling.ts +5 -4
  380. package/src/tools/local/attachments.ts +0 -6
  381. package/src/tools/local/resolveLocalExecutionTools.ts +15 -15
  382. package/src/tools/search/firecrawl.ts +1 -1
  383. package/src/tools/search/jina-reranker.test.ts +148 -37
  384. package/src/tools/search/rerankers.ts +14 -4
  385. package/src/tools/search/tavily-search.ts +2 -2
  386. package/src/tools/search/types.ts +1 -1
  387. package/src/tools/search/utils.ts +99 -9
  388. package/src/tools/subagent/SubagentExecutor.ts +12 -6
  389. package/src/types/graph.ts +12 -12
  390. package/src/types/llm.ts +7 -6
  391. package/src/types/messages.ts +1 -1
  392. package/src/types/run.ts +7 -7
  393. package/src/types/stream.ts +2 -2
  394. package/src/types/tools.ts +5 -1
  395. package/src/utils/handlers.ts +2 -2
  396. package/src/utils/llmConfig.ts +1 -1
  397. package/src/utils/logging.ts +20 -10
  398. package/src/utils/run.ts +2 -2
@@ -1,5 +1,5 @@
1
- import type { AIMessageChunk } from '@langchain/core/messages';
2
1
  import type { ChatOpenAIReasoningSummary } from '@langchain/openai';
2
+ import type { AIMessageChunk } from '@langchain/core/messages';
3
3
  import { getChunkContent } from './stream';
4
4
  import { Providers } from '@/common';
5
5
 
@@ -23,9 +23,9 @@ describe('getChunkContent', () => {
23
23
  expect(result).toBe('Reasoning summary text');
24
24
  });
25
25
 
26
- it('should fallback to reasoningKey when no OpenAI reasoning summary', () => {
26
+ it('should fallback to reasoningKey when no visible content is present', () => {
27
27
  const chunk: Partial<AIMessageChunk> = {
28
- content: 'Regular content',
28
+ content: '',
29
29
  additional_kwargs: {
30
30
  reasoning_content: 'Reasoning from key',
31
31
  },
@@ -39,6 +39,56 @@ describe('getChunkContent', () => {
39
39
  expect(result).toBe('Reasoning from key');
40
40
  });
41
41
 
42
+ it('should use OpenRouter reasoning_content when no visible content is present', () => {
43
+ const chunk: Partial<AIMessageChunk> = {
44
+ content: '',
45
+ additional_kwargs: {
46
+ reasoning_content: 'OpenRouter reasoning delta',
47
+ },
48
+ };
49
+
50
+ const result = getChunkContent({
51
+ chunk,
52
+ provider: Providers.OPENROUTER,
53
+ reasoningKey: 'reasoning',
54
+ });
55
+
56
+ expect(result).toBe('OpenRouter reasoning delta');
57
+ });
58
+
59
+ it('should prefer visible content when hidden reasoning is present on the same chunk', () => {
60
+ const chunk: Partial<AIMessageChunk> = {
61
+ content: 'Regular content',
62
+ additional_kwargs: {
63
+ reasoning_content: 'Reasoning from key',
64
+ },
65
+ };
66
+
67
+ const result = getChunkContent({
68
+ chunk,
69
+ reasoningKey: 'reasoning_content',
70
+ });
71
+
72
+ expect(result).toBe('Regular content');
73
+ });
74
+
75
+ it('should prefer visible OpenRouter content over reasoning_content on the same chunk', () => {
76
+ const chunk: Partial<AIMessageChunk> = {
77
+ content: 'Regular content',
78
+ additional_kwargs: {
79
+ reasoning_content: 'OpenRouter reasoning delta',
80
+ },
81
+ };
82
+
83
+ const result = getChunkContent({
84
+ chunk,
85
+ provider: Providers.OPENROUTER,
86
+ reasoningKey: 'reasoning',
87
+ });
88
+
89
+ expect(result).toBe('Regular content');
90
+ });
91
+
42
92
  it('should fallback to chunk.content when reasoningKey value is null or undefined', () => {
43
93
  const chunk: Partial<AIMessageChunk> = {
44
94
  content: 'Fallback content',
package/src/stream.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/stream.ts
2
+ import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
2
3
  import type { ChatOpenAIReasoningSummary } from '@langchain/openai';
3
4
  import type { AIMessageChunk } from '@langchain/core/messages';
4
- import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
5
5
  import type { AgentContext } from '@/agents/AgentContext';
6
6
  import type { StandardGraph } from '@/graphs';
7
7
  import type * as t from '@/types';
@@ -16,32 +16,37 @@ import {
16
16
  LOCAL_CODING_BUNDLE_NAMES,
17
17
  } from '@/common';
18
18
  import {
19
- handleServerToolResult,
20
- handleToolCallChunks,
21
- handleToolCalls,
22
- } from '@/tools/handlers';
23
- import { getMessageId } from '@/messages';
24
- import { safeDispatchCustomEvent } from '@/utils/events';
19
+ getStreamedToolCallSeal,
20
+ getStreamedToolCallAdapter,
21
+ type StreamedToolCallSeal,
22
+ } from '@/tools/streamedToolCallSeals';
25
23
  import {
26
24
  buildToolExecutionRequestPlan,
27
25
  coerceRecordArgs,
28
26
  normalizeError,
29
27
  } from '@/tools/eagerEventExecution';
28
+ import {
29
+ handleServerToolResult,
30
+ handleToolCallChunks,
31
+ handleToolCalls,
32
+ } from '@/tools/handlers';
30
33
  import {
31
34
  calculateMaxToolResultChars,
32
35
  truncateToolResultContent,
33
36
  } from '@/utils/truncation';
34
- import {
35
- getStreamedToolCallSeal,
36
- getStreamedToolCallAdapter,
37
- type StreamedToolCallSeal,
38
- } from '@/tools/streamedToolCallSeals';
39
37
  import { TOOL_OUTPUT_REF_PATTERN } from '@/tools/toolOutputReferences';
38
+ import { safeDispatchCustomEvent } from '@/utils/events';
39
+ import { isGoogleLike } from '@/utils/llm';
40
+ import { getMessageId } from '@/messages';
40
41
 
41
42
  const LOCAL_CODING_BUNDLE_NAME_SET: ReadonlySet<string> = new Set(
42
43
  LOCAL_CODING_BUNDLE_NAMES
43
44
  );
44
45
 
46
+ type ReasoningSummaryLike = {
47
+ summary?: Array<{ text?: string }>;
48
+ };
49
+
45
50
  /**
46
51
  * Parses content to extract thinking sections enclosed in <think> tags using string operations
47
52
  * @param content The content to parse
@@ -329,6 +334,230 @@ function hasDirectToolCallChunkStateInStep(args: {
329
334
  return false;
330
335
  }
331
336
 
337
+ function isGoogleServerSideToolContentPart(
338
+ contentPart: t.MessageContentComplex
339
+ ): boolean {
340
+ return contentPart.type === 'toolCall' || contentPart.type === 'toolResponse';
341
+ }
342
+
343
+ function isTextContentPart(contentPart: t.MessageContentComplex): boolean {
344
+ return contentPart.type?.startsWith(ContentTypes.TEXT) ?? false;
345
+ }
346
+
347
+ function isReasoningContentPart(contentPart: t.MessageContentComplex): boolean {
348
+ return (
349
+ (contentPart.type?.startsWith(ContentTypes.THINKING) ?? false) ||
350
+ (contentPart.type?.startsWith(ContentTypes.REASONING) ?? false) ||
351
+ (contentPart.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false) ||
352
+ contentPart.type === 'redacted_thinking'
353
+ );
354
+ }
355
+
356
+ function getReasoningTextFromContentPart(
357
+ contentPart: t.MessageContentComplex
358
+ ): string {
359
+ return (
360
+ (contentPart as t.ThinkingContentText).thinking ??
361
+ (contentPart as Partial<t.GoogleReasoningContentText>).reasoning ??
362
+ (contentPart as Partial<t.BedrockReasoningContentText>).reasoningText
363
+ ?.text ??
364
+ ''
365
+ );
366
+ }
367
+
368
+ function getReasoningTextFromChunk(
369
+ chunk: Partial<AIMessageChunk>,
370
+ agentContext: AgentContext
371
+ ): string {
372
+ const reasoning = chunk.additional_kwargs?.[agentContext.reasoningKey] as
373
+ | string
374
+ | Partial<ChatOpenAIReasoningSummary>
375
+ | undefined;
376
+ if (typeof reasoning === 'string') {
377
+ return reasoning;
378
+ }
379
+ return reasoning?.summary?.[0]?.text ?? '';
380
+ }
381
+
382
+ const googleServerSideToolStepIdsByGraph = new WeakMap<
383
+ StandardGraph,
384
+ Set<string>
385
+ >();
386
+
387
+ function markGoogleServerSideToolMessageStep(
388
+ graph: StandardGraph,
389
+ stepId: string
390
+ ): void {
391
+ const stepIds = googleServerSideToolStepIdsByGraph.get(graph) ?? new Set();
392
+ stepIds.add(stepId);
393
+ googleServerSideToolStepIdsByGraph.set(graph, stepIds);
394
+ }
395
+
396
+ function isGoogleServerSideToolMessageStep(
397
+ graph: StandardGraph,
398
+ stepId: string
399
+ ): boolean {
400
+ return googleServerSideToolStepIdsByGraph.get(graph)?.has(stepId) === true;
401
+ }
402
+
403
+ function shouldStartFreshMessageStepAfterGoogleServerSideTool({
404
+ graph,
405
+ stepId,
406
+ runStep,
407
+ content,
408
+ }: {
409
+ graph: StandardGraph;
410
+ stepId: string;
411
+ runStep?: t.RunStep;
412
+ content: string | t.MessageContentComplex[];
413
+ }): boolean {
414
+ if (
415
+ runStep?.type !== StepTypes.MESSAGE_CREATION ||
416
+ !isGoogleServerSideToolMessageStep(graph, stepId)
417
+ ) {
418
+ return false;
419
+ }
420
+ if (typeof content === 'string') {
421
+ return true;
422
+ }
423
+ return (
424
+ content.every((c) => isTextContentPart(c)) ||
425
+ content.every((c) => isReasoningContentPart(c))
426
+ );
427
+ }
428
+
429
+ async function dispatchMessageCreationStep({
430
+ graph,
431
+ stepKey,
432
+ metadata,
433
+ }: {
434
+ graph: StandardGraph;
435
+ stepKey: string;
436
+ metadata?: Record<string, unknown>;
437
+ }): Promise<string> {
438
+ const messageId = getMessageId(stepKey, graph, true) ?? '';
439
+ return graph.dispatchRunStep(
440
+ stepKey,
441
+ {
442
+ type: StepTypes.MESSAGE_CREATION,
443
+ message_creation: {
444
+ message_id: messageId,
445
+ },
446
+ },
447
+ metadata
448
+ );
449
+ }
450
+
451
+ async function dispatchMessageContentParts({
452
+ graph,
453
+ stepKey,
454
+ content,
455
+ metadata,
456
+ }: {
457
+ graph: StandardGraph;
458
+ stepKey: string;
459
+ content: t.MessageContentComplex[];
460
+ metadata?: Record<string, unknown>;
461
+ }): Promise<void> {
462
+ for (const contentPart of content) {
463
+ const currentStepId = await dispatchMessageCreationStep({
464
+ graph,
465
+ stepKey,
466
+ metadata,
467
+ });
468
+ if (isGoogleServerSideToolContentPart(contentPart)) {
469
+ markGoogleServerSideToolMessageStep(graph, currentStepId);
470
+ }
471
+ await graph.dispatchMessageDelta(
472
+ currentStepId,
473
+ {
474
+ content: [contentPart],
475
+ },
476
+ metadata
477
+ );
478
+ }
479
+ }
480
+
481
+ async function dispatchReasoningContentParts({
482
+ graph,
483
+ stepKey,
484
+ content,
485
+ metadata,
486
+ }: {
487
+ graph: StandardGraph;
488
+ stepKey: string;
489
+ content: t.MessageContentComplex[];
490
+ metadata?: Record<string, unknown>;
491
+ }): Promise<void> {
492
+ if (content.length === 0) {
493
+ return;
494
+ }
495
+ const currentStepId = await dispatchMessageCreationStep({
496
+ graph,
497
+ stepKey,
498
+ metadata,
499
+ });
500
+ await graph.dispatchReasoningDelta(
501
+ currentStepId,
502
+ {
503
+ content,
504
+ },
505
+ metadata
506
+ );
507
+ }
508
+
509
+ async function dispatchGoogleServerSideToolStreamContent({
510
+ graph,
511
+ stepKey,
512
+ chunk,
513
+ agentContext,
514
+ content,
515
+ metadata,
516
+ }: {
517
+ graph: StandardGraph;
518
+ stepKey: string;
519
+ chunk: Partial<AIMessageChunk>;
520
+ agentContext: AgentContext;
521
+ content: t.MessageContentComplex[];
522
+ metadata?: Record<string, unknown>;
523
+ }): Promise<void> {
524
+ const reasoningContent: t.MessageContentComplex[] = [];
525
+ const reasoningText = getReasoningTextFromChunk(chunk, agentContext);
526
+ if (reasoningText !== '') {
527
+ reasoningContent.push({
528
+ type: ContentTypes.THINK,
529
+ think: reasoningText,
530
+ });
531
+ }
532
+ reasoningContent.push(
533
+ ...content
534
+ .filter((contentPart) => isReasoningContentPart(contentPart))
535
+ .map((contentPart) => ({
536
+ type: ContentTypes.THINK,
537
+ think: getReasoningTextFromContentPart(contentPart),
538
+ }))
539
+ .filter((contentPart) => contentPart.think !== '')
540
+ );
541
+ await dispatchReasoningContentParts({
542
+ graph,
543
+ stepKey,
544
+ content: reasoningContent,
545
+ metadata,
546
+ });
547
+
548
+ const messageContent = content.filter(
549
+ (contentPart) =>
550
+ isTextContentPart(contentPart) ||
551
+ isGoogleServerSideToolContentPart(contentPart)
552
+ );
553
+ await dispatchMessageContentParts({
554
+ graph,
555
+ stepKey,
556
+ content: messageContent,
557
+ metadata,
558
+ });
559
+ }
560
+
332
561
  type EagerToolExecutionEntry = {
333
562
  id: string;
334
563
  toolName: string;
@@ -890,6 +1119,14 @@ export function getChunkContent({
890
1119
  provider?: Providers;
891
1120
  reasoningKey: 'reasoning_content' | 'reasoning';
892
1121
  }): string | t.MessageContentComplex[] | undefined {
1122
+ if (
1123
+ isGoogleLike(provider) &&
1124
+ Array.isArray(chunk?.content) &&
1125
+ chunk.content.some((c) => isGoogleServerSideToolContentPart(c))
1126
+ ) {
1127
+ return chunk.content;
1128
+ }
1129
+
893
1130
  if (
894
1131
  (provider === Providers.OPENAI || provider === Providers.AZURE) &&
895
1132
  (
@@ -909,16 +1146,6 @@ export function getChunkContent({
909
1146
  | undefined
910
1147
  )?.summary?.[0]?.text;
911
1148
  }
912
- /**
913
- * For OpenRouter, reasoning is stored in additional_kwargs.reasoning (not reasoning_content).
914
- * NOTE: We intentionally do NOT extract text from reasoning_details here.
915
- * The reasoning_details array contains the FULL accumulated reasoning text (set only on final chunk),
916
- * but individual reasoning tokens are already streamed via additional_kwargs.reasoning.
917
- * Extracting from reasoning_details would cause duplication.
918
- * The reasoning_details is only used for:
919
- * 1. Detecting reasoning mode in handleReasoning()
920
- * 2. Final message storage (for thought signatures)
921
- */
922
1149
  if (provider === Providers.OPENROUTER) {
923
1150
  // Content presence signals end of reasoning phase - prefer content over reasoning
924
1151
  // This handles transitional chunks that may have both reasoning and content
@@ -929,11 +1156,158 @@ export function getChunkContent({
929
1156
  if (reasoning != null && reasoning !== '') {
930
1157
  return reasoning;
931
1158
  }
1159
+ const reasoningContent = chunk?.additional_kwargs?.reasoning_content as
1160
+ | string
1161
+ | undefined;
1162
+ if (reasoningContent != null && reasoningContent !== '') {
1163
+ return reasoningContent;
1164
+ }
932
1165
  return chunk?.content;
933
1166
  }
1167
+ const keyedReasoning = chunk?.additional_kwargs?.[reasoningKey] as
1168
+ | string
1169
+ | undefined;
1170
+ if (
1171
+ typeof chunk?.content === 'string' &&
1172
+ chunk.content !== '' &&
1173
+ keyedReasoning != null &&
1174
+ keyedReasoning !== ''
1175
+ ) {
1176
+ return chunk.content;
1177
+ }
1178
+ return ((keyedReasoning as string | undefined) ?? '') || chunk?.content;
1179
+ }
1180
+
1181
+ function isDisableStreamingEnabled(
1182
+ clientOptions: t.ClientOptions | undefined
1183
+ ): boolean {
1184
+ return (
1185
+ clientOptions != null &&
1186
+ 'disableStreaming' in clientOptions &&
1187
+ clientOptions.disableStreaming === true
1188
+ );
1189
+ }
1190
+
1191
+ function hasReasoningContent(
1192
+ value: string | ReasoningSummaryLike | object[] | null | undefined
1193
+ ): boolean {
1194
+ if (typeof value === 'string') {
1195
+ return value !== '';
1196
+ }
1197
+ if (Array.isArray(value)) {
1198
+ return value.length > 0;
1199
+ }
1200
+ if (value == null) {
1201
+ return false;
1202
+ }
1203
+ return (
1204
+ value.summary?.some(
1205
+ (summary) => summary.text != null && summary.text.length > 0
1206
+ ) === true
1207
+ );
1208
+ }
1209
+
1210
+ function shouldDeferMixedFinalReasoningChunk({
1211
+ chunk,
1212
+ agentContext,
1213
+ }: {
1214
+ chunk: Partial<AIMessageChunk>;
1215
+ agentContext: AgentContext;
1216
+ }): boolean {
1217
+ if (
1218
+ (chunk.tool_calls?.length ?? 0) > 0 ||
1219
+ (chunk.tool_call_chunks?.length ?? 0) > 0 ||
1220
+ typeof chunk.content !== 'string' ||
1221
+ chunk.content === ''
1222
+ ) {
1223
+ return false;
1224
+ }
1225
+ const additionalKwargs = chunk.additional_kwargs;
1226
+ if (
1227
+ agentContext.provider === Providers.OPENROUTER &&
1228
+ hasReasoningContent(additionalKwargs?.reasoning_details as object[])
1229
+ ) {
1230
+ return true;
1231
+ }
1232
+ if (!isDisableStreamingEnabled(agentContext.clientOptions)) {
1233
+ return false;
1234
+ }
1235
+ return (
1236
+ hasReasoningContent(
1237
+ additionalKwargs?.[agentContext.reasoningKey] as
1238
+ | string
1239
+ | ReasoningSummaryLike
1240
+ | null
1241
+ | undefined
1242
+ ) ||
1243
+ hasReasoningContent(
1244
+ additionalKwargs?.reasoning_content as
1245
+ | string
1246
+ | ReasoningSummaryLike
1247
+ | null
1248
+ | undefined
1249
+ ) ||
1250
+ hasReasoningContent(
1251
+ additionalKwargs?.reasoning as
1252
+ | string
1253
+ | ReasoningSummaryLike
1254
+ | null
1255
+ | undefined
1256
+ ) ||
1257
+ hasReasoningContent(additionalKwargs?.reasoning_details as object[])
1258
+ );
1259
+ }
1260
+
1261
+ function hasCurrentTextDeltaStep({
1262
+ graph,
1263
+ metadata,
1264
+ }: {
1265
+ graph: StandardGraph;
1266
+ metadata?: Record<string, unknown>;
1267
+ }): boolean {
1268
+ if (metadata == null) {
1269
+ return false;
1270
+ }
1271
+ const baseStepKey = graph.getStepBaseKey(metadata);
1272
+ for (const [stepKey, stepIds] of graph.stepKeyIds) {
1273
+ if (stepKey !== baseStepKey && !stepKey.startsWith(`${baseStepKey}_`)) {
1274
+ continue;
1275
+ }
1276
+ if (stepIds.some((stepId) => graph.messageStepHasTextDeltas.has(stepId))) {
1277
+ return true;
1278
+ }
1279
+ }
1280
+ return false;
1281
+ }
1282
+
1283
+ function shouldSkipLateOpenRouterReasoningChunk({
1284
+ chunk,
1285
+ agentContext,
1286
+ graph,
1287
+ metadata,
1288
+ }: {
1289
+ chunk: Partial<AIMessageChunk>;
1290
+ agentContext: AgentContext;
1291
+ graph: StandardGraph;
1292
+ metadata?: Record<string, unknown>;
1293
+ }): boolean {
1294
+ if (
1295
+ agentContext.provider !== Providers.OPENROUTER ||
1296
+ (chunk.tool_calls?.length ?? 0) > 0 ||
1297
+ (chunk.tool_call_chunks?.length ?? 0) > 0 ||
1298
+ (chunk.content != null && chunk.content !== '')
1299
+ ) {
1300
+ return false;
1301
+ }
934
1302
  return (
935
- ((chunk?.additional_kwargs?.[reasoningKey] as string | undefined) ?? '') ||
936
- chunk?.content
1303
+ (hasReasoningContent(chunk.additional_kwargs?.reasoning as string) ||
1304
+ hasReasoningContent(
1305
+ chunk.additional_kwargs?.reasoning_content as string
1306
+ ) ||
1307
+ hasReasoningContent(
1308
+ chunk.additional_kwargs?.reasoning_details as object[]
1309
+ )) &&
1310
+ hasCurrentTextDeltaStep({ graph, metadata })
937
1311
  );
938
1312
  }
939
1313
 
@@ -974,11 +1348,39 @@ export class ChatModelStreamHandler implements t.EventHandler {
974
1348
  if (skipHandling) {
975
1349
  return;
976
1350
  }
1351
+ if (shouldDeferMixedFinalReasoningChunk({ chunk, agentContext })) {
1352
+ return;
1353
+ }
1354
+ if (
1355
+ shouldSkipLateOpenRouterReasoningChunk({
1356
+ chunk,
1357
+ agentContext,
1358
+ graph,
1359
+ metadata,
1360
+ })
1361
+ ) {
1362
+ return;
1363
+ }
977
1364
  this.handleReasoning(chunk, agentContext);
978
1365
  const stepKey = graph.getStepKey(metadata);
979
1366
  let hasToolCalls = false;
980
1367
  const hasToolCallChunks =
981
1368
  (chunk.tool_call_chunks && chunk.tool_call_chunks.length > 0) ?? false;
1369
+ const hasGoogleServerSideToolContent =
1370
+ isGoogleLike(agentContext.provider) &&
1371
+ Array.isArray(content) &&
1372
+ content.some((c) => isGoogleServerSideToolContentPart(c));
1373
+ if (hasGoogleServerSideToolContent && Array.isArray(content)) {
1374
+ await dispatchGoogleServerSideToolStreamContent({
1375
+ graph,
1376
+ stepKey,
1377
+ chunk,
1378
+ agentContext,
1379
+ content,
1380
+ metadata,
1381
+ });
1382
+ }
1383
+
982
1384
  if (
983
1385
  chunk.tool_calls &&
984
1386
  chunk.tool_calls.length > 0 &&
@@ -1069,6 +1471,10 @@ export class ChatModelStreamHandler implements t.EventHandler {
1069
1471
  return;
1070
1472
  }
1071
1473
 
1474
+ if (hasGoogleServerSideToolContent) {
1475
+ return;
1476
+ }
1477
+
1072
1478
  const message_id = getMessageId(stepKey, graph) ?? '';
1073
1479
  if (message_id) {
1074
1480
  await graph.dispatchRunStep(
@@ -1083,8 +1489,19 @@ export class ChatModelStreamHandler implements t.EventHandler {
1083
1489
  );
1084
1490
  }
1085
1491
 
1086
- const stepId = graph.getStepIdByKey(stepKey);
1087
- const runStep = graph.getRunStep(stepId);
1492
+ let stepId = graph.getStepIdByKey(stepKey);
1493
+ let runStep = graph.getRunStep(stepId);
1494
+ if (
1495
+ shouldStartFreshMessageStepAfterGoogleServerSideTool({
1496
+ graph,
1497
+ stepId,
1498
+ runStep,
1499
+ content,
1500
+ })
1501
+ ) {
1502
+ stepId = await dispatchMessageCreationStep({ graph, stepKey, metadata });
1503
+ runStep = graph.getRunStep(stepId);
1504
+ }
1088
1505
  if (!runStep) {
1089
1506
  console.warn(`\n
1090
1507
  ==============================================================
@@ -1186,9 +1603,7 @@ hasToolCallChunks: ${hasToolCallChunks}
1186
1603
  metadata
1187
1604
  );
1188
1605
  }
1189
- } else if (
1190
- content.every((c) => c.type?.startsWith(ContentTypes.TEXT) ?? false)
1191
- ) {
1606
+ } else if (content.every((c) => isTextContentPart(c))) {
1192
1607
  await graph.dispatchMessageDelta(
1193
1608
  stepId,
1194
1609
  {
@@ -1196,15 +1611,7 @@ hasToolCallChunks: ${hasToolCallChunks}
1196
1611
  },
1197
1612
  metadata
1198
1613
  );
1199
- } else if (
1200
- content.every(
1201
- (c) =>
1202
- (c.type?.startsWith(ContentTypes.THINKING) ?? false) ||
1203
- (c.type?.startsWith(ContentTypes.REASONING) ?? false) ||
1204
- (c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false) ||
1205
- c.type === 'redacted_thinking'
1206
- )
1207
- ) {
1614
+ } else if (content.every((c) => isReasoningContentPart(c))) {
1208
1615
  await graph.dispatchReasoningDelta(
1209
1616
  stepId,
1210
1617
  {
@@ -1255,7 +1662,9 @@ hasToolCallChunks: ${hasToolCallChunks}
1255
1662
  Array.isArray(chunk.additional_kwargs.reasoning_details) &&
1256
1663
  chunk.additional_kwargs.reasoning_details.length > 0) ||
1257
1664
  (typeof chunk.additional_kwargs?.reasoning === 'string' &&
1258
- chunk.additional_kwargs.reasoning !== ''))
1665
+ chunk.additional_kwargs.reasoning !== '') ||
1666
+ (typeof chunk.additional_kwargs?.reasoning_content === 'string' &&
1667
+ chunk.additional_kwargs.reasoning_content !== ''))
1259
1668
  ) {
1260
1669
  reasoning_content = 'valid';
1261
1670
  }
@@ -1388,6 +1797,8 @@ export function createContentAggregator(): t.ContentAggregatorResult {
1388
1797
  };
1389
1798
 
1390
1799
  contentParts[index] = update;
1800
+ } else if (partType === 'toolCall' || partType === 'toolResponse') {
1801
+ contentParts[index] = contentPart;
1391
1802
  } else if (partType === ContentTypes.SUMMARY) {
1392
1803
  const currentSummary = contentParts[index] as
1393
1804
  | t.SummaryContentBlock
@@ -1,6 +1,6 @@
1
- import { createContentAggregator } from '@/stream';
2
- import { ContentTypes, GraphEvents, StepTypes } from '@/common';
3
1
  import type * as t from '@/types';
2
+ import { ContentTypes, GraphEvents, StepTypes } from '@/common';
3
+ import { createContentAggregator } from '@/stream';
4
4
 
5
5
  describe('createContentAggregator – SUMMARY accumulation', () => {
6
6
  it('accumulates text from multiple ON_SUMMARIZE_DELTA events', () => {
@@ -1,15 +1,15 @@
1
1
  import { AIMessage, HumanMessage, ToolMessage } from '@langchain/core/messages';
2
2
  import type { RunnableConfig } from '@langchain/core/runnables';
3
3
  import type * as t from '@/types';
4
- import { GraphEvents, Providers } from '@/common';
5
4
  import {
6
5
  createSummarizeNode,
7
6
  DEFAULT_SUMMARIZATION_PROMPT,
8
7
  DEFAULT_UPDATE_SUMMARIZATION_PROMPT,
9
8
  } from '@/summarization/node';
9
+ import { AgentContext } from '@/agents/AgentContext';
10
+ import { GraphEvents, Providers } from '@/common';
10
11
  import * as providers from '@/llm/providers';
11
12
  import * as eventUtils from '@/utils/events';
12
- import { AgentContext } from '@/agents/AgentContext';
13
13
 
14
14
  // ---------------------------------------------------------------------------
15
15
  // Helpers
@@ -4,8 +4,8 @@ import {
4
4
  HumanMessage,
5
5
  SystemMessage,
6
6
  } from '@langchain/core/messages';
7
- import type { RunnableConfig } from '@langchain/core/runnables';
8
7
  import type { UsageMetadata, BaseMessage } from '@langchain/core/messages';
8
+ import type { RunnableConfig } from '@langchain/core/runnables';
9
9
  import type { AgentContext } from '@/agents/AgentContext';
10
10
  import type { HookRegistry } from '@/hooks';
11
11
  import type { OnChunk } from '@/llm/invoke';