@librechat/agents 3.2.31 → 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 (582) 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 -696
  53. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  54. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +171 -252
  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 +308 -401
  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 -1382
  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 -690
  324. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  325. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +171 -249
  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 +308 -399
  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 -1378
  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/messages/format.d.ts +5 -0
  545. package/dist/types/tools/search/tool.d.ts +17 -0
  546. package/dist/types/tools/search/types.d.ts +4 -0
  547. package/package.json +11 -17
  548. package/src/llm/anthropic/llm.spec.ts +36 -0
  549. package/src/llm/anthropic/utils/message_inputs.ts +45 -3
  550. package/src/llm/anthropic/utils/message_outputs.ts +6 -2
  551. package/src/llm/anthropic/utils/streaming-tool-input.test.ts +186 -0
  552. package/src/messages/cache.test.ts +122 -0
  553. package/src/messages/cache.ts +25 -1
  554. package/src/messages/format.ts +9 -0
  555. package/src/messages/formatAgentMessages.skills.test.ts +100 -0
  556. package/src/tools/search/highlights.ts +9 -1
  557. package/src/tools/search/search.ts +41 -3
  558. package/src/tools/search/source-processing.test.ts +373 -0
  559. package/src/tools/search/tool.ts +22 -2
  560. package/src/tools/search/types.ts +4 -0
  561. package/dist/cjs/langchain/google-common.cjs.map +0 -1
  562. package/dist/cjs/langchain/index.cjs.map +0 -1
  563. package/dist/cjs/langchain/language_models/chat_models.cjs.map +0 -1
  564. package/dist/cjs/langchain/messages/tool.cjs.map +0 -1
  565. package/dist/cjs/langchain/messages.cjs.map +0 -1
  566. package/dist/cjs/langchain/openai.cjs.map +0 -1
  567. package/dist/cjs/langchain/prompts.cjs.map +0 -1
  568. package/dist/cjs/langchain/runnables.cjs.map +0 -1
  569. package/dist/cjs/langchain/tools.cjs.map +0 -1
  570. package/dist/cjs/langchain/utils/env.cjs.map +0 -1
  571. package/dist/cjs/main.cjs.map +0 -1
  572. package/dist/esm/langchain/google-common.mjs.map +0 -1
  573. package/dist/esm/langchain/index.mjs.map +0 -1
  574. package/dist/esm/langchain/language_models/chat_models.mjs.map +0 -1
  575. package/dist/esm/langchain/messages/tool.mjs.map +0 -1
  576. package/dist/esm/langchain/messages.mjs.map +0 -1
  577. package/dist/esm/langchain/openai.mjs.map +0 -1
  578. package/dist/esm/langchain/prompts.mjs.map +0 -1
  579. package/dist/esm/langchain/runnables.mjs.map +0 -1
  580. package/dist/esm/langchain/tools.mjs.map +0 -1
  581. package/dist/esm/langchain/utils/env.mjs.map +0 -1
  582. package/dist/esm/main.mjs.map +0 -1
@@ -1,1836 +1,1420 @@
1
- import { nanoid } from 'nanoid';
2
- import { tool } from '@langchain/core/tools';
3
- import { AIMessageChunk, ToolMessage } from '@langchain/core/messages';
4
- import { Annotation, StateGraph, START, END } from '@langchain/langgraph';
5
- import { convertMessagesToContent, formatAnthropicArtifactContent, formatArtifactPayload } from '../messages/core.mjs';
6
- import { getMessageId } from '../messages/ids.mjs';
7
- import { createPruneMessages, enforceOriginalContentCap, sanitizeOrphanToolBlocks } from '../messages/prune.mjs';
8
- import { ensureThinkingBlockInMessages } from '../messages/format.mjs';
9
- import { addCacheControl, addBedrockCacheControl } from '../messages/cache.mjs';
10
- import { partitionAndMarkAnthropicToolCache, makeIsDeferred } from '../messages/anthropicToolCache.mjs';
11
- import { formatContentStrings } from '../messages/content.mjs';
12
- import { extractToolDiscoveries } from '../messages/tools.mjs';
13
- import { messagesStateReducer } from '../messages/reducer.mjs';
14
- import { shouldTraceToolNodeForLangfuse, resolveLangfuseConfig, withLangfuseToolOutputTracingConfig } from '../langfuseToolOutputTracing.mjs';
15
- import { createLangfuseTraceMetadata, createLangfuseHandler, disposeLangfuseHandler, isLangfuseCallbackHandler } from '../langfuse.mjs';
16
- import { resetIfNotEmpty, joinKeys } from '../utils/graph.mjs';
17
- import { isAnthropicLike, isOpenAILike, isGoogleLike } from '../utils/llm.mjs';
18
- import '../stream.mjs';
19
- import { GraphNodeKeys, ContentTypes, Providers, GraphEvents, StepTypes } from '../common/enum.mjs';
20
- import { sleep } from '../utils/run.mjs';
21
- import 'ai-tokenizer';
22
- import 'zod-to-json-schema';
23
- import { findCallback, appendCallbacks } from '../utils/callbacks.mjs';
24
- import { partitionAndMarkOpenRouterToolCache } from '../llm/openrouter/toolCache.mjs';
25
- import { ToolNode, toolsCondition } from '../tools/ToolNode.mjs';
26
- import { createLocalCodingToolBundle } from '../tools/local/LocalCodingTools.mjs';
27
- import { resolveSubagentConfigs, SubagentExecutor } from '../tools/subagent/SubagentExecutor.mjs';
28
- import { ToolOutputReferenceRegistry } from '../tools/toolOutputReferences.mjs';
29
- import { partitionAndMarkBedrockToolCache } from '../llm/bedrock/toolCache.mjs';
30
- import { emitAgentLog, safeDispatchCustomEvent } from '../utils/events.mjs';
31
- import 'path';
32
- import '../tools/cloudflare/CloudflareProgrammaticToolCalling.mjs';
33
- import 'stream';
34
- import 'events';
35
- import '../tools/local/LocalExecutionEngine.mjs';
36
- import { createCloudflareCodingToolBundle } from '../tools/cloudflare/CloudflareSandboxTools.mjs';
37
- import { attemptInvoke, tryFallbackProviders } from '../llm/invoke.mjs';
38
- import { buildSubagentToolParams } from '../tools/SubagentTool.mjs';
39
- import { initializeLangfuseTracing } from '../instrumentation.mjs';
40
- import { shouldTriggerSummarization } from '../summarization/index.mjs';
41
- import '../tools/local/CompileCheckTool.mjs';
42
- import 'fs/promises';
43
- import '../tools/BashExecutor.mjs';
44
- import '../tools/CodeExecutor.mjs';
45
- import 'http';
46
- import 'crypto';
47
- import '../tools/ProgrammaticToolCalling.mjs';
48
- import '../tools/BashProgrammaticToolCalling.mjs';
49
- import '../hooks/createWorkspacePolicyHook.mjs';
50
- import { resolveLocalToolsForBinding } from '../tools/local/resolveLocalExecutionTools.mjs';
51
- import { createSummarizeNode } from '../summarization/node.mjs';
52
- import { createSchemaOnlyTools } from '../tools/schema.mjs';
53
- import { AgentContext } from '../agents/AgentContext.mjs';
54
- import { createFakeStreamingLLM } from '../llm/fake.mjs';
55
- import { handleToolCalls } from '../tools/handlers.mjs';
56
- import { isThinkingEnabled } from '../llm/request.mjs';
57
- import { initializeModel } from '../llm/init.mjs';
58
-
59
- /* eslint-disable no-console */
1
+ import { createLangfuseHandler, createLangfuseTraceMetadata, disposeLangfuseHandler, isLangfuseCallbackHandler } from "../langfuse.mjs";
2
+ import { resolveLangfuseConfig, shouldTraceToolNodeForLangfuse, withLangfuseToolOutputTracingConfig } from "../langfuseToolOutputTracing.mjs";
3
+ import { appendCallbacks, findCallback } from "../utils/callbacks.mjs";
4
+ import { GraphNodeKeys } from "../common/enum.mjs";
5
+ import "../common/index.mjs";
6
+ import { initializeLangfuseTracing } from "../instrumentation.mjs";
7
+ import { convertMessagesToContent, formatAnthropicArtifactContent, formatArtifactPayload } from "../messages/core.mjs";
8
+ import { getMessageId } from "../messages/ids.mjs";
9
+ import { createPruneMessages, enforceOriginalContentCap, sanitizeOrphanToolBlocks } from "../messages/prune.mjs";
10
+ import { emitAgentLog, safeDispatchCustomEvent } from "../utils/events.mjs";
11
+ import { ensureThinkingBlockInMessages } from "../messages/format.mjs";
12
+ import { addBedrockCacheControl, addCacheControl } from "../messages/cache.mjs";
13
+ import { makeIsDeferred, partitionAndMarkAnthropicToolCache } from "../messages/anthropicToolCache.mjs";
14
+ import { formatContentStrings } from "../messages/content.mjs";
15
+ import { extractToolDiscoveries } from "../messages/tools.mjs";
16
+ import { messagesStateReducer as messagesStateReducer$1 } from "../messages/reducer.mjs";
17
+ import "../messages/index.mjs";
18
+ import { joinKeys, resetIfNotEmpty } from "../utils/graph.mjs";
19
+ import { isAnthropicLike, isGoogleLike, isOpenAILike } from "../utils/llm.mjs";
20
+ import { handleToolCalls } from "../tools/handlers.mjs";
21
+ import { ToolOutputReferenceRegistry } from "../tools/toolOutputReferences.mjs";
22
+ import { sleep } from "../utils/run.mjs";
23
+ import "../utils/index.mjs";
24
+ import { partitionAndMarkOpenRouterToolCache } from "../llm/openrouter/toolCache.mjs";
25
+ import { createLocalCodingToolBundle } from "../tools/local/LocalCodingTools.mjs";
26
+ import { createCloudflareCodingToolBundle } from "../tools/cloudflare/CloudflareSandboxTools.mjs";
27
+ import "../tools/cloudflare/index.mjs";
28
+ import { resolveLocalToolsForBinding } from "../tools/local/resolveLocalExecutionTools.mjs";
29
+ import "../tools/local/index.mjs";
30
+ import { ToolNode, toolsCondition } from "../tools/ToolNode.mjs";
31
+ import { SubagentExecutor, resolveSubagentConfigs } from "../tools/subagent/SubagentExecutor.mjs";
32
+ import "../tools/subagent/index.mjs";
33
+ import { partitionAndMarkBedrockToolCache } from "../llm/bedrock/toolCache.mjs";
34
+ import { initializeModel } from "../llm/init.mjs";
35
+ import { attemptInvoke, tryFallbackProviders } from "../llm/invoke.mjs";
36
+ import { buildSubagentToolParams } from "../tools/SubagentTool.mjs";
37
+ import { shouldTriggerSummarization } from "../summarization/index.mjs";
38
+ import { isThinkingEnabled } from "../llm/request.mjs";
39
+ import { createSummarizeNode } from "../summarization/node.mjs";
40
+ import { createSchemaOnlyTools } from "../tools/schema.mjs";
41
+ import { AgentContext } from "../agents/AgentContext.mjs";
42
+ import { createFakeStreamingLLM } from "../llm/fake.mjs";
43
+ import { AIMessageChunk, ToolMessage } from "@langchain/core/messages";
44
+ import { Annotation, END, START, StateGraph } from "@langchain/langgraph";
45
+ import { tool } from "@langchain/core/tools";
46
+ import { nanoid } from "nanoid";
47
+ //#region src/graphs/Graph.ts
60
48
  const { AGENT, TOOLS, SUMMARIZE } = GraphNodeKeys;
61
49
  /** Minimum relative variance before calibrated toolSchemaTokens overrides current value. */
62
- const CALIBRATION_VARIANCE_THRESHOLD = 0.15;
50
+ const CALIBRATION_VARIANCE_THRESHOLD = .15;
63
51
  function getHandlerDispatchedEventKey(eventName, stepId) {
64
- return `${eventName}:${stepId}`;
52
+ return `${eventName}:${stepId}`;
65
53
  }
66
54
  function getReasoningText(value) {
67
- if (typeof value === 'string') {
68
- return value !== '' ? value : undefined;
69
- }
70
- const summaryText = value?.summary
71
- ?.map((summary) => summary.text ?? '')
72
- .filter((text) => text !== '')
73
- .join('');
74
- return summaryText != null && summaryText !== '' ? summaryText : undefined;
55
+ if (typeof value === "string") return value !== "" ? value : void 0;
56
+ const summaryText = value?.summary?.map((summary) => summary.text ?? "").filter((text) => text !== "").join("");
57
+ return summaryText != null && summaryText !== "" ? summaryText : void 0;
75
58
  }
76
59
  function getReasoningDetailsText(value) {
77
- if (!Array.isArray(value)) {
78
- return undefined;
79
- }
80
- const reasoningText = value
81
- .filter((detail) => detail.type === 'reasoning.text')
82
- .map((detail) => detail.text ?? '')
83
- .filter((text) => text !== '')
84
- .join('');
85
- return reasoningText !== '' ? reasoningText : undefined;
60
+ if (!Array.isArray(value)) return;
61
+ const reasoningText = value.filter((detail) => detail.type === "reasoning.text").map((detail) => detail.text ?? "").filter((text) => text !== "").join("");
62
+ return reasoningText !== "" ? reasoningText : void 0;
86
63
  }
87
- function getResponseReasoningContent({ responseMessage, reasoningKey, }) {
88
- const additionalKwargs = responseMessage?.additional_kwargs;
89
- if (additionalKwargs == null) {
90
- return undefined;
91
- }
92
- const keyedReasoning = getReasoningText(additionalKwargs[reasoningKey]);
93
- if (keyedReasoning != null) {
94
- return keyedReasoning;
95
- }
96
- const reasoningContent = getReasoningText(additionalKwargs.reasoning_content);
97
- if (reasoningContent != null) {
98
- return reasoningContent;
99
- }
100
- const reasoning = getReasoningText(additionalKwargs.reasoning);
101
- if (reasoning != null) {
102
- return reasoning;
103
- }
104
- return getReasoningDetailsText(additionalKwargs.reasoning_details);
64
+ function getResponseReasoningContent({ responseMessage, reasoningKey }) {
65
+ const additionalKwargs = responseMessage?.additional_kwargs;
66
+ if (additionalKwargs == null) return;
67
+ const keyedReasoning = getReasoningText(additionalKwargs[reasoningKey]);
68
+ if (keyedReasoning != null) return keyedReasoning;
69
+ const reasoningContent = getReasoningText(additionalKwargs.reasoning_content);
70
+ if (reasoningContent != null) return reasoningContent;
71
+ const reasoning = getReasoningText(additionalKwargs.reasoning);
72
+ if (reasoning != null) return reasoning;
73
+ return getReasoningDetailsText(additionalKwargs.reasoning_details);
105
74
  }
106
75
  function isTextMessageContentPart(contentPart) {
107
- return (typeof contentPart === 'object' &&
108
- 'type' in contentPart &&
109
- typeof contentPart.type === 'string' &&
110
- contentPart.type.startsWith('text'));
76
+ return typeof contentPart === "object" && "type" in contentPart && typeof contentPart.type === "string" && contentPart.type.startsWith("text");
111
77
  }
112
78
  function isGoogleServerSideToolMessageContentPart(contentPart) {
113
- return (typeof contentPart === 'object' &&
114
- 'type' in contentPart &&
115
- (contentPart.type === 'toolCall' || contentPart.type === 'toolResponse'));
79
+ return typeof contentPart === "object" && "type" in contentPart && (contentPart.type === "toolCall" || contentPart.type === "toolResponse");
116
80
  }
117
81
  function hasGoogleServerSideToolDeltaContent(provider, content) {
118
- return (isGoogleLike(provider) &&
119
- Array.isArray(content) &&
120
- content.some((contentPart) => isGoogleServerSideToolMessageContentPart(contentPart)));
82
+ return isGoogleLike(provider) && Array.isArray(content) && content.some((contentPart) => isGoogleServerSideToolMessageContentPart(contentPart));
121
83
  }
122
84
  function getMessageDeltaContent(provider, content) {
123
- if (content == null) {
124
- return undefined;
125
- }
126
- if (typeof content === 'string') {
127
- return content !== ''
128
- ? [{ type: ContentTypes.TEXT, text: content }]
129
- : undefined;
130
- }
131
- if (content.length === 0) {
132
- return undefined;
133
- }
134
- const hasGoogleServerSideToolPart = isGoogleLike(provider) &&
135
- content.some((contentPart) => isGoogleServerSideToolMessageContentPart(contentPart));
136
- if (content.every((contentPart) => isTextMessageContentPart(contentPart))) {
137
- return content;
138
- }
139
- if (!hasGoogleServerSideToolPart) {
140
- return undefined;
141
- }
142
- const messageContent = content.filter((contentPart) => isTextMessageContentPart(contentPart) ||
143
- isGoogleServerSideToolMessageContentPart(contentPart));
144
- return messageContent.length > 0
145
- ? messageContent
146
- : undefined;
85
+ if (content == null) return;
86
+ if (typeof content === "string") return content !== "" ? [{
87
+ type: "text",
88
+ text: content
89
+ }] : void 0;
90
+ if (content.length === 0) return;
91
+ const hasGoogleServerSideToolPart = isGoogleLike(provider) && content.some((contentPart) => isGoogleServerSideToolMessageContentPart(contentPart));
92
+ if (content.every((contentPart) => isTextMessageContentPart(contentPart))) return content;
93
+ if (!hasGoogleServerSideToolPart) return;
94
+ const messageContent = content.filter((contentPart) => isTextMessageContentPart(contentPart) || isGoogleServerSideToolMessageContentPart(contentPart));
95
+ return messageContent.length > 0 ? messageContent : void 0;
147
96
  }
148
97
  function hasTextDeltaContent(content) {
149
- if (content == null) {
150
- return false;
151
- }
152
- return content.some((contentPart) => {
153
- if (contentPart.type?.startsWith(ContentTypes.TEXT) !== true) {
154
- return false;
155
- }
156
- const text = contentPart.text;
157
- return typeof text === 'string' && text !== '';
158
- });
98
+ if (content == null) return false;
99
+ return content.some((contentPart) => {
100
+ if (contentPart.type?.startsWith("text") !== true) return false;
101
+ const text = contentPart.text;
102
+ return typeof text === "string" && text !== "";
103
+ });
159
104
  }
160
105
  function hasReasoningDeltaContent(content) {
161
- if (content == null) {
162
- return false;
163
- }
164
- return content.some((contentPart) => contentPart.type === ContentTypes.THINK && contentPart.think !== '');
106
+ if (content == null) return false;
107
+ return content.some((contentPart) => contentPart.type === "think" && contentPart.think !== "");
165
108
  }
166
- function getCurrentStepIds({ graph, metadata, }) {
167
- const baseStepKey = graph.getStepBaseKey(metadata);
168
- const currentStepIds = [];
169
- for (const [stepKey, stepIds] of graph.stepKeyIds) {
170
- if (stepKey !== baseStepKey && !stepKey.startsWith(`${baseStepKey}_`)) {
171
- continue;
172
- }
173
- currentStepIds.push(...stepIds);
174
- }
175
- return currentStepIds;
109
+ function getCurrentStepIds({ graph, metadata }) {
110
+ const baseStepKey = graph.getStepBaseKey(metadata);
111
+ const currentStepIds = [];
112
+ for (const [stepKey, stepIds] of graph.stepKeyIds) {
113
+ if (stepKey !== baseStepKey && !stepKey.startsWith(`${baseStepKey}_`)) continue;
114
+ currentStepIds.push(...stepIds);
115
+ }
116
+ return currentStepIds;
176
117
  }
177
- function hasCurrentTextDeltaStep({ graph, metadata, }) {
178
- return getCurrentStepIds({ graph, metadata }).some((stepId) => graph.messageStepHasTextDeltas.has(stepId));
118
+ function hasCurrentTextDeltaStep({ graph, metadata }) {
119
+ return getCurrentStepIds({
120
+ graph,
121
+ metadata
122
+ }).some((stepId) => graph.messageStepHasTextDeltas.has(stepId));
179
123
  }
180
- function hasCurrentReasoningDeltaStep({ graph, metadata, }) {
181
- return getCurrentStepIds({ graph, metadata }).some((stepId) => graph.reasoningStepHasDeltas.has(stepId));
124
+ function hasCurrentReasoningDeltaStep({ graph, metadata }) {
125
+ return getCurrentStepIds({
126
+ graph,
127
+ metadata
128
+ }).some((stepId) => graph.reasoningStepHasDeltas.has(stepId));
182
129
  }
183
- function clearCurrentDeltaStepMarkers({ graph, metadata, }) {
184
- for (const stepId of getCurrentStepIds({ graph, metadata })) {
185
- graph.messageStepHasTextDeltas.delete(stepId);
186
- graph.reasoningStepHasDeltas.delete(stepId);
187
- }
130
+ function clearCurrentDeltaStepMarkers({ graph, metadata }) {
131
+ for (const stepId of getCurrentStepIds({
132
+ graph,
133
+ metadata
134
+ })) {
135
+ graph.messageStepHasTextDeltas.delete(stepId);
136
+ graph.reasoningStepHasDeltas.delete(stepId);
137
+ }
188
138
  }
189
- async function dispatchMessageCreationStep({ graph, stepKey, messageId, metadata, }) {
190
- await graph.dispatchRunStep(stepKey, {
191
- type: StepTypes.MESSAGE_CREATION,
192
- message_creation: { message_id: messageId },
193
- }, metadata);
194
- return graph.getStepIdByKey(stepKey);
139
+ async function dispatchMessageCreationStep({ graph, stepKey, messageId, metadata }) {
140
+ await graph.dispatchRunStep(stepKey, {
141
+ type: "message_creation",
142
+ message_creation: { message_id: messageId }
143
+ }, metadata);
144
+ return graph.getStepIdByKey(stepKey);
195
145
  }
196
- async function dispatchTextMessageContent({ graph, stepKey, provider, content, metadata, }) {
197
- const messageId = getMessageId(stepKey, graph) ?? '';
198
- if (!messageId) {
199
- return false;
200
- }
201
- if (hasGoogleServerSideToolDeltaContent(provider, content)) {
202
- for (const contentPart of content) {
203
- const stepId = await dispatchMessageCreationStep({
204
- graph,
205
- stepKey,
206
- messageId,
207
- metadata,
208
- });
209
- await graph.dispatchMessageDelta(stepId, { content: [contentPart] }, metadata);
210
- }
211
- return true;
212
- }
213
- const stepId = await dispatchMessageCreationStep({
214
- graph,
215
- stepKey,
216
- messageId,
217
- metadata,
218
- });
219
- await graph.dispatchMessageDelta(stepId, { content }, metadata);
220
- return true;
146
+ async function dispatchTextMessageContent({ graph, stepKey, provider, content, metadata }) {
147
+ const messageId = getMessageId(stepKey, graph) ?? "";
148
+ if (!messageId) return false;
149
+ if (hasGoogleServerSideToolDeltaContent(provider, content)) {
150
+ for (const contentPart of content) {
151
+ const stepId = await dispatchMessageCreationStep({
152
+ graph,
153
+ stepKey,
154
+ messageId,
155
+ metadata
156
+ });
157
+ await graph.dispatchMessageDelta(stepId, { content: [contentPart] }, metadata);
158
+ }
159
+ return true;
160
+ }
161
+ const stepId = await dispatchMessageCreationStep({
162
+ graph,
163
+ stepKey,
164
+ messageId,
165
+ metadata
166
+ });
167
+ await graph.dispatchMessageDelta(stepId, { content }, metadata);
168
+ return true;
221
169
  }
222
- async function dispatchReasoningContent({ graph, agentContext, reasoningContent, metadata, }) {
223
- const previousTokenType = agentContext.currentTokenType;
224
- const previousTokenTypeSwitch = agentContext.tokenTypeSwitch;
225
- const previousTransitionCount = agentContext.reasoningTransitionCount;
226
- agentContext.currentTokenType = ContentTypes.THINK;
227
- agentContext.tokenTypeSwitch = 'reasoning';
228
- const stepKey = graph.getStepKey(metadata);
229
- const messageId = getMessageId(stepKey, graph) ?? '';
230
- if (!messageId) {
231
- agentContext.currentTokenType = previousTokenType;
232
- agentContext.tokenTypeSwitch = previousTokenTypeSwitch;
233
- agentContext.reasoningTransitionCount = previousTransitionCount;
234
- return false;
235
- }
236
- await graph.dispatchRunStep(stepKey, {
237
- type: StepTypes.MESSAGE_CREATION,
238
- message_creation: { message_id: messageId },
239
- }, metadata);
240
- const stepId = graph.getStepIdByKey(stepKey);
241
- await graph.dispatchReasoningDelta(stepId, {
242
- content: [{ type: ContentTypes.THINK, think: reasoningContent }],
243
- }, metadata);
244
- return true;
170
+ async function dispatchReasoningContent({ graph, agentContext, reasoningContent, metadata }) {
171
+ const previousTokenType = agentContext.currentTokenType;
172
+ const previousTokenTypeSwitch = agentContext.tokenTypeSwitch;
173
+ const previousTransitionCount = agentContext.reasoningTransitionCount;
174
+ agentContext.currentTokenType = "think";
175
+ agentContext.tokenTypeSwitch = "reasoning";
176
+ const stepKey = graph.getStepKey(metadata);
177
+ const messageId = getMessageId(stepKey, graph) ?? "";
178
+ if (!messageId) {
179
+ agentContext.currentTokenType = previousTokenType;
180
+ agentContext.tokenTypeSwitch = previousTokenTypeSwitch;
181
+ agentContext.reasoningTransitionCount = previousTransitionCount;
182
+ return false;
183
+ }
184
+ await graph.dispatchRunStep(stepKey, {
185
+ type: "message_creation",
186
+ message_creation: { message_id: messageId }
187
+ }, metadata);
188
+ const stepId = graph.getStepIdByKey(stepKey);
189
+ await graph.dispatchReasoningDelta(stepId, { content: [{
190
+ type: "think",
191
+ think: reasoningContent
192
+ }] }, metadata);
193
+ return true;
245
194
  }
246
195
  function markPostReasoningContent(agentContext) {
247
- if (agentContext.tokenTypeSwitch !== 'reasoning' ||
248
- agentContext.currentTokenType === ContentTypes.TEXT) {
249
- return;
250
- }
251
- agentContext.currentTokenType = ContentTypes.TEXT;
252
- agentContext.tokenTypeSwitch = 'content';
253
- agentContext.reasoningTransitionCount++;
254
- }
255
- function getDispatchableFinalReasoningContent({ agentContext, responseReasoningContent, hasStreamedTextDeltaStep, hasStreamedReasoningDeltaStep, }) {
256
- if (responseReasoningContent == null || hasStreamedReasoningDeltaStep) {
257
- return undefined;
258
- }
259
- if (agentContext.provider === Providers.OPENROUTER &&
260
- hasStreamedTextDeltaStep) {
261
- return undefined;
262
- }
263
- return responseReasoningContent;
264
- }
265
- class Graph {
266
- messageStepHasTextDeltas = new Set();
267
- messageStepHasToolCalls = new Map();
268
- messageIdsByStepKey = new Map();
269
- prelimMessageIdsByStepKey = new Map();
270
- config;
271
- contentData = [];
272
- stepKeyIds = new Map();
273
- contentIndexMap = new Map();
274
- toolCallStepIds = new Map();
275
- /**
276
- * Step IDs dispatched through the handler registry during this run.
277
- * Event echo suppression is tracked separately so repeated deltas for
278
- * the same step are scoped to the active custom event dispatch.
279
- */
280
- handlerDispatchedStepIds = new Set();
281
- reasoningStepHasDeltas = new Set();
282
- handlerDispatchedEventCounts = new Map();
283
- signal;
284
- /** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
285
- invokedToolIds;
286
- handlerRegistry;
287
- /**
288
- * True when event-driven tool execution can be routed through callbacks even
289
- * though this graph intentionally does not own the full handler registry.
290
- * Self-spawned subagent graphs use this shape: their callback forwarder sends
291
- * `ON_TOOL_EXECUTE` to the parent's handler, while child run-step events stay
292
- * wrapped as `ON_SUBAGENT_UPDATE` instead of leaking as parent events.
293
- */
294
- eventToolExecutionAvailable = false;
295
- hookRegistry;
296
- /**
297
- * Run-scoped HITL configuration. When `humanInTheLoop?.enabled` is
298
- * `true`, `ToolNode` raises a real `interrupt()` for `PreToolUse`
299
- * `ask` decisions instead of treating them as a synchronous deny.
300
- * Threaded from `RunConfig.humanInTheLoop`.
301
- */
302
- humanInTheLoop;
303
- /**
304
- * Run-scoped config for the tool output reference registry. Threaded
305
- * from `RunConfig.toolOutputReferences` down into every ToolNode this
306
- * graph compiles.
307
- */
308
- toolOutputReferences;
309
- /**
310
- * Run-scoped Langfuse defaults. Per-agent config wins when present.
311
- */
312
- langfuse;
313
- /**
314
- * Run-scoped opt-in for eager event-driven tool execution. The stream
315
- * handler may prestart eligible event-driven tools; ToolNode later
316
- * consumes the settled promises while preserving final ToolMessage order.
317
- */
318
- eagerEventToolExecution;
319
- eagerEventToolExecutions = new Map();
320
- eagerEventToolUsageCount = new Map();
321
- eagerEventToolUsageCountsByAgentId = new Map();
322
- eagerEventToolCallChunks = new Map();
323
- /**
324
- * Run-scoped execution backend for built-in code tools. Defaults to the
325
- * remote Code API sandbox when unset.
326
- */
327
- toolExecution;
328
- /**
329
- * Shared registry instance used by every ToolNode compiled from this
330
- * graph. Lazily constructed on first access so multi-agent graphs
331
- * produce one registry per run (not one per agent), letting cross-
332
- * agent `{{tool<i>turn<n>}}` substitutions resolve.
333
- */
334
- _toolOutputRegistry;
335
- /**
336
- * Tool session contexts for automatic state persistence across tool invocations.
337
- * Keyed by tool name (e.g., Constants.EXECUTE_CODE).
338
- * Currently supports code execution session tracking (session_id, files).
339
- */
340
- sessions = new Map();
341
- /**
342
- * Clears heavy references to allow GC to reclaim memory held by
343
- * LangGraph's internal config / AsyncLocalStorage RunTree chain.
344
- * Call after a run completes and content has been extracted.
345
- */
346
- clearHeavyState() {
347
- this.config = undefined;
348
- this.signal = undefined;
349
- this.contentData = [];
350
- this.contentIndexMap = new Map();
351
- this.stepKeyIds = new Map();
352
- this.toolCallStepIds.clear();
353
- this.messageIdsByStepKey = new Map();
354
- this.messageStepHasTextDeltas = new Set();
355
- this.reasoningStepHasDeltas = new Set();
356
- this.messageStepHasToolCalls = new Map();
357
- this.prelimMessageIdsByStepKey = new Map();
358
- this.invokedToolIds = undefined;
359
- this.handlerRegistry = undefined;
360
- this.hookRegistry = undefined;
361
- this.humanInTheLoop = undefined;
362
- this.toolOutputReferences = undefined;
363
- this.eagerEventToolExecution = undefined;
364
- this.eagerEventToolExecutions.clear();
365
- this.clearEagerEventToolUsageCounts();
366
- this.eagerEventToolCallChunks.clear();
367
- this.toolExecution = undefined;
368
- this.handlerDispatchedEventCounts.clear();
369
- /**
370
- * ToolNodes compiled from this graph captured the registry
371
- * instance at construction time, so simply dropping the Graph's
372
- * own reference would leave their captured reference — and every
373
- * stored `tool<i>turn<n>` entry, plus up to `maxTotalSize` of raw
374
- * output — alive across subsequent `processStream()` calls. Wipe
375
- * the registry's contents first so subsequent runs start fresh.
376
- */
377
- this._toolOutputRegistry?.clear();
378
- this._toolOutputRegistry = undefined;
379
- // NB: `_fileCheckpointer` is intentionally NOT cleared here.
380
- // `Run.processStream()` calls `clearHeavyState()` in its
381
- // finally block on natural-completion / error paths — exactly
382
- // when the host is most likely to want `Run.rewindFiles()` (for
383
- // rollback after a failed batch). Per-Run isolation is already
384
- // automatic because each `Run.create()` constructs a brand-new
385
- // Graph instance, so the next Run gets its own checkpointer
386
- // without us needing to reset this field. Codex P1 #32: pre-fix
387
- // the checkpointer was nulled before the caller could reach it.
388
- // Flush each compiled ToolNode's direct-path turn cache so it
389
- // doesn't leak across Runs (Codex P2 #33). The cache survives
390
- // `run()` re-entry by design (resume-stable), but end-of-Run
391
- // is the right point to reset it.
392
- for (const node of this._compiledToolNodes) {
393
- node.clearDirectPathTurns();
394
- }
395
- this._compiledToolNodes.clear();
396
- this.sessions.clear();
397
- }
398
- getEagerEventToolUsageCount(agentId) {
399
- if (agentId == null || agentId === '') {
400
- return this.eagerEventToolUsageCount;
401
- }
402
- let usageCount = this.eagerEventToolUsageCountsByAgentId.get(agentId);
403
- if (usageCount == null) {
404
- usageCount = new Map();
405
- this.eagerEventToolUsageCountsByAgentId.set(agentId, usageCount);
406
- }
407
- return usageCount;
408
- }
409
- clearEagerEventToolUsageCounts() {
410
- this.eagerEventToolUsageCount.clear();
411
- for (const usageCount of this.eagerEventToolUsageCountsByAgentId.values()) {
412
- usageCount.clear();
413
- }
414
- }
415
- markHandlerDispatchedEvent(eventName, stepId) {
416
- const key = getHandlerDispatchedEventKey(eventName, stepId);
417
- this.handlerDispatchedEventCounts.set(key, (this.handlerDispatchedEventCounts.get(key) ?? 0) + 1);
418
- return () => {
419
- const count = this.handlerDispatchedEventCounts.get(key) ?? 0;
420
- if (count <= 1) {
421
- this.handlerDispatchedEventCounts.delete(key);
422
- return;
423
- }
424
- this.handlerDispatchedEventCounts.set(key, count - 1);
425
- };
426
- }
427
- hasHandlerDispatchedEvent(eventName, stepId) {
428
- const key = getHandlerDispatchedEventKey(eventName, stepId);
429
- return (this.handlerDispatchedEventCounts.get(key) ?? 0) > 0;
430
- }
431
- /**
432
- * Subclass hook to register a freshly compiled ToolNode so
433
- * `clearHeavyState` can flush its per-Run direct-path turn cache
434
- * at end-of-Run. Internal — called from `initializeTools` in the
435
- * concrete graph subclasses.
436
- */
437
- registerCompiledToolNode(node) {
438
- this._compiledToolNodes.add(node);
439
- }
440
- /**
441
- * Returns the shared `ToolOutputReferenceRegistry` for this run,
442
- * constructing it on first access. Returns `undefined` when the
443
- * feature is disabled. All ToolNodes compiled from this graph share
444
- * this single instance so cross-agent `{{…}}` references resolve.
445
- *
446
- * @internal Public so `attemptInvoke` can read it through the typed
447
- * `InvokeContext` and project ToolMessages into LLM-facing annotated
448
- * copies right before each provider call (see
449
- * `annotateMessagesForLLM`). Host code should not call this directly
450
- * — registry mutations outside the ToolNode lifecycle break the
451
- * partitioning, eviction, and turn-counter invariants.
452
- */
453
- getOrCreateToolOutputRegistry() {
454
- if (this.toolOutputReferences?.enabled !== true) {
455
- return undefined;
456
- }
457
- if (this._toolOutputRegistry == null) {
458
- this._toolOutputRegistry = new ToolOutputReferenceRegistry({
459
- maxOutputSize: this.toolOutputReferences.maxOutputSize,
460
- maxTotalSize: this.toolOutputReferences.maxTotalSize,
461
- });
462
- }
463
- return this._toolOutputRegistry;
464
- }
465
- /**
466
- * Single per-Run file checkpointer shared across every ToolNode the
467
- * graph compiles. Lazily constructed when
468
- * `toolExecution.local.fileCheckpointing === true` or
469
- * `toolExecution.cloudflare.fileCheckpointing === true` so
470
- * multi-agent graphs see ONE snapshot store, not one-per-agent.
471
- * Returns undefined when checkpointing is disabled or a supported
472
- * coding-tool engine isn't selected. Exposed via
473
- * `Run.getFileCheckpointer()` / `Run.rewindFiles()`.
474
- */
475
- _fileCheckpointer;
476
- /**
477
- * ToolNodes compiled into this Graph's workflow. Tracked so
478
- * `clearHeavyState()` can flush their per-Run direct-path turn
479
- * cache (`directPathTurns`) at end-of-Run — that map intentionally
480
- * survives `run()` re-entry (resume-stable per Codex P2 #30) but
481
- * would otherwise grow linearly with tool calls and could collide
482
- * across Runs if a provider reuses call ids (Codex P2 #33).
483
- */
484
- _compiledToolNodes = new Set();
485
- getOrCreateFileCheckpointer() {
486
- // Return the cached instance unconditionally if one exists. The
487
- // toolExecution check below decides whether to *create* a new
488
- // one — `clearHeavyState` nulls `this.toolExecution` at end-of-
489
- // Run, but we want post-Run `Run.rewindFiles()` to still resolve
490
- // to the checkpointer that captured the writes. Codex P1 #32.
491
- if (this._fileCheckpointer != null) {
492
- return this._fileCheckpointer;
493
- }
494
- // Eagerly create via the bundle factory so the construction path
495
- // matches the bundle-only callers (and future bundle-internal
496
- // cleanup hooks fire). The bundle factory itself accepts a pre-
497
- // supplied checkpointer when present, so re-injecting this one
498
- // into every ToolNode is idempotent.
499
- if (this.toolExecution?.engine === 'local' &&
500
- this.toolExecution.local?.fileCheckpointing === true) {
501
- const bundle = createLocalCodingToolBundle(this.toolExecution.local ?? {});
502
- this._fileCheckpointer = bundle.checkpointer;
503
- return this._fileCheckpointer;
504
- }
505
- if (this.toolExecution?.engine === 'cloudflare-sandbox' &&
506
- this.toolExecution.cloudflare?.fileCheckpointing === true) {
507
- const bundle = createCloudflareCodingToolBundle(this.toolExecution.cloudflare);
508
- this._fileCheckpointer = bundle.checkpointer;
509
- return this._fileCheckpointer;
510
- }
511
- return undefined;
512
- }
196
+ if (agentContext.tokenTypeSwitch !== "reasoning" || agentContext.currentTokenType === "text") return;
197
+ agentContext.currentTokenType = "text";
198
+ agentContext.tokenTypeSwitch = "content";
199
+ agentContext.reasoningTransitionCount++;
513
200
  }
514
- class StandardGraph extends Graph {
515
- overrideModel;
516
- /** Optional compile options passed into workflow.compile() */
517
- compileOptions;
518
- messages = [];
519
- /** Cached run messages preserved before clearHeavyState() so getRunMessages() works after cleanup. */
520
- cachedRunMessages;
521
- runId;
522
- /**
523
- * Boundary between historical messages (loaded from conversation state)
524
- * and messages produced during the current run. Set once in the state
525
- * reducer when messages first arrive. Used by `getRunMessages()` and
526
- * multi-agent message filtering — NOT for pruner token counting (the
527
- * pruner maintains its own `lastTurnStartIndex` in its closure).
528
- */
529
- startIndex = 0;
530
- signal;
531
- /** Map of agent contexts by agent ID */
532
- agentContexts = new Map();
533
- /** Default agent ID to use */
534
- defaultAgentId;
535
- constructor({ runId, signal, agents, langfuse, tokenCounter, indexTokenCountMap, calibrationRatio, }) {
536
- super();
537
- this.runId = runId;
538
- this.signal = signal;
539
- this.langfuse = langfuse;
540
- if (agents.length === 0) {
541
- throw new Error('At least one agent configuration is required');
542
- }
543
- for (const agentConfig of agents) {
544
- const agentContext = AgentContext.fromConfig(agentConfig, tokenCounter, indexTokenCountMap);
545
- if (calibrationRatio != null && calibrationRatio > 0) {
546
- agentContext.calibrationRatio = calibrationRatio;
547
- }
548
- this.agentContexts.set(agentConfig.agentId, agentContext);
549
- }
550
- this.defaultAgentId = agents[0].agentId;
551
- }
552
- /* Init */
553
- resetValues(keepContent) {
554
- this.messages = [];
555
- this.cachedRunMessages = undefined;
556
- this.config = resetIfNotEmpty(this.config, undefined);
557
- if (keepContent !== true) {
558
- this.contentData = resetIfNotEmpty(this.contentData, []);
559
- this.contentIndexMap = resetIfNotEmpty(this.contentIndexMap, new Map());
560
- }
561
- this.stepKeyIds = resetIfNotEmpty(this.stepKeyIds, new Map());
562
- /**
563
- * Clear in-place instead of replacing with a new Map to preserve the
564
- * shared reference held by ToolNode (passed at construction time).
565
- * Using resetIfNotEmpty would create a new Map, leaving ToolNode with
566
- * a stale reference on 2nd+ processStream calls.
567
- */
568
- this.toolCallStepIds.clear();
569
- this.eagerEventToolExecutions.clear();
570
- this.clearEagerEventToolUsageCounts();
571
- this.eagerEventToolCallChunks.clear();
572
- this.handlerDispatchedStepIds = resetIfNotEmpty(this.handlerDispatchedStepIds, new Set());
573
- this.handlerDispatchedEventCounts = resetIfNotEmpty(this.handlerDispatchedEventCounts, new Map());
574
- this.messageIdsByStepKey = resetIfNotEmpty(this.messageIdsByStepKey, new Map());
575
- this.messageStepHasToolCalls = resetIfNotEmpty(this.messageStepHasToolCalls, new Map());
576
- this.messageStepHasTextDeltas = resetIfNotEmpty(this.messageStepHasTextDeltas, new Set());
577
- this.reasoningStepHasDeltas = resetIfNotEmpty(this.reasoningStepHasDeltas, new Set());
578
- this.prelimMessageIdsByStepKey = resetIfNotEmpty(this.prelimMessageIdsByStepKey, new Map());
579
- this.invokedToolIds = resetIfNotEmpty(this.invokedToolIds, undefined);
580
- for (const context of this.agentContexts.values()) {
581
- context.reset();
582
- }
583
- }
584
- clearHeavyState() {
585
- this.cachedRunMessages = this.messages.slice(this.startIndex);
586
- super.clearHeavyState();
587
- this.messages = [];
588
- this.overrideModel = undefined;
589
- for (const context of this.agentContexts.values()) {
590
- context.reset();
591
- }
592
- }
593
- /* Run Step Processing */
594
- getRunStep(stepId) {
595
- const index = this.contentIndexMap.get(stepId);
596
- if (index !== undefined) {
597
- return this.contentData[index];
598
- }
599
- return undefined;
600
- }
601
- getAgentContext(metadata) {
602
- if (!metadata) {
603
- throw new Error('No metadata provided to retrieve agent context');
604
- }
605
- const currentNode = metadata.langgraph_node;
606
- if (!currentNode) {
607
- throw new Error('No langgraph_node in metadata to retrieve agent context');
608
- }
609
- let agentId;
610
- if (currentNode.startsWith(AGENT)) {
611
- agentId = currentNode.substring(AGENT.length);
612
- }
613
- else if (currentNode.startsWith(TOOLS)) {
614
- agentId = currentNode.substring(TOOLS.length);
615
- }
616
- else if (currentNode.startsWith(SUMMARIZE)) {
617
- agentId = currentNode.substring(SUMMARIZE.length);
618
- }
619
- const agentContext = this.agentContexts.get(agentId ?? '');
620
- if (!agentContext) {
621
- throw new Error(`No agent context found for agent ID ${agentId}`);
622
- }
623
- return agentContext;
624
- }
625
- getStepBaseKey(metadata) {
626
- if (!metadata)
627
- return '';
628
- const keyList = this.getInvocationKeyList(metadata);
629
- if (this.checkKeyList(keyList)) {
630
- throw new Error('Missing metadata');
631
- }
632
- return joinKeys(keyList);
633
- }
634
- getStepKey(metadata) {
635
- if (!metadata)
636
- return '';
637
- const keyList = this.getKeyList(metadata);
638
- if (this.checkKeyList(keyList)) {
639
- throw new Error('Missing metadata');
640
- }
641
- return joinKeys(keyList);
642
- }
643
- getStepIdByKey(stepKey, index) {
644
- const stepIds = this.stepKeyIds.get(stepKey);
645
- if (!stepIds) {
646
- throw new Error(`No step IDs found for stepKey ${stepKey}`);
647
- }
648
- if (index === undefined) {
649
- return stepIds[stepIds.length - 1];
650
- }
651
- return stepIds[index];
652
- }
653
- generateStepId(stepKey) {
654
- const stepIds = this.stepKeyIds.get(stepKey);
655
- let newStepId;
656
- let stepIndex = 0;
657
- if (stepIds) {
658
- stepIndex = stepIds.length;
659
- newStepId = `step_${nanoid()}`;
660
- stepIds.push(newStepId);
661
- this.stepKeyIds.set(stepKey, stepIds);
662
- }
663
- else {
664
- newStepId = `step_${nanoid()}`;
665
- this.stepKeyIds.set(stepKey, [newStepId]);
666
- }
667
- return [newStepId, stepIndex];
668
- }
669
- getKeyList(metadata) {
670
- if (!metadata)
671
- return [];
672
- const keyList = this.getInvocationKeyList(metadata);
673
- const agentContext = this.getAgentContext(metadata);
674
- if (agentContext.currentTokenType === ContentTypes.THINK ||
675
- agentContext.currentTokenType === 'think_and_text') {
676
- keyList.push('reasoning');
677
- }
678
- else if (agentContext.tokenTypeSwitch === 'content') {
679
- keyList.push(`post-reasoning-${agentContext.reasoningTransitionCount}`);
680
- }
681
- return keyList;
682
- }
683
- getInvocationKeyList(metadata) {
684
- const keyList = this.getBaseKeyList(metadata);
685
- if (this.invokedToolIds != null && this.invokedToolIds.size > 0) {
686
- keyList.push(this.invokedToolIds.size + '');
687
- }
688
- return keyList;
689
- }
690
- getBaseKeyList(metadata) {
691
- const configurable = this.config?.configurable;
692
- const runId = metadata.run_id ??
693
- configurable?.run_id ??
694
- this.runId;
695
- const threadId = metadata.thread_id ??
696
- configurable?.thread_id ??
697
- runId;
698
- const checkpointNs = metadata.checkpoint_ns ??
699
- metadata.langgraph_checkpoint_ns ??
700
- '';
701
- const keyList = [
702
- runId,
703
- threadId,
704
- metadata.langgraph_node,
705
- metadata.langgraph_step,
706
- checkpointNs,
707
- ];
708
- return keyList;
709
- }
710
- checkKeyList(keyList) {
711
- return keyList.some((key) => key === undefined);
712
- }
713
- /* Misc.*/
714
- getRunMessages() {
715
- if (this.messages.length === 0 && this.cachedRunMessages != null) {
716
- return this.cachedRunMessages;
717
- }
718
- return this.messages.slice(this.startIndex);
719
- }
720
- getContentParts() {
721
- return convertMessagesToContent(this.messages.slice(this.startIndex));
722
- }
723
- getCalibrationRatio() {
724
- const context = this.agentContexts.get(this.defaultAgentId);
725
- return context?.calibrationRatio ?? 1;
726
- }
727
- getResolvedInstructionOverhead() {
728
- const context = this.agentContexts.get(this.defaultAgentId);
729
- return context?.resolvedInstructionOverhead;
730
- }
731
- getToolCount() {
732
- const context = this.agentContexts.get(this.defaultAgentId);
733
- return ((context?.tools?.length ?? 0) + (context?.toolDefinitions?.length ?? 0));
734
- }
735
- /**
736
- * Get all run steps, optionally filtered by agent ID
737
- */
738
- getRunSteps(agentId) {
739
- if (agentId == null || agentId === '') {
740
- return [...this.contentData];
741
- }
742
- return this.contentData.filter((step) => step.agentId === agentId);
743
- }
744
- /**
745
- * Get run steps grouped by agent ID
746
- */
747
- getRunStepsByAgent() {
748
- const stepsByAgent = new Map();
749
- for (const step of this.contentData) {
750
- if (step.agentId == null || step.agentId === '')
751
- continue;
752
- const steps = stepsByAgent.get(step.agentId) ?? [];
753
- steps.push(step);
754
- stepsByAgent.set(step.agentId, steps);
755
- }
756
- return stepsByAgent;
757
- }
758
- /**
759
- * Get agent IDs that participated in this run
760
- */
761
- getActiveAgentIds() {
762
- const agentIds = new Set();
763
- for (const step of this.contentData) {
764
- if (step.agentId != null && step.agentId !== '') {
765
- agentIds.add(step.agentId);
766
- }
767
- }
768
- return Array.from(agentIds);
769
- }
770
- /**
771
- * Maps contentPart indices to agent IDs for post-run analysis
772
- * Returns a map where key is the contentPart index and value is the agentId
773
- */
774
- getContentPartAgentMap() {
775
- const contentPartAgentMap = new Map();
776
- for (const step of this.contentData) {
777
- if (step.agentId != null &&
778
- step.agentId !== '' &&
779
- Number.isFinite(step.index)) {
780
- contentPartAgentMap.set(step.index, step.agentId);
781
- }
782
- }
783
- return contentPartAgentMap;
784
- }
785
- /* Graph */
786
- initializeTools({ currentTools, currentToolMap, agentContext, }) {
787
- const toolDefinitions = agentContext?.toolDefinitions;
788
- const eventDrivenMode = toolDefinitions != null && toolDefinitions.length > 0;
789
- const traceToolNode = shouldTraceToolNodeForLangfuse({
790
- runLangfuse: this.langfuse,
791
- agentLangfuse: agentContext?.langfuse,
792
- });
793
- if (eventDrivenMode) {
794
- const schemaTools = createSchemaOnlyTools(toolDefinitions);
795
- const toolDefMap = new Map(toolDefinitions.map((def) => [def.name, def]));
796
- const graphTools = agentContext?.graphTools;
797
- const directToolNames = new Set();
798
- const allTools = [...schemaTools];
799
- const allToolMap = new Map(schemaTools.map((tool) => [tool.name, tool]));
800
- if (graphTools && graphTools.length > 0) {
801
- for (const tool of graphTools) {
802
- if ('name' in tool) {
803
- allTools.push(tool);
804
- allToolMap.set(tool.name, tool);
805
- directToolNames.add(tool.name);
806
- }
807
- }
808
- }
809
- const node = new ToolNode({
810
- tools: allTools,
811
- toolMap: allToolMap,
812
- trace: traceToolNode,
813
- runLangfuse: this.langfuse,
814
- agentLangfuse: agentContext?.langfuse,
815
- eventDrivenMode: true,
816
- sessions: this.sessions,
817
- toolDefinitions: toolDefMap,
818
- agentId: agentContext?.agentId,
819
- executingAgentId: agentContext?.agentId,
820
- toolCallStepIds: this.toolCallStepIds,
821
- toolRegistry: agentContext?.toolRegistry,
822
- hookRegistry: this.hookRegistry,
823
- humanInTheLoop: this.humanInTheLoop,
824
- eagerEventToolExecution: this.eagerEventToolExecution,
825
- eagerEventToolExecutions: this.eagerEventToolExecutions,
826
- eagerEventToolUsageCount: this.getEagerEventToolUsageCount(agentContext?.agentId),
827
- toolExecution: this.toolExecution,
828
- directToolNames: directToolNames.size > 0 ? directToolNames : undefined,
829
- maxContextTokens: agentContext?.maxContextTokens,
830
- maxToolResultChars: agentContext?.maxToolResultChars,
831
- toolOutputRegistry: this.getOrCreateToolOutputRegistry(),
832
- fileCheckpointer: this.getOrCreateFileCheckpointer(),
833
- errorHandler: (data, metadata) => StandardGraph.handleToolCallErrorStatic(this, data, metadata),
834
- });
835
- this.registerCompiledToolNode(node);
836
- return node;
837
- }
838
- const graphTools = agentContext?.graphTools;
839
- const baseTools = currentTools ?? [];
840
- const allTraditionalTools = graphTools && graphTools.length > 0
841
- ? [...baseTools, ...graphTools]
842
- : baseTools;
843
- const traditionalToolMap = graphTools && graphTools.length > 0
844
- ? new Map([
845
- ...(currentToolMap ?? new Map()),
846
- ...graphTools
847
- .filter((t) => 'name' in t)
848
- .map((t) => [t.name, t]),
849
- ])
850
- : currentToolMap;
851
- const node = new ToolNode({
852
- tools: allTraditionalTools,
853
- toolMap: traditionalToolMap,
854
- trace: traceToolNode,
855
- runLangfuse: this.langfuse,
856
- agentLangfuse: agentContext?.langfuse,
857
- // `agentId` is intentionally left unset on this path (it is the
858
- // subagent-scope marker); `executingAgentId` always identifies the owning
859
- // agent so hooks can attribute the batch even at the top level.
860
- executingAgentId: agentContext?.agentId,
861
- toolCallStepIds: this.toolCallStepIds,
862
- errorHandler: (data, metadata) => StandardGraph.handleToolCallErrorStatic(this, data, metadata),
863
- toolRegistry: agentContext?.toolRegistry,
864
- sessions: this.sessions,
865
- toolExecution: this.toolExecution,
866
- hookRegistry: this.hookRegistry,
867
- humanInTheLoop: this.humanInTheLoop,
868
- maxContextTokens: agentContext?.maxContextTokens,
869
- maxToolResultChars: agentContext?.maxToolResultChars,
870
- toolOutputRegistry: this.getOrCreateToolOutputRegistry(),
871
- fileCheckpointer: this.getOrCreateFileCheckpointer(),
872
- });
873
- this.registerCompiledToolNode(node);
874
- return node;
875
- }
876
- overrideTestModel(responses, sleep, toolCalls) {
877
- this.overrideModel = createFakeStreamingLLM({
878
- responses,
879
- sleep,
880
- toolCalls,
881
- });
882
- }
883
- getUsageMetadata(finalMessage) {
884
- if (finalMessage &&
885
- 'usage_metadata' in finalMessage &&
886
- finalMessage.usage_metadata != null) {
887
- return finalMessage.usage_metadata;
888
- }
889
- }
890
- cleanupSignalListener(currentModel) {
891
- if (!this.signal) {
892
- return;
893
- }
894
- const model = this.overrideModel ?? currentModel;
895
- if (!model) {
896
- return;
897
- }
898
- const client = model?.exposedClient;
899
- if (!client?.abortHandler) {
900
- return;
901
- }
902
- this.signal.removeEventListener('abort', client.abortHandler);
903
- client.abortHandler = undefined;
904
- }
905
- createCallModel(agentId = 'default') {
906
- return async (state, config) => {
907
- const agentContext = this.agentContexts.get(agentId);
908
- if (!agentContext) {
909
- throw new Error(`Agent context not found for agentId: ${agentId}`);
910
- }
911
- if (!config) {
912
- throw new Error('No config provided');
913
- }
914
- const { messages } = state;
915
- const discoveredNames = extractToolDiscoveries(messages);
916
- if (discoveredNames.length > 0) {
917
- agentContext.markToolsAsDiscovered(discoveredNames);
918
- }
919
- const rawToolsForBinding = resolveLocalToolsForBinding({
920
- tools: agentContext.getToolsForBinding(),
921
- toolExecution: this.toolExecution,
922
- });
923
- /**
924
- * Anthropic prompt-cache breakpoint on the tool definitions.
925
- *
926
- * Without this, the (often static) tool inventory shows up as
927
- * fresh input on every turn — measured at ~28k tokens/turn for
928
- * the local engine's coding-tool bundle, dominating per-turn
929
- * cost even when message-level caching is on.
930
- *
931
- * Strategy: partition tools into [static, deferred] and stamp
932
- * `cache_control: ephemeral` on the last static tool.
933
- * Discovered deferred tools that arrive across turns sit *after*
934
- * the breakpoint and don't invalidate the prefix.
935
- */
936
- let toolsForBinding = rawToolsForBinding;
937
- if (agentContext.provider === Providers.ANTHROPIC &&
938
- agentContext.clientOptions
939
- ?.promptCache === true) {
940
- toolsForBinding =
941
- partitionAndMarkAnthropicToolCache(rawToolsForBinding, makeIsDeferred(agentContext.toolDefinitions)) ?? rawToolsForBinding;
942
- }
943
- else if (agentContext.provider === Providers.OPENROUTER &&
944
- agentContext.clientOptions?.promptCache === true) {
945
- toolsForBinding =
946
- partitionAndMarkOpenRouterToolCache(rawToolsForBinding, makeIsDeferred(agentContext.toolDefinitions)) ?? rawToolsForBinding;
947
- }
948
- else if (agentContext.provider === Providers.BEDROCK &&
949
- agentContext.clientOptions?.promptCache === true) {
950
- toolsForBinding =
951
- partitionAndMarkBedrockToolCache(rawToolsForBinding, makeIsDeferred(agentContext.toolDefinitions)) ?? rawToolsForBinding;
952
- }
953
- let model = this.overrideModel ??
954
- initializeModel({
955
- tools: toolsForBinding,
956
- provider: agentContext.provider,
957
- clientOptions: agentContext.clientOptions,
958
- });
959
- if (agentContext.systemRunnable) {
960
- model = agentContext.systemRunnable.pipe(model);
961
- }
962
- if (agentContext.tokenCalculationPromise) {
963
- await agentContext.tokenCalculationPromise;
964
- }
965
- if (!config.signal) {
966
- config.signal = this.signal;
967
- }
968
- this.config = config;
969
- let messagesToUse = messages;
970
- if (!agentContext.pruneMessages &&
971
- agentContext.tokenCounter &&
972
- agentContext.maxContextTokens != null) {
973
- agentContext.pruneMessages = createPruneMessages({
974
- startIndex: agentContext.indexTokenCountMap[0] != null ? this.startIndex : 0,
975
- provider: agentContext.provider,
976
- tokenCounter: agentContext.tokenCounter,
977
- maxTokens: agentContext.maxContextTokens,
978
- thinkingEnabled: isThinkingEnabled(agentContext.provider, agentContext.clientOptions),
979
- indexTokenCountMap: agentContext.indexTokenCountMap,
980
- contextPruningConfig: agentContext.contextPruningConfig,
981
- summarizationEnabled: agentContext.summarizationEnabled,
982
- reserveRatio: agentContext.summarizationConfig?.reserveRatio,
983
- calibrationRatio: agentContext.calibrationRatio,
984
- getInstructionTokens: () => agentContext.instructionTokens,
985
- log: (level, message, data) => {
986
- emitAgentLog(config, level, 'prune', message, data, {
987
- runId: this.runId,
988
- agentId,
989
- });
990
- },
991
- });
992
- }
993
- if (agentContext.pruneMessages) {
994
- const { context, indexTokenCountMap, messagesToRefine, prePruneContextTokens, remainingContextTokens, originalToolContent, calibrationRatio, resolvedInstructionOverhead, } = agentContext.pruneMessages({
995
- messages,
996
- usageMetadata: agentContext.currentUsage,
997
- lastCallUsage: agentContext.lastCallUsage,
998
- totalTokensFresh: agentContext.totalTokensFresh,
999
- });
1000
- agentContext.indexTokenCountMap = indexTokenCountMap;
1001
- if (calibrationRatio != null && calibrationRatio > 0) {
1002
- agentContext.calibrationRatio = calibrationRatio;
1003
- }
1004
- if (resolvedInstructionOverhead != null) {
1005
- agentContext.resolvedInstructionOverhead =
1006
- resolvedInstructionOverhead;
1007
- const nonToolOverhead = agentContext.instructionTokens - agentContext.toolSchemaTokens;
1008
- const calibratedToolTokens = Math.max(0, resolvedInstructionOverhead - nonToolOverhead);
1009
- const currentToolTokens = agentContext.toolSchemaTokens;
1010
- const variance = currentToolTokens > 0
1011
- ? Math.abs(calibratedToolTokens - currentToolTokens) /
1012
- currentToolTokens
1013
- : 1;
1014
- if (variance > CALIBRATION_VARIANCE_THRESHOLD) {
1015
- agentContext.toolSchemaTokens = calibratedToolTokens;
1016
- }
1017
- }
1018
- messagesToUse = context;
1019
- const hasPrunedMessages = agentContext.summarizationEnabled === true &&
1020
- Array.isArray(messagesToRefine) &&
1021
- messagesToRefine.length > 0;
1022
- if (hasPrunedMessages) {
1023
- const shouldSkip = agentContext.shouldSkipSummarization(messages.length);
1024
- const triggerResult = !shouldSkip &&
1025
- shouldTriggerSummarization({
1026
- trigger: agentContext.summarizationConfig?.trigger,
1027
- maxContextTokens: agentContext.maxContextTokens,
1028
- prePruneContextTokens: prePruneContextTokens != null
1029
- ? prePruneContextTokens + agentContext.instructionTokens
1030
- : undefined,
1031
- remainingContextTokens,
1032
- messagesToRefineCount: messagesToRefine.length,
1033
- });
1034
- if (triggerResult) {
1035
- if (originalToolContent != null && originalToolContent.size > 0) {
1036
- /**
1037
- * Merge — never overwrite — the pruner's masking record
1038
- * into pendingOriginalToolContent. Carry-over entries
1039
- * from a prior summarize (preserved by the recency
1040
- * window for masked tool messages still in the tail) and
1041
- * the current pruner's new entries are both keyed by
1042
- * indices in the current `state.messages`, so a key-wise
1043
- * union is correct. Overwriting would discard the
1044
- * carry-over and reduce summary fidelity when those
1045
- * masked tail messages eventually move into the head.
1046
- */
1047
- if (agentContext.pendingOriginalToolContent == null) {
1048
- agentContext.pendingOriginalToolContent = originalToolContent;
1049
- }
1050
- else {
1051
- for (const [idx, content] of originalToolContent) {
1052
- agentContext.pendingOriginalToolContent.set(idx, content);
1053
- }
1054
- /**
1055
- * Re-apply the per-store char cap after the union. The
1056
- * pruner enforces ORIGINAL_CONTENT_MAX_CHARS inside its
1057
- * own map via the onContentStored callback, but a
1058
- * key-wise merge with recency carry-over bypasses that
1059
- * accounting and could let the merged map grow without
1060
- * bound across long sessions.
1061
- */
1062
- enforceOriginalContentCap(agentContext.pendingOriginalToolContent);
1063
- }
1064
- }
1065
- emitAgentLog(config, 'info', 'graph', 'Summarization triggered', undefined, { runId: this.runId, agentId });
1066
- emitAgentLog(config, 'debug', 'graph', 'Summarization trigger details', {
1067
- totalMessages: messages.length,
1068
- remainingContextTokens: remainingContextTokens ?? 0,
1069
- summaryVersion: agentContext.summaryVersion + 1,
1070
- toolSchemaTokens: agentContext.toolSchemaTokens,
1071
- instructionTokens: agentContext.instructionTokens,
1072
- systemMessageTokens: agentContext.systemMessageTokens,
1073
- }, { runId: this.runId, agentId });
1074
- agentContext.markSummarizationTriggered(messages.length);
1075
- return {
1076
- summarizationRequest: {
1077
- remainingContextTokens: remainingContextTokens ?? 0,
1078
- agentId: agentId || agentContext.agentId,
1079
- },
1080
- };
1081
- }
1082
- if (shouldSkip) {
1083
- emitAgentLog(config, 'debug', 'graph', 'Summarization skipped — no new messages or per-run cap reached', {
1084
- messageCount: messages.length,
1085
- messagesToRefineCount: messagesToRefine.length,
1086
- contextLength: context.length,
1087
- }, { runId: this.runId, agentId });
1088
- }
1089
- }
1090
- }
1091
- let finalMessages = messagesToUse;
1092
- if (agentContext.useLegacyContent) {
1093
- finalMessages = formatContentStrings(finalMessages);
1094
- }
1095
- const lastMessageX = finalMessages.length >= 2
1096
- ? finalMessages[finalMessages.length - 2]
1097
- : null;
1098
- const lastMessageY = finalMessages.length >= 1
1099
- ? finalMessages[finalMessages.length - 1]
1100
- : null;
1101
- const anthropicLike = isAnthropicLike(agentContext.provider, agentContext.clientOptions);
1102
- if (agentContext.provider === Providers.BEDROCK &&
1103
- lastMessageX instanceof AIMessageChunk &&
1104
- lastMessageY instanceof ToolMessage &&
1105
- typeof lastMessageX.content === 'string') {
1106
- const trimmed = lastMessageX.content.trim();
1107
- finalMessages[finalMessages.length - 2].content =
1108
- trimmed.length > 0 ? [{ type: 'text', text: trimmed }] : '';
1109
- }
1110
- if (lastMessageY instanceof ToolMessage) {
1111
- if (anthropicLike) {
1112
- formatAnthropicArtifactContent(finalMessages);
1113
- }
1114
- else if ((isOpenAILike(agentContext.provider) &&
1115
- agentContext.provider !== Providers.DEEPSEEK) ||
1116
- isGoogleLike(agentContext.provider)) {
1117
- formatArtifactPayload(finalMessages);
1118
- }
1119
- }
1120
- if (agentContext.provider === Providers.ANTHROPIC) {
1121
- const anthropicOptions = agentContext.clientOptions;
1122
- if (anthropicOptions?.promptCache === true &&
1123
- !agentContext.systemRunnable) {
1124
- finalMessages = addCacheControl(finalMessages);
1125
- }
1126
- }
1127
- else if (agentContext.provider === Providers.BEDROCK) {
1128
- const bedrockOptions = agentContext.clientOptions;
1129
- if (bedrockOptions?.promptCache === true) {
1130
- finalMessages = addBedrockCacheControl(finalMessages);
1131
- }
1132
- }
1133
- else if (agentContext.provider === Providers.OPENROUTER) {
1134
- const openRouterOptions = agentContext.clientOptions;
1135
- if (openRouterOptions?.promptCache === true &&
1136
- !agentContext.systemRunnable) {
1137
- finalMessages = addCacheControl(finalMessages);
1138
- }
1139
- }
1140
- if (isThinkingEnabled(agentContext.provider, agentContext.clientOptions)) {
1141
- /**
1142
- * Pass `this.startIndex` so the function can distinguish CURRENT-run
1143
- * AI messages (the agent's own iterations — possibly without a
1144
- * leading thinking block, which Claude is allowed to skip) from
1145
- * historical context that genuinely needs the
1146
- * `[Previous agent context]` placeholder. Without this signal the
1147
- * function would convert the agent's own in-run tool_use messages,
1148
- * polluting the next iteration's prompt with a placeholder the
1149
- * model treats as suspicious injected content.
1150
- */
1151
- finalMessages = ensureThinkingBlockInMessages(finalMessages, agentContext.provider, config, this.startIndex);
1152
- }
1153
- // Intentionally broad: runs when the pruner wasn't used OR any post-pruning
1154
- // transform (addCacheControl, ensureThinkingBlock, etc.) reassigned finalMessages.
1155
- // sanitizeOrphanToolBlocks fast-paths to a Set diff check when no orphans exist,
1156
- // so the cost is negligible and this acts as a safety net for Anthropic/Bedrock.
1157
- const needsOrphanSanitize = anthropicLike &&
1158
- (!agentContext.pruneMessages || finalMessages !== messagesToUse);
1159
- if (needsOrphanSanitize) {
1160
- const beforeSanitize = finalMessages.length;
1161
- finalMessages = sanitizeOrphanToolBlocks(finalMessages);
1162
- if (finalMessages.length !== beforeSanitize) {
1163
- emitAgentLog(config, 'warn', 'sanitize', 'Orphan tool blocks removed', {
1164
- before: beforeSanitize,
1165
- after: finalMessages.length,
1166
- dropped: beforeSanitize - finalMessages.length,
1167
- }, { runId: this.runId, agentId });
1168
- }
1169
- }
1170
- if (agentContext.lastStreamCall != null &&
1171
- agentContext.streamBuffer != null) {
1172
- const timeSinceLastCall = Date.now() - agentContext.lastStreamCall;
1173
- if (timeSinceLastCall < agentContext.streamBuffer) {
1174
- const timeToWait = Math.ceil((agentContext.streamBuffer - timeSinceLastCall) / 1000) *
1175
- 1000;
1176
- await sleep(timeToWait);
1177
- }
1178
- }
1179
- agentContext.lastStreamCall = Date.now();
1180
- agentContext.markTokensStale();
1181
- let result;
1182
- const fallbacks = agentContext.clientOptions?.fallbacks ??
1183
- [];
1184
- if (finalMessages.length === 0 &&
1185
- !agentContext.hasPendingCompactionSummary()) {
1186
- const budgetBreakdown = agentContext.getTokenBudgetBreakdown(messages);
1187
- const breakdown = agentContext.formatTokenBudgetBreakdown(messages);
1188
- const instructionsExceedBudget = budgetBreakdown.instructionTokens > budgetBreakdown.maxContextTokens;
1189
- let guidance;
1190
- if (instructionsExceedBudget) {
1191
- const toolPct = budgetBreakdown.toolSchemaTokens > 0
1192
- ? Math.round((budgetBreakdown.toolSchemaTokens /
1193
- budgetBreakdown.instructionTokens) *
1194
- 100)
1195
- : 0;
1196
- guidance =
1197
- toolPct > 50
1198
- ? `Tool definitions consume ${budgetBreakdown.toolSchemaTokens} tokens (${toolPct}% of instructions) across ${budgetBreakdown.toolCount} tools, exceeding maxContextTokens (${budgetBreakdown.maxContextTokens}). Reduce the number of tools or increase maxContextTokens.`
1199
- : `Instructions (${budgetBreakdown.instructionTokens} tokens) exceed maxContextTokens (${budgetBreakdown.maxContextTokens}). Increase maxContextTokens or shorten the system prompt.`;
1200
- if (agentContext.summarizationEnabled === true) {
1201
- guidance +=
1202
- ' Summarization was skipped because the summary would further increase the instruction overhead.';
1203
- }
1204
- }
1205
- else {
1206
- guidance =
1207
- 'Please increase the context window size or make your message shorter.';
1208
- }
1209
- emitAgentLog(config, 'error', 'graph', 'Empty messages after pruning', {
1210
- messageCount: messages.length,
1211
- instructionsExceedBudget,
1212
- breakdown,
1213
- }, { runId: this.runId, agentId });
1214
- throw new Error(JSON.stringify({
1215
- type: 'empty_messages',
1216
- info: `Message pruning removed all messages as none fit in the context window. ${guidance}\n${breakdown}`,
1217
- }));
1218
- }
1219
- const invokeStart = Date.now();
1220
- const invokeMeta = { runId: this.runId, agentId };
1221
- emitAgentLog(config, 'debug', 'graph', 'Invoking LLM', {
1222
- messageCount: finalMessages.length,
1223
- provider: agentContext.provider,
1224
- }, invokeMeta, { force: true });
1225
- const langfuse = resolveLangfuseConfig(this.langfuse, agentContext.langfuse);
1226
- const traceMetadata = createLangfuseTraceMetadata({
1227
- messageId: this.runId,
1228
- parentMessageId: config.configurable?.requestBody?.parentMessageId,
1229
- agentId,
1230
- agentName: agentContext.name,
1231
- });
1232
- let langfuseHandler;
1233
- let invokeConfig = {
1234
- ...config,
1235
- metadata: {
1236
- ...(config.metadata ?? {}),
1237
- ...traceMetadata,
1238
- },
1239
- };
1240
- initializeLangfuseTracing(langfuse);
1241
- if (findCallback(config.callbacks, isLangfuseCallbackHandler) == null) {
1242
- langfuseHandler = createLangfuseHandler({
1243
- langfuse,
1244
- userId: config.configurable?.user_id,
1245
- sessionId: config.configurable?.thread_id,
1246
- traceMetadata,
1247
- tags: ['librechat', 'agent'],
1248
- });
1249
- if (langfuseHandler != null) {
1250
- invokeConfig = {
1251
- ...invokeConfig,
1252
- callbacks: appendCallbacks(invokeConfig.callbacks, [
1253
- langfuseHandler,
1254
- ]),
1255
- };
1256
- }
1257
- }
1258
- const metadata = config.metadata;
1259
- try {
1260
- result = await withLangfuseToolOutputTracingConfig(this.langfuse, () => attemptInvoke({
1261
- model: (this.overrideModel ?? model),
1262
- messages: finalMessages,
1263
- provider: agentContext.provider,
1264
- context: this,
1265
- }, invokeConfig), agentContext.langfuse);
1266
- }
1267
- catch (primaryError) {
1268
- clearCurrentDeltaStepMarkers({
1269
- graph: this,
1270
- metadata,
1271
- });
1272
- result = await withLangfuseToolOutputTracingConfig(this.langfuse, () => tryFallbackProviders({
1273
- fallbacks,
1274
- tools: agentContext.tools,
1275
- messages: finalMessages,
1276
- config: invokeConfig,
1277
- primaryError,
1278
- context: this,
1279
- }), agentContext.langfuse);
1280
- }
1281
- finally {
1282
- await disposeLangfuseHandler(langfuseHandler);
1283
- }
1284
- if (!result) {
1285
- throw new Error('No result after model invocation');
1286
- }
1287
- /**
1288
- * Fallback: populate toolCallStepIds in the graph execution context.
1289
- *
1290
- * When model.stream() is available (the common case), attemptInvoke
1291
- * processes all chunks through a local ChatModelStreamHandler which
1292
- * creates run steps and populates toolCallStepIds before returning.
1293
- * The code below is a fallback for the rare case where model.stream
1294
- * is unavailable and model.invoke() was used instead.
1295
- *
1296
- * Text content is dispatched FIRST so that MESSAGE_CREATION is the
1297
- * current step when handleToolCalls runs. handleToolCalls then creates
1298
- * TOOL_CALLS on top of it. The dedup in getMessageId and
1299
- * toolCallStepIds.has makes this safe when attemptInvoke already
1300
- * handled everything — both paths become no-ops.
1301
- */
1302
- const responseMessage = result.messages?.[0];
1303
- const toolCalls = responseMessage
1304
- ?.tool_calls;
1305
- const hasToolCalls = Array.isArray(toolCalls) && toolCalls.length > 0;
1306
- const responseReasoningContent = getResponseReasoningContent({
1307
- responseMessage: responseMessage,
1308
- reasoningKey: agentContext.reasoningKey,
1309
- });
1310
- const textMessageContent = getMessageDeltaContent(agentContext.provider, responseMessage?.content);
1311
- const hasStreamedTextDeltaStep = hasCurrentTextDeltaStep({
1312
- graph: this,
1313
- metadata,
1314
- });
1315
- const hasStreamedReasoningDeltaStep = hasCurrentReasoningDeltaStep({
1316
- graph: this,
1317
- metadata,
1318
- });
1319
- const dispatchableFinalReasoningContent = getDispatchableFinalReasoningContent({
1320
- agentContext,
1321
- responseReasoningContent,
1322
- hasStreamedTextDeltaStep,
1323
- hasStreamedReasoningDeltaStep,
1324
- });
1325
- if (hasToolCalls) {
1326
- const dispatchedReasoning = dispatchableFinalReasoningContent != null &&
1327
- (await dispatchReasoningContent({
1328
- graph: this,
1329
- agentContext,
1330
- reasoningContent: dispatchableFinalReasoningContent,
1331
- metadata,
1332
- }));
1333
- if (dispatchedReasoning) {
1334
- markPostReasoningContent(agentContext);
1335
- }
1336
- if (textMessageContent != null && !hasStreamedTextDeltaStep) {
1337
- const stepKey = this.getStepKey(metadata);
1338
- const dispatchedText = await dispatchTextMessageContent({
1339
- graph: this,
1340
- stepKey,
1341
- provider: agentContext.provider,
1342
- content: textMessageContent,
1343
- metadata,
1344
- });
1345
- if (dispatchedText) {
1346
- markPostReasoningContent(agentContext);
1347
- }
1348
- }
1349
- await handleToolCalls(toolCalls, metadata, this);
1350
- }
1351
- /**
1352
- * When streaming events are unavailable, ChatModelStreamHandler never
1353
- * fires. Dispatch final reasoning/text content here. getMessageId makes
1354
- * this a no-op when the streaming path already handled the same step.
1355
- */
1356
- if (!hasToolCalls && responseMessage != null) {
1357
- const dispatchedReasoning = dispatchableFinalReasoningContent != null &&
1358
- (await dispatchReasoningContent({
1359
- graph: this,
1360
- agentContext,
1361
- reasoningContent: dispatchableFinalReasoningContent,
1362
- metadata,
1363
- }));
1364
- if (dispatchedReasoning && textMessageContent != null) {
1365
- markPostReasoningContent(agentContext);
1366
- }
1367
- if (textMessageContent != null && !hasStreamedTextDeltaStep) {
1368
- const stepKey = this.getStepKey(metadata);
1369
- await dispatchTextMessageContent({
1370
- graph: this,
1371
- stepKey,
1372
- provider: agentContext.provider,
1373
- content: textMessageContent,
1374
- metadata,
1375
- });
1376
- }
1377
- }
1378
- const invokeElapsed = ((Date.now() - invokeStart) / 1000).toFixed(2);
1379
- agentContext.currentUsage = this.getUsageMetadata(result.messages?.[0]);
1380
- if (agentContext.currentUsage) {
1381
- agentContext.updateLastCallUsage(agentContext.currentUsage);
1382
- emitAgentLog(config, 'debug', 'graph', `LLM call complete (${invokeElapsed}s)`, {
1383
- ...agentContext.currentUsage,
1384
- elapsedSeconds: Number(invokeElapsed),
1385
- instructionTokens: agentContext.instructionTokens,
1386
- toolSchemaTokens: agentContext.toolSchemaTokens,
1387
- messageCount: finalMessages.length,
1388
- }, invokeMeta, { force: true });
1389
- }
1390
- else {
1391
- emitAgentLog(config, 'debug', 'graph', `LLM call complete (${invokeElapsed}s)`, {
1392
- elapsedSeconds: Number(invokeElapsed),
1393
- messageCount: finalMessages.length,
1394
- }, invokeMeta, { force: true });
1395
- }
1396
- this.cleanupSignalListener();
1397
- return result;
1398
- };
1399
- }
1400
- createAgentNode(agentId) {
1401
- const getConfig = () => this.config;
1402
- const agentContext = this.agentContexts.get(agentId);
1403
- if (!agentContext) {
1404
- throw new Error(`Agent context not found for agentId: ${agentId}`);
1405
- }
1406
- /**
1407
- * Depth countdown across graph boundaries: the parent's `maxSubagentDepth`
1408
- * becomes this executor's `maxDepth`. When the child graph is constructed,
1409
- * `buildChildInputs()` decrements `maxSubagentDepth` on the child's
1410
- * `AgentInputs` (only when `allowNested: true`; otherwise subagentConfigs
1411
- * are stripped entirely). The child graph's own `createAgentNode()` then
1412
- * reads the decremented value here and creates a narrower executor —
1413
- * recursion is bounded even though each graph has its own separate
1414
- * executor instance.
1415
- */
1416
- const effectiveSubagentDepth = agentContext.maxSubagentDepth ?? 1;
1417
- if (agentContext.subagentConfigs != null &&
1418
- agentContext.subagentConfigs.length > 0 &&
1419
- effectiveSubagentDepth > 0) {
1420
- const resolvedConfigs = resolveSubagentConfigs(agentContext.subagentConfigs, agentContext);
1421
- if (resolvedConfigs.length > 0) {
1422
- const getParentHandlerRegistry = () => this.handlerRegistry;
1423
- const executor = new SubagentExecutor({
1424
- configs: new Map(resolvedConfigs.map((c) => [c.type, c])),
1425
- parentSignal: this.signal,
1426
- hookRegistry: this.hookRegistry,
1427
- /** Lazy — Run wires the registry onto the graph AFTER
1428
- * `createWorkflow()` runs, so a direct capture here would be
1429
- * `undefined` at construction time. */
1430
- parentHandlerRegistry: getParentHandlerRegistry,
1431
- parentRunId: this.runId ?? '',
1432
- parentAgentId: agentContext.agentId,
1433
- langfuse: this.langfuse,
1434
- tokenCounter: agentContext.tokenCounter,
1435
- maxDepth: effectiveSubagentDepth,
1436
- createChildGraph: (input) => {
1437
- const childGraph = new StandardGraph(input);
1438
- childGraph.hookRegistry = this.hookRegistry;
1439
- /**
1440
- * Do not propagate `humanInTheLoop` into the child graph yet:
1441
- * nested subagent interrupts need a stable child checkpoint and
1442
- * resume bridge. Child hooks still fire; `ask` decisions fail
1443
- * closed inside the subagent until that flow is implemented.
1444
- */
1445
- childGraph.toolOutputReferences = this.toolOutputReferences;
1446
- childGraph.eagerEventToolExecution = this.eagerEventToolExecution;
1447
- childGraph.toolExecution = this.toolExecution;
1448
- childGraph.eventToolExecutionAvailable =
1449
- this.handlerRegistry?.getHandler(GraphEvents.ON_TOOL_EXECUTE) !=
1450
- null;
1451
- return childGraph;
1452
- },
1453
- });
1454
- const subagentTool = tool(async (rawInput, config) => {
1455
- const input = rawInput;
1456
- const description = typeof input.description === 'string' &&
1457
- input.description.trim().length > 0
1458
- ? input.description
1459
- : 'No task description provided';
1460
- const subagentType = typeof input.subagent_type === 'string' ? input.subagent_type : '';
1461
- const threadId = config.configurable?.thread_id;
1462
- /**
1463
- * When the tool is dispatched from an LLM's `tool_call`, LangChain
1464
- * threads the originating `ToolCall` onto the RunnableConfig as
1465
- * `config.toolCall` (see `ToolRunnableConfig` in
1466
- * `@langchain/core/tools` — internal but stable since ≥0.3.x).
1467
- * Surfacing its id lets hosts correlate `SubagentUpdateEvent`s
1468
- * back to the parent's `tool_call_id` deterministically — no
1469
- * temporal heuristics needed. If a future LangChain version
1470
- * changes the threading, the type-guarded read falls back to
1471
- * `undefined` and the correlation degrades gracefully.
1472
- */
1473
- const toolCall = config.toolCall;
1474
- const parentToolCallId = typeof toolCall?.id === 'string' ? toolCall.id : undefined;
1475
- const result = await executor.execute({
1476
- description,
1477
- subagentType,
1478
- threadId,
1479
- parentToolCallId,
1480
- /**
1481
- * Forward the parent's `configurable` so host-set fields
1482
- * (`requestBody`, `user`, etc.) propagate into the child
1483
- * workflow. The executor scrubs run-identity fields before
1484
- * forwarding — see `SubagentExecuteParams.parentConfigurable`.
1485
- */
1486
- parentConfigurable: config.configurable,
1487
- });
1488
- return result.content;
1489
- }, buildSubagentToolParams(resolvedConfigs));
1490
- if (!agentContext.graphTools) {
1491
- agentContext.graphTools = [];
1492
- }
1493
- agentContext.graphTools.push(subagentTool);
1494
- /**
1495
- * Refresh toolSchemaTokens to include the subagent tool's schema.
1496
- * `calculateInstructionTokens()` was kicked off in `fromConfig()`
1497
- * before graphTools was populated, so its result did not count this
1498
- * tool. Without this retrigger, token-budget/pruning logic
1499
- * underestimates prompt overhead.
1500
- */
1501
- if (agentContext.tokenCounter) {
1502
- const { tokenCounter, baseIndexTokenCountMap } = agentContext;
1503
- agentContext.tokenCalculationPromise = agentContext
1504
- .calculateInstructionTokens(tokenCounter)
1505
- .then(() => {
1506
- agentContext.updateTokenMapWithInstructions(baseIndexTokenCountMap);
1507
- })
1508
- .catch((err) => {
1509
- console.error('Error recalculating instruction tokens after subagent tool injection:', err);
1510
- });
1511
- }
1512
- }
1513
- }
1514
- const agentNode = `${AGENT}${agentId}`;
1515
- const toolNode = `${TOOLS}${agentId}`;
1516
- const summarizeNode = `${SUMMARIZE}${agentId}`;
1517
- const routeMessage = (state, config) => {
1518
- this.config = config;
1519
- if (state.summarizationRequest != null) {
1520
- return summarizeNode;
1521
- }
1522
- return toolsCondition(state, toolNode, this.invokedToolIds);
1523
- };
1524
- const StateAnnotation = Annotation.Root({
1525
- messages: Annotation({
1526
- reducer: messagesStateReducer,
1527
- default: () => [],
1528
- }),
1529
- summarizationRequest: Annotation({
1530
- reducer: (_, b) => b,
1531
- default: () => undefined,
1532
- }),
1533
- });
1534
- const workflow = new StateGraph(StateAnnotation)
1535
- .addNode(agentNode, this.createCallModel(agentId))
1536
- .addNode(toolNode, this.initializeTools({
1537
- currentTools: agentContext.tools,
1538
- currentToolMap: agentContext.toolMap,
1539
- agentContext,
1540
- }))
1541
- .addNode(summarizeNode, createSummarizeNode({
1542
- agentContext,
1543
- graph: {
1544
- contentData: this.contentData,
1545
- contentIndexMap: this.contentIndexMap,
1546
- get config() {
1547
- return getConfig();
1548
- },
1549
- runId: this.runId,
1550
- isMultiAgent: this.isMultiAgentGraph(),
1551
- hookRegistry: this.hookRegistry,
1552
- dispatchRunStep: async (runStep, nodeConfig) => {
1553
- this.contentData.push(runStep);
1554
- this.contentIndexMap.set(runStep.id, runStep.index);
1555
- const resolvedConfig = nodeConfig ?? this.config;
1556
- const handler = this.handlerRegistry?.getHandler(GraphEvents.ON_RUN_STEP);
1557
- if (handler) {
1558
- await handler.handle(GraphEvents.ON_RUN_STEP, runStep, resolvedConfig?.configurable, this);
1559
- this.handlerDispatchedStepIds.add(runStep.id);
1560
- }
1561
- const unmarkHandlerDispatchedEvent = handler
1562
- ? this.markHandlerDispatchedEvent(GraphEvents.ON_RUN_STEP, runStep.id)
1563
- : undefined;
1564
- try {
1565
- if (resolvedConfig) {
1566
- await safeDispatchCustomEvent(GraphEvents.ON_RUN_STEP, runStep, resolvedConfig);
1567
- }
1568
- }
1569
- finally {
1570
- unmarkHandlerDispatchedEvent?.();
1571
- }
1572
- },
1573
- dispatchRunStepCompleted: async (stepId, result, nodeConfig) => {
1574
- const resolvedConfig = nodeConfig ?? this.config;
1575
- const runStep = this.contentData.find((s) => s.id === stepId);
1576
- const handler = this.handlerRegistry?.getHandler(GraphEvents.ON_RUN_STEP_COMPLETED);
1577
- if (handler) {
1578
- await handler.handle(GraphEvents.ON_RUN_STEP_COMPLETED, {
1579
- result: {
1580
- ...result,
1581
- id: stepId,
1582
- index: runStep?.index ?? 0,
1583
- },
1584
- }, resolvedConfig?.configurable, this);
1585
- }
1586
- },
1587
- },
1588
- generateStepId: (stepKey) => this.generateStepId(stepKey),
1589
- }))
1590
- .addEdge(START, agentNode)
1591
- .addConditionalEdges(agentNode, routeMessage)
1592
- .addEdge(summarizeNode, agentNode)
1593
- .addEdge(toolNode, agentContext.toolEnd ? END : agentNode);
1594
- return workflow.compile();
1595
- }
1596
- createWorkflow() {
1597
- const agentNode = this.createAgentNode(this.defaultAgentId);
1598
- const StateAnnotation = Annotation.Root({
1599
- messages: Annotation({
1600
- reducer: (a, b) => {
1601
- if (!this.messages.length) {
1602
- this.startIndex = a.length + b.length;
1603
- }
1604
- const result = messagesStateReducer(a, b);
1605
- this.messages = result;
1606
- return result;
1607
- },
1608
- default: () => [],
1609
- }),
1610
- });
1611
- const workflow = new StateGraph(StateAnnotation)
1612
- .addNode(this.defaultAgentId, agentNode, { ends: [END] })
1613
- .addEdge(START, this.defaultAgentId)
1614
- // LangGraph compile() types are overly strict for opt-in options
1615
- .compile(this.compileOptions);
1616
- return workflow;
1617
- }
1618
- /**
1619
- * Indicates if this is a multi-agent graph.
1620
- * Override in MultiAgentGraph to return true.
1621
- * Used to conditionally include agentId in RunStep for frontend rendering.
1622
- */
1623
- isMultiAgentGraph() {
1624
- return false;
1625
- }
1626
- /**
1627
- * Get the parallel group ID for an agent, if any.
1628
- * Override in MultiAgentGraph to provide actual group IDs.
1629
- * Group IDs are incrementing numbers (1, 2, 3...) reflecting execution order.
1630
- * @param _agentId - The agent ID to look up
1631
- * @returns undefined for StandardGraph (no parallel groups), or group number for MultiAgentGraph
1632
- */
1633
- getParallelGroupIdForAgent(_agentId) {
1634
- return undefined;
1635
- }
1636
- /* Dispatchers */
1637
- /**
1638
- * Dispatches a run step to the client, returns the step ID
1639
- */
1640
- async dispatchRunStep(stepKey, stepDetails, metadata) {
1641
- if (!this.config) {
1642
- throw new Error('No config provided');
1643
- }
1644
- const [stepId, stepIndex] = this.generateStepId(stepKey);
1645
- if (stepDetails.type === StepTypes.TOOL_CALLS && stepDetails.tool_calls) {
1646
- for (const tool_call of stepDetails.tool_calls) {
1647
- const toolCallId = tool_call.id ?? '';
1648
- if (!toolCallId || this.toolCallStepIds.has(toolCallId)) {
1649
- continue;
1650
- }
1651
- this.toolCallStepIds.set(toolCallId, stepId);
1652
- }
1653
- }
1654
- const runStep = {
1655
- stepIndex,
1656
- id: stepId,
1657
- type: stepDetails.type,
1658
- index: this.contentData.length,
1659
- stepDetails,
1660
- usage: null,
1661
- };
1662
- const runId = this.runId ?? '';
1663
- if (runId) {
1664
- runStep.runId = runId;
1665
- }
1666
- if (metadata) {
1667
- try {
1668
- const agentContext = this.getAgentContext(metadata);
1669
- if (this.isMultiAgentGraph() && agentContext.agentId) {
1670
- runStep.agentId = agentContext.agentId;
1671
- const groupId = this.getParallelGroupIdForAgent(agentContext.agentId);
1672
- if (groupId != null) {
1673
- runStep.groupId = groupId;
1674
- }
1675
- }
1676
- }
1677
- catch (_e) {
1678
- /** If we can't get agent context, that's okay - agentId remains undefined */
1679
- }
1680
- }
1681
- this.contentData.push(runStep);
1682
- this.contentIndexMap.set(stepId, runStep.index);
1683
- // Primary dispatch: handler registry (reliable, always works).
1684
- // This mirrors how handleToolCallCompleted dispatches ON_RUN_STEP_COMPLETED
1685
- // via the handler registry, ensuring the event always reaches the handler
1686
- // even when LangGraph's callback system drops the custom event.
1687
- const handler = this.handlerRegistry?.getHandler(GraphEvents.ON_RUN_STEP);
1688
- if (handler) {
1689
- await handler.handle(GraphEvents.ON_RUN_STEP, runStep, metadata, this);
1690
- this.handlerDispatchedStepIds.add(stepId);
1691
- }
1692
- // Secondary dispatch: custom event for LangGraph callback chain
1693
- // (tracing, Langfuse, external consumers). May be silently dropped
1694
- // in some scenarios (stale run ID, subgraph callback propagation issues),
1695
- // but the primary dispatch above guarantees the event reaches the handler.
1696
- // The customEventCallback in run.ts skips events already dispatched above
1697
- // to prevent double handling.
1698
- const unmarkHandlerDispatchedEvent = handler
1699
- ? this.markHandlerDispatchedEvent(GraphEvents.ON_RUN_STEP, stepId)
1700
- : undefined;
1701
- try {
1702
- await safeDispatchCustomEvent(GraphEvents.ON_RUN_STEP, runStep, this.config);
1703
- }
1704
- finally {
1705
- unmarkHandlerDispatchedEvent?.();
1706
- }
1707
- return stepId;
1708
- }
1709
- /**
1710
- * Static version of handleToolCallError to avoid creating strong references
1711
- * that prevent garbage collection
1712
- */
1713
- static async handleToolCallErrorStatic(graph, data, metadata) {
1714
- if (!graph.config) {
1715
- throw new Error('No config provided');
1716
- }
1717
- if (!data.id) {
1718
- console.warn('No Tool ID provided for Tool Error');
1719
- return;
1720
- }
1721
- const stepId = graph.toolCallStepIds.get(data.id) ?? '';
1722
- if (!stepId) {
1723
- throw new Error(`No stepId found for tool_call_id ${data.id}`);
1724
- }
1725
- const { name, input: args, error } = data;
1726
- const runStep = graph.getRunStep(stepId);
1727
- if (!runStep) {
1728
- throw new Error(`No run step found for stepId ${stepId}`);
1729
- }
1730
- const tool_call = {
1731
- id: data.id,
1732
- name: name || '',
1733
- args: typeof args === 'string' ? args : JSON.stringify(args),
1734
- output: `Error processing tool${error?.message != null ? `: ${error.message}` : ''}`,
1735
- progress: 1,
1736
- };
1737
- await graph.handlerRegistry
1738
- ?.getHandler(GraphEvents.ON_RUN_STEP_COMPLETED)
1739
- ?.handle(GraphEvents.ON_RUN_STEP_COMPLETED, {
1740
- result: {
1741
- id: stepId,
1742
- index: runStep.index,
1743
- type: 'tool_call',
1744
- tool_call,
1745
- },
1746
- }, metadata, graph);
1747
- }
1748
- /**
1749
- * Instance method that delegates to the static method
1750
- * Kept for backward compatibility
1751
- */
1752
- async handleToolCallError(data, metadata) {
1753
- await StandardGraph.handleToolCallErrorStatic(this, data, metadata);
1754
- }
1755
- async dispatchRunStepDelta(id, delta, metadata) {
1756
- if (!this.config) {
1757
- throw new Error('No config provided');
1758
- }
1759
- else if (!id) {
1760
- throw new Error('No step ID found');
1761
- }
1762
- const runStepDelta = {
1763
- id,
1764
- delta,
1765
- };
1766
- const handler = this.handlerRegistry?.getHandler(GraphEvents.ON_RUN_STEP_DELTA);
1767
- if (handler) {
1768
- await handler.handle(GraphEvents.ON_RUN_STEP_DELTA, runStepDelta, metadata, this);
1769
- this.handlerDispatchedStepIds.add(id);
1770
- }
1771
- const unmarkHandlerDispatchedEvent = handler
1772
- ? this.markHandlerDispatchedEvent(GraphEvents.ON_RUN_STEP_DELTA, id)
1773
- : undefined;
1774
- try {
1775
- await safeDispatchCustomEvent(GraphEvents.ON_RUN_STEP_DELTA, runStepDelta, this.config);
1776
- }
1777
- finally {
1778
- unmarkHandlerDispatchedEvent?.();
1779
- }
1780
- }
1781
- async dispatchMessageDelta(id, delta, metadata) {
1782
- if (!this.config) {
1783
- throw new Error('No config provided');
1784
- }
1785
- const messageDelta = {
1786
- id,
1787
- delta,
1788
- };
1789
- if (hasTextDeltaContent(delta.content)) {
1790
- this.messageStepHasTextDeltas.add(id);
1791
- }
1792
- const handler = this.handlerRegistry?.getHandler(GraphEvents.ON_MESSAGE_DELTA);
1793
- if (handler) {
1794
- await handler.handle(GraphEvents.ON_MESSAGE_DELTA, messageDelta, metadata, this);
1795
- this.handlerDispatchedStepIds.add(id);
1796
- }
1797
- const unmarkHandlerDispatchedEvent = handler
1798
- ? this.markHandlerDispatchedEvent(GraphEvents.ON_MESSAGE_DELTA, id)
1799
- : undefined;
1800
- try {
1801
- await safeDispatchCustomEvent(GraphEvents.ON_MESSAGE_DELTA, messageDelta, this.config);
1802
- }
1803
- finally {
1804
- unmarkHandlerDispatchedEvent?.();
1805
- }
1806
- }
1807
- dispatchReasoningDelta = async (stepId, delta, metadata) => {
1808
- if (!this.config) {
1809
- throw new Error('No config provided');
1810
- }
1811
- const reasoningDelta = {
1812
- id: stepId,
1813
- delta,
1814
- };
1815
- if (hasReasoningDeltaContent(delta.content)) {
1816
- this.reasoningStepHasDeltas.add(stepId);
1817
- }
1818
- const handler = this.handlerRegistry?.getHandler(GraphEvents.ON_REASONING_DELTA);
1819
- if (handler) {
1820
- await handler.handle(GraphEvents.ON_REASONING_DELTA, reasoningDelta, metadata, this);
1821
- this.handlerDispatchedStepIds.add(stepId);
1822
- }
1823
- const unmarkHandlerDispatchedEvent = handler
1824
- ? this.markHandlerDispatchedEvent(GraphEvents.ON_REASONING_DELTA, stepId)
1825
- : undefined;
1826
- try {
1827
- await safeDispatchCustomEvent(GraphEvents.ON_REASONING_DELTA, reasoningDelta, this.config);
1828
- }
1829
- finally {
1830
- unmarkHandlerDispatchedEvent?.();
1831
- }
1832
- };
201
+ function getDispatchableFinalReasoningContent({ agentContext, responseReasoningContent, hasStreamedTextDeltaStep, hasStreamedReasoningDeltaStep }) {
202
+ if (responseReasoningContent == null || hasStreamedReasoningDeltaStep) return;
203
+ if (agentContext.provider === "openrouter" && hasStreamedTextDeltaStep) return;
204
+ return responseReasoningContent;
1833
205
  }
1834
-
206
+ var Graph = class {
207
+ messageStepHasTextDeltas = /* @__PURE__ */ new Set();
208
+ messageStepHasToolCalls = /* @__PURE__ */ new Map();
209
+ messageIdsByStepKey = /* @__PURE__ */ new Map();
210
+ prelimMessageIdsByStepKey = /* @__PURE__ */ new Map();
211
+ config;
212
+ contentData = [];
213
+ stepKeyIds = /* @__PURE__ */ new Map();
214
+ contentIndexMap = /* @__PURE__ */ new Map();
215
+ toolCallStepIds = /* @__PURE__ */ new Map();
216
+ /**
217
+ * Step IDs dispatched through the handler registry during this run.
218
+ * Event echo suppression is tracked separately so repeated deltas for
219
+ * the same step are scoped to the active custom event dispatch.
220
+ */
221
+ handlerDispatchedStepIds = /* @__PURE__ */ new Set();
222
+ reasoningStepHasDeltas = /* @__PURE__ */ new Set();
223
+ handlerDispatchedEventCounts = /* @__PURE__ */ new Map();
224
+ signal;
225
+ /** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
226
+ invokedToolIds;
227
+ handlerRegistry;
228
+ /**
229
+ * True when event-driven tool execution can be routed through callbacks even
230
+ * though this graph intentionally does not own the full handler registry.
231
+ * Self-spawned subagent graphs use this shape: their callback forwarder sends
232
+ * `ON_TOOL_EXECUTE` to the parent's handler, while child run-step events stay
233
+ * wrapped as `ON_SUBAGENT_UPDATE` instead of leaking as parent events.
234
+ */
235
+ eventToolExecutionAvailable = false;
236
+ hookRegistry;
237
+ /**
238
+ * Run-scoped HITL configuration. When `humanInTheLoop?.enabled` is
239
+ * `true`, `ToolNode` raises a real `interrupt()` for `PreToolUse`
240
+ * `ask` decisions instead of treating them as a synchronous deny.
241
+ * Threaded from `RunConfig.humanInTheLoop`.
242
+ */
243
+ humanInTheLoop;
244
+ /**
245
+ * Run-scoped config for the tool output reference registry. Threaded
246
+ * from `RunConfig.toolOutputReferences` down into every ToolNode this
247
+ * graph compiles.
248
+ */
249
+ toolOutputReferences;
250
+ /**
251
+ * Run-scoped Langfuse defaults. Per-agent config wins when present.
252
+ */
253
+ langfuse;
254
+ /**
255
+ * Run-scoped opt-in for eager event-driven tool execution. The stream
256
+ * handler may prestart eligible event-driven tools; ToolNode later
257
+ * consumes the settled promises while preserving final ToolMessage order.
258
+ */
259
+ eagerEventToolExecution;
260
+ eagerEventToolExecutions = /* @__PURE__ */ new Map();
261
+ eagerEventToolUsageCount = /* @__PURE__ */ new Map();
262
+ eagerEventToolUsageCountsByAgentId = /* @__PURE__ */ new Map();
263
+ eagerEventToolCallChunks = /* @__PURE__ */ new Map();
264
+ /**
265
+ * Run-scoped execution backend for built-in code tools. Defaults to the
266
+ * remote Code API sandbox when unset.
267
+ */
268
+ toolExecution;
269
+ /**
270
+ * Shared registry instance used by every ToolNode compiled from this
271
+ * graph. Lazily constructed on first access so multi-agent graphs
272
+ * produce one registry per run (not one per agent), letting cross-
273
+ * agent `{{tool<i>turn<n>}}` substitutions resolve.
274
+ */
275
+ _toolOutputRegistry;
276
+ /**
277
+ * Tool session contexts for automatic state persistence across tool invocations.
278
+ * Keyed by tool name (e.g., Constants.EXECUTE_CODE).
279
+ * Currently supports code execution session tracking (session_id, files).
280
+ */
281
+ sessions = /* @__PURE__ */ new Map();
282
+ /**
283
+ * Clears heavy references to allow GC to reclaim memory held by
284
+ * LangGraph's internal config / AsyncLocalStorage RunTree chain.
285
+ * Call after a run completes and content has been extracted.
286
+ */
287
+ clearHeavyState() {
288
+ this.config = void 0;
289
+ this.signal = void 0;
290
+ this.contentData = [];
291
+ this.contentIndexMap = /* @__PURE__ */ new Map();
292
+ this.stepKeyIds = /* @__PURE__ */ new Map();
293
+ this.toolCallStepIds.clear();
294
+ this.messageIdsByStepKey = /* @__PURE__ */ new Map();
295
+ this.messageStepHasTextDeltas = /* @__PURE__ */ new Set();
296
+ this.reasoningStepHasDeltas = /* @__PURE__ */ new Set();
297
+ this.messageStepHasToolCalls = /* @__PURE__ */ new Map();
298
+ this.prelimMessageIdsByStepKey = /* @__PURE__ */ new Map();
299
+ this.invokedToolIds = void 0;
300
+ this.handlerRegistry = void 0;
301
+ this.hookRegistry = void 0;
302
+ this.humanInTheLoop = void 0;
303
+ this.toolOutputReferences = void 0;
304
+ this.eagerEventToolExecution = void 0;
305
+ this.eagerEventToolExecutions.clear();
306
+ this.clearEagerEventToolUsageCounts();
307
+ this.eagerEventToolCallChunks.clear();
308
+ this.toolExecution = void 0;
309
+ this.handlerDispatchedEventCounts.clear();
310
+ /**
311
+ * ToolNodes compiled from this graph captured the registry
312
+ * instance at construction time, so simply dropping the Graph's
313
+ * own reference would leave their captured reference — and every
314
+ * stored `tool<i>turn<n>` entry, plus up to `maxTotalSize` of raw
315
+ * output — alive across subsequent `processStream()` calls. Wipe
316
+ * the registry's contents first so subsequent runs start fresh.
317
+ */
318
+ this._toolOutputRegistry?.clear();
319
+ this._toolOutputRegistry = void 0;
320
+ for (const node of this._compiledToolNodes) node.clearDirectPathTurns();
321
+ this._compiledToolNodes.clear();
322
+ this.sessions.clear();
323
+ }
324
+ getEagerEventToolUsageCount(agentId) {
325
+ if (agentId == null || agentId === "") return this.eagerEventToolUsageCount;
326
+ let usageCount = this.eagerEventToolUsageCountsByAgentId.get(agentId);
327
+ if (usageCount == null) {
328
+ usageCount = /* @__PURE__ */ new Map();
329
+ this.eagerEventToolUsageCountsByAgentId.set(agentId, usageCount);
330
+ }
331
+ return usageCount;
332
+ }
333
+ clearEagerEventToolUsageCounts() {
334
+ this.eagerEventToolUsageCount.clear();
335
+ for (const usageCount of this.eagerEventToolUsageCountsByAgentId.values()) usageCount.clear();
336
+ }
337
+ markHandlerDispatchedEvent(eventName, stepId) {
338
+ const key = getHandlerDispatchedEventKey(eventName, stepId);
339
+ this.handlerDispatchedEventCounts.set(key, (this.handlerDispatchedEventCounts.get(key) ?? 0) + 1);
340
+ return () => {
341
+ const count = this.handlerDispatchedEventCounts.get(key) ?? 0;
342
+ if (count <= 1) {
343
+ this.handlerDispatchedEventCounts.delete(key);
344
+ return;
345
+ }
346
+ this.handlerDispatchedEventCounts.set(key, count - 1);
347
+ };
348
+ }
349
+ hasHandlerDispatchedEvent(eventName, stepId) {
350
+ const key = getHandlerDispatchedEventKey(eventName, stepId);
351
+ return (this.handlerDispatchedEventCounts.get(key) ?? 0) > 0;
352
+ }
353
+ /**
354
+ * Subclass hook to register a freshly compiled ToolNode so
355
+ * `clearHeavyState` can flush its per-Run direct-path turn cache
356
+ * at end-of-Run. Internal — called from `initializeTools` in the
357
+ * concrete graph subclasses.
358
+ */
359
+ registerCompiledToolNode(node) {
360
+ this._compiledToolNodes.add(node);
361
+ }
362
+ /**
363
+ * Returns the shared `ToolOutputReferenceRegistry` for this run,
364
+ * constructing it on first access. Returns `undefined` when the
365
+ * feature is disabled. All ToolNodes compiled from this graph share
366
+ * this single instance so cross-agent `{{…}}` references resolve.
367
+ *
368
+ * @internal Public so `attemptInvoke` can read it through the typed
369
+ * `InvokeContext` and project ToolMessages into LLM-facing annotated
370
+ * copies right before each provider call (see
371
+ * `annotateMessagesForLLM`). Host code should not call this directly
372
+ * — registry mutations outside the ToolNode lifecycle break the
373
+ * partitioning, eviction, and turn-counter invariants.
374
+ */
375
+ getOrCreateToolOutputRegistry() {
376
+ if (this.toolOutputReferences?.enabled !== true) return;
377
+ if (this._toolOutputRegistry == null) this._toolOutputRegistry = new ToolOutputReferenceRegistry({
378
+ maxOutputSize: this.toolOutputReferences.maxOutputSize,
379
+ maxTotalSize: this.toolOutputReferences.maxTotalSize
380
+ });
381
+ return this._toolOutputRegistry;
382
+ }
383
+ /**
384
+ * Single per-Run file checkpointer shared across every ToolNode the
385
+ * graph compiles. Lazily constructed when
386
+ * `toolExecution.local.fileCheckpointing === true` or
387
+ * `toolExecution.cloudflare.fileCheckpointing === true` so
388
+ * multi-agent graphs see ONE snapshot store, not one-per-agent.
389
+ * Returns undefined when checkpointing is disabled or a supported
390
+ * coding-tool engine isn't selected. Exposed via
391
+ * `Run.getFileCheckpointer()` / `Run.rewindFiles()`.
392
+ */
393
+ _fileCheckpointer;
394
+ /**
395
+ * ToolNodes compiled into this Graph's workflow. Tracked so
396
+ * `clearHeavyState()` can flush their per-Run direct-path turn
397
+ * cache (`directPathTurns`) at end-of-Run — that map intentionally
398
+ * survives `run()` re-entry (resume-stable per Codex P2 #30) but
399
+ * would otherwise grow linearly with tool calls and could collide
400
+ * across Runs if a provider reuses call ids (Codex P2 #33).
401
+ */
402
+ _compiledToolNodes = /* @__PURE__ */ new Set();
403
+ getOrCreateFileCheckpointer() {
404
+ if (this._fileCheckpointer != null) return this._fileCheckpointer;
405
+ if (this.toolExecution?.engine === "local" && this.toolExecution.local?.fileCheckpointing === true) {
406
+ const bundle = createLocalCodingToolBundle(this.toolExecution.local ?? {});
407
+ this._fileCheckpointer = bundle.checkpointer;
408
+ return this._fileCheckpointer;
409
+ }
410
+ if (this.toolExecution?.engine === "cloudflare-sandbox" && this.toolExecution.cloudflare?.fileCheckpointing === true) {
411
+ const bundle = createCloudflareCodingToolBundle(this.toolExecution.cloudflare);
412
+ this._fileCheckpointer = bundle.checkpointer;
413
+ return this._fileCheckpointer;
414
+ }
415
+ }
416
+ };
417
+ var StandardGraph = class StandardGraph extends Graph {
418
+ overrideModel;
419
+ /** Optional compile options passed into workflow.compile() */
420
+ compileOptions;
421
+ messages = [];
422
+ /** Cached run messages preserved before clearHeavyState() so getRunMessages() works after cleanup. */
423
+ cachedRunMessages;
424
+ runId;
425
+ /**
426
+ * Boundary between historical messages (loaded from conversation state)
427
+ * and messages produced during the current run. Set once in the state
428
+ * reducer when messages first arrive. Used by `getRunMessages()` and
429
+ * multi-agent message filtering — NOT for pruner token counting (the
430
+ * pruner maintains its own `lastTurnStartIndex` in its closure).
431
+ */
432
+ startIndex = 0;
433
+ signal;
434
+ /** Map of agent contexts by agent ID */
435
+ agentContexts = /* @__PURE__ */ new Map();
436
+ /** Default agent ID to use */
437
+ defaultAgentId;
438
+ constructor({ runId, signal, agents, langfuse, tokenCounter, indexTokenCountMap, calibrationRatio }) {
439
+ super();
440
+ this.runId = runId;
441
+ this.signal = signal;
442
+ this.langfuse = langfuse;
443
+ if (agents.length === 0) throw new Error("At least one agent configuration is required");
444
+ for (const agentConfig of agents) {
445
+ const agentContext = AgentContext.fromConfig(agentConfig, tokenCounter, indexTokenCountMap);
446
+ if (calibrationRatio != null && calibrationRatio > 0) agentContext.calibrationRatio = calibrationRatio;
447
+ this.agentContexts.set(agentConfig.agentId, agentContext);
448
+ }
449
+ this.defaultAgentId = agents[0].agentId;
450
+ }
451
+ resetValues(keepContent) {
452
+ this.messages = [];
453
+ this.cachedRunMessages = void 0;
454
+ this.config = resetIfNotEmpty(this.config, void 0);
455
+ if (keepContent !== true) {
456
+ this.contentData = resetIfNotEmpty(this.contentData, []);
457
+ this.contentIndexMap = resetIfNotEmpty(this.contentIndexMap, /* @__PURE__ */ new Map());
458
+ }
459
+ this.stepKeyIds = resetIfNotEmpty(this.stepKeyIds, /* @__PURE__ */ new Map());
460
+ /**
461
+ * Clear in-place instead of replacing with a new Map to preserve the
462
+ * shared reference held by ToolNode (passed at construction time).
463
+ * Using resetIfNotEmpty would create a new Map, leaving ToolNode with
464
+ * a stale reference on 2nd+ processStream calls.
465
+ */
466
+ this.toolCallStepIds.clear();
467
+ this.eagerEventToolExecutions.clear();
468
+ this.clearEagerEventToolUsageCounts();
469
+ this.eagerEventToolCallChunks.clear();
470
+ this.handlerDispatchedStepIds = resetIfNotEmpty(this.handlerDispatchedStepIds, /* @__PURE__ */ new Set());
471
+ this.handlerDispatchedEventCounts = resetIfNotEmpty(this.handlerDispatchedEventCounts, /* @__PURE__ */ new Map());
472
+ this.messageIdsByStepKey = resetIfNotEmpty(this.messageIdsByStepKey, /* @__PURE__ */ new Map());
473
+ this.messageStepHasToolCalls = resetIfNotEmpty(this.messageStepHasToolCalls, /* @__PURE__ */ new Map());
474
+ this.messageStepHasTextDeltas = resetIfNotEmpty(this.messageStepHasTextDeltas, /* @__PURE__ */ new Set());
475
+ this.reasoningStepHasDeltas = resetIfNotEmpty(this.reasoningStepHasDeltas, /* @__PURE__ */ new Set());
476
+ this.prelimMessageIdsByStepKey = resetIfNotEmpty(this.prelimMessageIdsByStepKey, /* @__PURE__ */ new Map());
477
+ this.invokedToolIds = resetIfNotEmpty(this.invokedToolIds, void 0);
478
+ for (const context of this.agentContexts.values()) context.reset();
479
+ }
480
+ clearHeavyState() {
481
+ this.cachedRunMessages = this.messages.slice(this.startIndex);
482
+ super.clearHeavyState();
483
+ this.messages = [];
484
+ this.overrideModel = void 0;
485
+ for (const context of this.agentContexts.values()) context.reset();
486
+ }
487
+ getRunStep(stepId) {
488
+ const index = this.contentIndexMap.get(stepId);
489
+ if (index !== void 0) return this.contentData[index];
490
+ }
491
+ getAgentContext(metadata) {
492
+ if (!metadata) throw new Error("No metadata provided to retrieve agent context");
493
+ const currentNode = metadata.langgraph_node;
494
+ if (!currentNode) throw new Error("No langgraph_node in metadata to retrieve agent context");
495
+ let agentId;
496
+ if (currentNode.startsWith(AGENT)) agentId = currentNode.substring(AGENT.length);
497
+ else if (currentNode.startsWith(TOOLS)) agentId = currentNode.substring(TOOLS.length);
498
+ else if (currentNode.startsWith(SUMMARIZE)) agentId = currentNode.substring(SUMMARIZE.length);
499
+ const agentContext = this.agentContexts.get(agentId ?? "");
500
+ if (!agentContext) throw new Error(`No agent context found for agent ID ${agentId}`);
501
+ return agentContext;
502
+ }
503
+ getStepBaseKey(metadata) {
504
+ if (!metadata) return "";
505
+ const keyList = this.getInvocationKeyList(metadata);
506
+ if (this.checkKeyList(keyList)) throw new Error("Missing metadata");
507
+ return joinKeys(keyList);
508
+ }
509
+ getStepKey(metadata) {
510
+ if (!metadata) return "";
511
+ const keyList = this.getKeyList(metadata);
512
+ if (this.checkKeyList(keyList)) throw new Error("Missing metadata");
513
+ return joinKeys(keyList);
514
+ }
515
+ getStepIdByKey(stepKey, index) {
516
+ const stepIds = this.stepKeyIds.get(stepKey);
517
+ if (!stepIds) throw new Error(`No step IDs found for stepKey ${stepKey}`);
518
+ if (index === void 0) return stepIds[stepIds.length - 1];
519
+ return stepIds[index];
520
+ }
521
+ generateStepId(stepKey) {
522
+ const stepIds = this.stepKeyIds.get(stepKey);
523
+ let newStepId;
524
+ let stepIndex = 0;
525
+ if (stepIds) {
526
+ stepIndex = stepIds.length;
527
+ newStepId = `step_${nanoid()}`;
528
+ stepIds.push(newStepId);
529
+ this.stepKeyIds.set(stepKey, stepIds);
530
+ } else {
531
+ newStepId = `step_${nanoid()}`;
532
+ this.stepKeyIds.set(stepKey, [newStepId]);
533
+ }
534
+ return [newStepId, stepIndex];
535
+ }
536
+ getKeyList(metadata) {
537
+ if (!metadata) return [];
538
+ const keyList = this.getInvocationKeyList(metadata);
539
+ const agentContext = this.getAgentContext(metadata);
540
+ if (agentContext.currentTokenType === "think" || agentContext.currentTokenType === "think_and_text") keyList.push("reasoning");
541
+ else if (agentContext.tokenTypeSwitch === "content") keyList.push(`post-reasoning-${agentContext.reasoningTransitionCount}`);
542
+ return keyList;
543
+ }
544
+ getInvocationKeyList(metadata) {
545
+ const keyList = this.getBaseKeyList(metadata);
546
+ if (this.invokedToolIds != null && this.invokedToolIds.size > 0) keyList.push(this.invokedToolIds.size + "");
547
+ return keyList;
548
+ }
549
+ getBaseKeyList(metadata) {
550
+ const configurable = this.config?.configurable;
551
+ const runId = metadata.run_id ?? configurable?.run_id ?? this.runId;
552
+ const threadId = metadata.thread_id ?? configurable?.thread_id ?? runId;
553
+ const checkpointNs = metadata.checkpoint_ns ?? metadata.langgraph_checkpoint_ns ?? "";
554
+ return [
555
+ runId,
556
+ threadId,
557
+ metadata.langgraph_node,
558
+ metadata.langgraph_step,
559
+ checkpointNs
560
+ ];
561
+ }
562
+ checkKeyList(keyList) {
563
+ return keyList.some((key) => key === void 0);
564
+ }
565
+ getRunMessages() {
566
+ if (this.messages.length === 0 && this.cachedRunMessages != null) return this.cachedRunMessages;
567
+ return this.messages.slice(this.startIndex);
568
+ }
569
+ getContentParts() {
570
+ return convertMessagesToContent(this.messages.slice(this.startIndex));
571
+ }
572
+ getCalibrationRatio() {
573
+ return this.agentContexts.get(this.defaultAgentId)?.calibrationRatio ?? 1;
574
+ }
575
+ getResolvedInstructionOverhead() {
576
+ return this.agentContexts.get(this.defaultAgentId)?.resolvedInstructionOverhead;
577
+ }
578
+ getToolCount() {
579
+ const context = this.agentContexts.get(this.defaultAgentId);
580
+ return (context?.tools?.length ?? 0) + (context?.toolDefinitions?.length ?? 0);
581
+ }
582
+ /**
583
+ * Get all run steps, optionally filtered by agent ID
584
+ */
585
+ getRunSteps(agentId) {
586
+ if (agentId == null || agentId === "") return [...this.contentData];
587
+ return this.contentData.filter((step) => step.agentId === agentId);
588
+ }
589
+ /**
590
+ * Get run steps grouped by agent ID
591
+ */
592
+ getRunStepsByAgent() {
593
+ const stepsByAgent = /* @__PURE__ */ new Map();
594
+ for (const step of this.contentData) {
595
+ if (step.agentId == null || step.agentId === "") continue;
596
+ const steps = stepsByAgent.get(step.agentId) ?? [];
597
+ steps.push(step);
598
+ stepsByAgent.set(step.agentId, steps);
599
+ }
600
+ return stepsByAgent;
601
+ }
602
+ /**
603
+ * Get agent IDs that participated in this run
604
+ */
605
+ getActiveAgentIds() {
606
+ const agentIds = /* @__PURE__ */ new Set();
607
+ for (const step of this.contentData) if (step.agentId != null && step.agentId !== "") agentIds.add(step.agentId);
608
+ return Array.from(agentIds);
609
+ }
610
+ /**
611
+ * Maps contentPart indices to agent IDs for post-run analysis
612
+ * Returns a map where key is the contentPart index and value is the agentId
613
+ */
614
+ getContentPartAgentMap() {
615
+ const contentPartAgentMap = /* @__PURE__ */ new Map();
616
+ for (const step of this.contentData) if (step.agentId != null && step.agentId !== "" && Number.isFinite(step.index)) contentPartAgentMap.set(step.index, step.agentId);
617
+ return contentPartAgentMap;
618
+ }
619
+ initializeTools({ currentTools, currentToolMap, agentContext }) {
620
+ const toolDefinitions = agentContext?.toolDefinitions;
621
+ const eventDrivenMode = toolDefinitions != null && toolDefinitions.length > 0;
622
+ const traceToolNode = shouldTraceToolNodeForLangfuse({
623
+ runLangfuse: this.langfuse,
624
+ agentLangfuse: agentContext?.langfuse
625
+ });
626
+ if (eventDrivenMode) {
627
+ const schemaTools = createSchemaOnlyTools(toolDefinitions);
628
+ const toolDefMap = new Map(toolDefinitions.map((def) => [def.name, def]));
629
+ const graphTools = agentContext?.graphTools;
630
+ const directToolNames = /* @__PURE__ */ new Set();
631
+ const allTools = [...schemaTools];
632
+ const allToolMap = new Map(schemaTools.map((tool) => [tool.name, tool]));
633
+ if (graphTools && graphTools.length > 0) {
634
+ for (const tool of graphTools) if ("name" in tool) {
635
+ allTools.push(tool);
636
+ allToolMap.set(tool.name, tool);
637
+ directToolNames.add(tool.name);
638
+ }
639
+ }
640
+ const node = new ToolNode({
641
+ tools: allTools,
642
+ toolMap: allToolMap,
643
+ trace: traceToolNode,
644
+ runLangfuse: this.langfuse,
645
+ agentLangfuse: agentContext?.langfuse,
646
+ eventDrivenMode: true,
647
+ sessions: this.sessions,
648
+ toolDefinitions: toolDefMap,
649
+ agentId: agentContext?.agentId,
650
+ executingAgentId: agentContext?.agentId,
651
+ toolCallStepIds: this.toolCallStepIds,
652
+ toolRegistry: agentContext?.toolRegistry,
653
+ hookRegistry: this.hookRegistry,
654
+ humanInTheLoop: this.humanInTheLoop,
655
+ eagerEventToolExecution: this.eagerEventToolExecution,
656
+ eagerEventToolExecutions: this.eagerEventToolExecutions,
657
+ eagerEventToolUsageCount: this.getEagerEventToolUsageCount(agentContext?.agentId),
658
+ toolExecution: this.toolExecution,
659
+ directToolNames: directToolNames.size > 0 ? directToolNames : void 0,
660
+ maxContextTokens: agentContext?.maxContextTokens,
661
+ maxToolResultChars: agentContext?.maxToolResultChars,
662
+ toolOutputRegistry: this.getOrCreateToolOutputRegistry(),
663
+ fileCheckpointer: this.getOrCreateFileCheckpointer(),
664
+ errorHandler: (data, metadata) => StandardGraph.handleToolCallErrorStatic(this, data, metadata)
665
+ });
666
+ this.registerCompiledToolNode(node);
667
+ return node;
668
+ }
669
+ const graphTools = agentContext?.graphTools;
670
+ const baseTools = currentTools ?? [];
671
+ const node = new ToolNode({
672
+ tools: graphTools && graphTools.length > 0 ? [...baseTools, ...graphTools] : baseTools,
673
+ toolMap: graphTools && graphTools.length > 0 ? new Map([...currentToolMap ?? /* @__PURE__ */ new Map(), ...graphTools.filter((t) => "name" in t).map((t) => [t.name, t])]) : currentToolMap,
674
+ trace: traceToolNode,
675
+ runLangfuse: this.langfuse,
676
+ agentLangfuse: agentContext?.langfuse,
677
+ executingAgentId: agentContext?.agentId,
678
+ toolCallStepIds: this.toolCallStepIds,
679
+ errorHandler: (data, metadata) => StandardGraph.handleToolCallErrorStatic(this, data, metadata),
680
+ toolRegistry: agentContext?.toolRegistry,
681
+ sessions: this.sessions,
682
+ toolExecution: this.toolExecution,
683
+ hookRegistry: this.hookRegistry,
684
+ humanInTheLoop: this.humanInTheLoop,
685
+ maxContextTokens: agentContext?.maxContextTokens,
686
+ maxToolResultChars: agentContext?.maxToolResultChars,
687
+ toolOutputRegistry: this.getOrCreateToolOutputRegistry(),
688
+ fileCheckpointer: this.getOrCreateFileCheckpointer()
689
+ });
690
+ this.registerCompiledToolNode(node);
691
+ return node;
692
+ }
693
+ overrideTestModel(responses, sleep, toolCalls) {
694
+ this.overrideModel = createFakeStreamingLLM({
695
+ responses,
696
+ sleep,
697
+ toolCalls
698
+ });
699
+ }
700
+ getUsageMetadata(finalMessage) {
701
+ if (finalMessage && "usage_metadata" in finalMessage && finalMessage.usage_metadata != null) return finalMessage.usage_metadata;
702
+ }
703
+ cleanupSignalListener(currentModel) {
704
+ if (!this.signal) return;
705
+ const model = this.overrideModel ?? currentModel;
706
+ if (!model) return;
707
+ const client = model?.exposedClient;
708
+ if (!client?.abortHandler) return;
709
+ this.signal.removeEventListener("abort", client.abortHandler);
710
+ client.abortHandler = void 0;
711
+ }
712
+ createCallModel(agentId = "default") {
713
+ return async (state, config) => {
714
+ const agentContext = this.agentContexts.get(agentId);
715
+ if (!agentContext) throw new Error(`Agent context not found for agentId: ${agentId}`);
716
+ if (!config) throw new Error("No config provided");
717
+ const { messages } = state;
718
+ const discoveredNames = extractToolDiscoveries(messages);
719
+ if (discoveredNames.length > 0) agentContext.markToolsAsDiscovered(discoveredNames);
720
+ const rawToolsForBinding = resolveLocalToolsForBinding({
721
+ tools: agentContext.getToolsForBinding(),
722
+ toolExecution: this.toolExecution
723
+ });
724
+ /**
725
+ * Anthropic prompt-cache breakpoint on the tool definitions.
726
+ *
727
+ * Without this, the (often static) tool inventory shows up as
728
+ * fresh input on every turn — measured at ~28k tokens/turn for
729
+ * the local engine's coding-tool bundle, dominating per-turn
730
+ * cost even when message-level caching is on.
731
+ *
732
+ * Strategy: partition tools into [static, deferred] and stamp
733
+ * `cache_control: ephemeral` on the last static tool.
734
+ * Discovered deferred tools that arrive across turns sit *after*
735
+ * the breakpoint and don't invalidate the prefix.
736
+ */
737
+ let toolsForBinding = rawToolsForBinding;
738
+ if (agentContext.provider === "anthropic" && agentContext.clientOptions?.promptCache === true) toolsForBinding = partitionAndMarkAnthropicToolCache(rawToolsForBinding, makeIsDeferred(agentContext.toolDefinitions)) ?? rawToolsForBinding;
739
+ else if (agentContext.provider === "openrouter" && agentContext.clientOptions?.promptCache === true) toolsForBinding = partitionAndMarkOpenRouterToolCache(rawToolsForBinding, makeIsDeferred(agentContext.toolDefinitions)) ?? rawToolsForBinding;
740
+ else if (agentContext.provider === "bedrock" && agentContext.clientOptions?.promptCache === true) toolsForBinding = partitionAndMarkBedrockToolCache(rawToolsForBinding, makeIsDeferred(agentContext.toolDefinitions)) ?? rawToolsForBinding;
741
+ let model = this.overrideModel ?? initializeModel({
742
+ tools: toolsForBinding,
743
+ provider: agentContext.provider,
744
+ clientOptions: agentContext.clientOptions
745
+ });
746
+ if (agentContext.systemRunnable) model = agentContext.systemRunnable.pipe(model);
747
+ if (agentContext.tokenCalculationPromise) await agentContext.tokenCalculationPromise;
748
+ if (!config.signal) config.signal = this.signal;
749
+ this.config = config;
750
+ let messagesToUse = messages;
751
+ if (!agentContext.pruneMessages && agentContext.tokenCounter && agentContext.maxContextTokens != null) agentContext.pruneMessages = createPruneMessages({
752
+ startIndex: agentContext.indexTokenCountMap[0] != null ? this.startIndex : 0,
753
+ provider: agentContext.provider,
754
+ tokenCounter: agentContext.tokenCounter,
755
+ maxTokens: agentContext.maxContextTokens,
756
+ thinkingEnabled: isThinkingEnabled(agentContext.provider, agentContext.clientOptions),
757
+ indexTokenCountMap: agentContext.indexTokenCountMap,
758
+ contextPruningConfig: agentContext.contextPruningConfig,
759
+ summarizationEnabled: agentContext.summarizationEnabled,
760
+ reserveRatio: agentContext.summarizationConfig?.reserveRatio,
761
+ calibrationRatio: agentContext.calibrationRatio,
762
+ getInstructionTokens: () => agentContext.instructionTokens,
763
+ log: (level, message, data) => {
764
+ emitAgentLog(config, level, "prune", message, data, {
765
+ runId: this.runId,
766
+ agentId
767
+ });
768
+ }
769
+ });
770
+ if (agentContext.pruneMessages) {
771
+ const { context, indexTokenCountMap, messagesToRefine, prePruneContextTokens, remainingContextTokens, originalToolContent, calibrationRatio, resolvedInstructionOverhead } = agentContext.pruneMessages({
772
+ messages,
773
+ usageMetadata: agentContext.currentUsage,
774
+ lastCallUsage: agentContext.lastCallUsage,
775
+ totalTokensFresh: agentContext.totalTokensFresh
776
+ });
777
+ agentContext.indexTokenCountMap = indexTokenCountMap;
778
+ if (calibrationRatio != null && calibrationRatio > 0) agentContext.calibrationRatio = calibrationRatio;
779
+ if (resolvedInstructionOverhead != null) {
780
+ agentContext.resolvedInstructionOverhead = resolvedInstructionOverhead;
781
+ const nonToolOverhead = agentContext.instructionTokens - agentContext.toolSchemaTokens;
782
+ const calibratedToolTokens = Math.max(0, resolvedInstructionOverhead - nonToolOverhead);
783
+ const currentToolTokens = agentContext.toolSchemaTokens;
784
+ if ((currentToolTokens > 0 ? Math.abs(calibratedToolTokens - currentToolTokens) / currentToolTokens : 1) > CALIBRATION_VARIANCE_THRESHOLD) agentContext.toolSchemaTokens = calibratedToolTokens;
785
+ }
786
+ messagesToUse = context;
787
+ if (agentContext.summarizationEnabled === true && Array.isArray(messagesToRefine) && messagesToRefine.length > 0) {
788
+ const shouldSkip = agentContext.shouldSkipSummarization(messages.length);
789
+ if (!shouldSkip && shouldTriggerSummarization({
790
+ trigger: agentContext.summarizationConfig?.trigger,
791
+ maxContextTokens: agentContext.maxContextTokens,
792
+ prePruneContextTokens: prePruneContextTokens != null ? prePruneContextTokens + agentContext.instructionTokens : void 0,
793
+ remainingContextTokens,
794
+ messagesToRefineCount: messagesToRefine.length
795
+ })) {
796
+ if (originalToolContent != null && originalToolContent.size > 0)
797
+ /**
798
+ * Merge — never overwrite — the pruner's masking record
799
+ * into pendingOriginalToolContent. Carry-over entries
800
+ * from a prior summarize (preserved by the recency
801
+ * window for masked tool messages still in the tail) and
802
+ * the current pruner's new entries are both keyed by
803
+ * indices in the current `state.messages`, so a key-wise
804
+ * union is correct. Overwriting would discard the
805
+ * carry-over and reduce summary fidelity when those
806
+ * masked tail messages eventually move into the head.
807
+ */
808
+ if (agentContext.pendingOriginalToolContent == null) agentContext.pendingOriginalToolContent = originalToolContent;
809
+ else {
810
+ for (const [idx, content] of originalToolContent) agentContext.pendingOriginalToolContent.set(idx, content);
811
+ /**
812
+ * Re-apply the per-store char cap after the union. The
813
+ * pruner enforces ORIGINAL_CONTENT_MAX_CHARS inside its
814
+ * own map via the onContentStored callback, but a
815
+ * key-wise merge with recency carry-over bypasses that
816
+ * accounting and could let the merged map grow without
817
+ * bound across long sessions.
818
+ */
819
+ enforceOriginalContentCap(agentContext.pendingOriginalToolContent);
820
+ }
821
+ emitAgentLog(config, "info", "graph", "Summarization triggered", void 0, {
822
+ runId: this.runId,
823
+ agentId
824
+ });
825
+ emitAgentLog(config, "debug", "graph", "Summarization trigger details", {
826
+ totalMessages: messages.length,
827
+ remainingContextTokens: remainingContextTokens ?? 0,
828
+ summaryVersion: agentContext.summaryVersion + 1,
829
+ toolSchemaTokens: agentContext.toolSchemaTokens,
830
+ instructionTokens: agentContext.instructionTokens,
831
+ systemMessageTokens: agentContext.systemMessageTokens
832
+ }, {
833
+ runId: this.runId,
834
+ agentId
835
+ });
836
+ agentContext.markSummarizationTriggered(messages.length);
837
+ return { summarizationRequest: {
838
+ remainingContextTokens: remainingContextTokens ?? 0,
839
+ agentId: agentId || agentContext.agentId
840
+ } };
841
+ }
842
+ if (shouldSkip) emitAgentLog(config, "debug", "graph", "Summarization skipped — no new messages or per-run cap reached", {
843
+ messageCount: messages.length,
844
+ messagesToRefineCount: messagesToRefine.length,
845
+ contextLength: context.length
846
+ }, {
847
+ runId: this.runId,
848
+ agentId
849
+ });
850
+ }
851
+ }
852
+ let finalMessages = messagesToUse;
853
+ if (agentContext.useLegacyContent) finalMessages = formatContentStrings(finalMessages);
854
+ const lastMessageX = finalMessages.length >= 2 ? finalMessages[finalMessages.length - 2] : null;
855
+ const lastMessageY = finalMessages.length >= 1 ? finalMessages[finalMessages.length - 1] : null;
856
+ const anthropicLike = isAnthropicLike(agentContext.provider, agentContext.clientOptions);
857
+ if (agentContext.provider === "bedrock" && lastMessageX instanceof AIMessageChunk && lastMessageY instanceof ToolMessage && typeof lastMessageX.content === "string") {
858
+ const trimmed = lastMessageX.content.trim();
859
+ finalMessages[finalMessages.length - 2].content = trimmed.length > 0 ? [{
860
+ type: "text",
861
+ text: trimmed
862
+ }] : "";
863
+ }
864
+ if (lastMessageY instanceof ToolMessage) {
865
+ if (anthropicLike) formatAnthropicArtifactContent(finalMessages);
866
+ else if (isOpenAILike(agentContext.provider) && agentContext.provider !== "deepseek" || isGoogleLike(agentContext.provider)) formatArtifactPayload(finalMessages);
867
+ }
868
+ if (agentContext.provider === "anthropic") {
869
+ if (agentContext.clientOptions?.promptCache === true && !agentContext.systemRunnable) finalMessages = addCacheControl(finalMessages);
870
+ } else if (agentContext.provider === "bedrock") {
871
+ if (agentContext.clientOptions?.promptCache === true) finalMessages = addBedrockCacheControl(finalMessages);
872
+ } else if (agentContext.provider === "openrouter") {
873
+ if (agentContext.clientOptions?.promptCache === true && !agentContext.systemRunnable) finalMessages = addCacheControl(finalMessages);
874
+ }
875
+ if (isThinkingEnabled(agentContext.provider, agentContext.clientOptions))
876
+ /**
877
+ * Pass `this.startIndex` so the function can distinguish CURRENT-run
878
+ * AI messages (the agent's own iterations — possibly without a
879
+ * leading thinking block, which Claude is allowed to skip) from
880
+ * historical context that genuinely needs the
881
+ * `[Previous agent context]` placeholder. Without this signal the
882
+ * function would convert the agent's own in-run tool_use messages,
883
+ * polluting the next iteration's prompt with a placeholder the
884
+ * model treats as suspicious injected content.
885
+ */
886
+ finalMessages = ensureThinkingBlockInMessages(finalMessages, agentContext.provider, config, this.startIndex);
887
+ if (anthropicLike && (!agentContext.pruneMessages || finalMessages !== messagesToUse)) {
888
+ const beforeSanitize = finalMessages.length;
889
+ finalMessages = sanitizeOrphanToolBlocks(finalMessages);
890
+ if (finalMessages.length !== beforeSanitize) emitAgentLog(config, "warn", "sanitize", "Orphan tool blocks removed", {
891
+ before: beforeSanitize,
892
+ after: finalMessages.length,
893
+ dropped: beforeSanitize - finalMessages.length
894
+ }, {
895
+ runId: this.runId,
896
+ agentId
897
+ });
898
+ }
899
+ if (agentContext.lastStreamCall != null && agentContext.streamBuffer != null) {
900
+ const timeSinceLastCall = Date.now() - agentContext.lastStreamCall;
901
+ if (timeSinceLastCall < agentContext.streamBuffer) await sleep(Math.ceil((agentContext.streamBuffer - timeSinceLastCall) / 1e3) * 1e3);
902
+ }
903
+ agentContext.lastStreamCall = Date.now();
904
+ agentContext.markTokensStale();
905
+ let result;
906
+ const fallbacks = agentContext.clientOptions?.fallbacks ?? [];
907
+ if (finalMessages.length === 0 && !agentContext.hasPendingCompactionSummary()) {
908
+ const budgetBreakdown = agentContext.getTokenBudgetBreakdown(messages);
909
+ const breakdown = agentContext.formatTokenBudgetBreakdown(messages);
910
+ const instructionsExceedBudget = budgetBreakdown.instructionTokens > budgetBreakdown.maxContextTokens;
911
+ let guidance;
912
+ if (instructionsExceedBudget) {
913
+ const toolPct = budgetBreakdown.toolSchemaTokens > 0 ? Math.round(budgetBreakdown.toolSchemaTokens / budgetBreakdown.instructionTokens * 100) : 0;
914
+ guidance = toolPct > 50 ? `Tool definitions consume ${budgetBreakdown.toolSchemaTokens} tokens (${toolPct}% of instructions) across ${budgetBreakdown.toolCount} tools, exceeding maxContextTokens (${budgetBreakdown.maxContextTokens}). Reduce the number of tools or increase maxContextTokens.` : `Instructions (${budgetBreakdown.instructionTokens} tokens) exceed maxContextTokens (${budgetBreakdown.maxContextTokens}). Increase maxContextTokens or shorten the system prompt.`;
915
+ if (agentContext.summarizationEnabled === true) guidance += " Summarization was skipped because the summary would further increase the instruction overhead.";
916
+ } else guidance = "Please increase the context window size or make your message shorter.";
917
+ emitAgentLog(config, "error", "graph", "Empty messages after pruning", {
918
+ messageCount: messages.length,
919
+ instructionsExceedBudget,
920
+ breakdown
921
+ }, {
922
+ runId: this.runId,
923
+ agentId
924
+ });
925
+ throw new Error(JSON.stringify({
926
+ type: "empty_messages",
927
+ info: `Message pruning removed all messages as none fit in the context window. ${guidance}\n${breakdown}`
928
+ }));
929
+ }
930
+ const invokeStart = Date.now();
931
+ const invokeMeta = {
932
+ runId: this.runId,
933
+ agentId
934
+ };
935
+ emitAgentLog(config, "debug", "graph", "Invoking LLM", {
936
+ messageCount: finalMessages.length,
937
+ provider: agentContext.provider
938
+ }, invokeMeta, { force: true });
939
+ const langfuse = resolveLangfuseConfig(this.langfuse, agentContext.langfuse);
940
+ const traceMetadata = createLangfuseTraceMetadata({
941
+ messageId: this.runId,
942
+ parentMessageId: config.configurable?.requestBody?.parentMessageId,
943
+ agentId,
944
+ agentName: agentContext.name
945
+ });
946
+ let langfuseHandler;
947
+ let invokeConfig = {
948
+ ...config,
949
+ metadata: {
950
+ ...config.metadata ?? {},
951
+ ...traceMetadata
952
+ }
953
+ };
954
+ initializeLangfuseTracing(langfuse);
955
+ if (findCallback(config.callbacks, isLangfuseCallbackHandler) == null) {
956
+ langfuseHandler = createLangfuseHandler({
957
+ langfuse,
958
+ userId: config.configurable?.user_id,
959
+ sessionId: config.configurable?.thread_id,
960
+ traceMetadata,
961
+ tags: ["librechat", "agent"]
962
+ });
963
+ if (langfuseHandler != null) invokeConfig = {
964
+ ...invokeConfig,
965
+ callbacks: appendCallbacks(invokeConfig.callbacks, [langfuseHandler])
966
+ };
967
+ }
968
+ const metadata = config.metadata;
969
+ try {
970
+ result = await withLangfuseToolOutputTracingConfig(this.langfuse, () => attemptInvoke({
971
+ model: this.overrideModel ?? model,
972
+ messages: finalMessages,
973
+ provider: agentContext.provider,
974
+ context: this
975
+ }, invokeConfig), agentContext.langfuse);
976
+ } catch (primaryError) {
977
+ clearCurrentDeltaStepMarkers({
978
+ graph: this,
979
+ metadata
980
+ });
981
+ result = await withLangfuseToolOutputTracingConfig(this.langfuse, () => tryFallbackProviders({
982
+ fallbacks,
983
+ tools: agentContext.tools,
984
+ messages: finalMessages,
985
+ config: invokeConfig,
986
+ primaryError,
987
+ context: this
988
+ }), agentContext.langfuse);
989
+ } finally {
990
+ await disposeLangfuseHandler(langfuseHandler);
991
+ }
992
+ if (!result) throw new Error("No result after model invocation");
993
+ /**
994
+ * Fallback: populate toolCallStepIds in the graph execution context.
995
+ *
996
+ * When model.stream() is available (the common case), attemptInvoke
997
+ * processes all chunks through a local ChatModelStreamHandler which
998
+ * creates run steps and populates toolCallStepIds before returning.
999
+ * The code below is a fallback for the rare case where model.stream
1000
+ * is unavailable and model.invoke() was used instead.
1001
+ *
1002
+ * Text content is dispatched FIRST so that MESSAGE_CREATION is the
1003
+ * current step when handleToolCalls runs. handleToolCalls then creates
1004
+ * TOOL_CALLS on top of it. The dedup in getMessageId and
1005
+ * toolCallStepIds.has makes this safe when attemptInvoke already
1006
+ * handled everything — both paths become no-ops.
1007
+ */
1008
+ const responseMessage = result.messages?.[0];
1009
+ const toolCalls = responseMessage?.tool_calls;
1010
+ const hasToolCalls = Array.isArray(toolCalls) && toolCalls.length > 0;
1011
+ const responseReasoningContent = getResponseReasoningContent({
1012
+ responseMessage,
1013
+ reasoningKey: agentContext.reasoningKey
1014
+ });
1015
+ const textMessageContent = getMessageDeltaContent(agentContext.provider, responseMessage?.content);
1016
+ const hasStreamedTextDeltaStep = hasCurrentTextDeltaStep({
1017
+ graph: this,
1018
+ metadata
1019
+ });
1020
+ const dispatchableFinalReasoningContent = getDispatchableFinalReasoningContent({
1021
+ agentContext,
1022
+ responseReasoningContent,
1023
+ hasStreamedTextDeltaStep,
1024
+ hasStreamedReasoningDeltaStep: hasCurrentReasoningDeltaStep({
1025
+ graph: this,
1026
+ metadata
1027
+ })
1028
+ });
1029
+ if (hasToolCalls) {
1030
+ if (dispatchableFinalReasoningContent != null && await dispatchReasoningContent({
1031
+ graph: this,
1032
+ agentContext,
1033
+ reasoningContent: dispatchableFinalReasoningContent,
1034
+ metadata
1035
+ })) markPostReasoningContent(agentContext);
1036
+ if (textMessageContent != null && !hasStreamedTextDeltaStep) {
1037
+ const stepKey = this.getStepKey(metadata);
1038
+ if (await dispatchTextMessageContent({
1039
+ graph: this,
1040
+ stepKey,
1041
+ provider: agentContext.provider,
1042
+ content: textMessageContent,
1043
+ metadata
1044
+ })) markPostReasoningContent(agentContext);
1045
+ }
1046
+ await handleToolCalls(toolCalls, metadata, this);
1047
+ }
1048
+ /**
1049
+ * When streaming events are unavailable, ChatModelStreamHandler never
1050
+ * fires. Dispatch final reasoning/text content here. getMessageId makes
1051
+ * this a no-op when the streaming path already handled the same step.
1052
+ */
1053
+ if (!hasToolCalls && responseMessage != null) {
1054
+ if (dispatchableFinalReasoningContent != null && await dispatchReasoningContent({
1055
+ graph: this,
1056
+ agentContext,
1057
+ reasoningContent: dispatchableFinalReasoningContent,
1058
+ metadata
1059
+ }) && textMessageContent != null) markPostReasoningContent(agentContext);
1060
+ if (textMessageContent != null && !hasStreamedTextDeltaStep) {
1061
+ const stepKey = this.getStepKey(metadata);
1062
+ await dispatchTextMessageContent({
1063
+ graph: this,
1064
+ stepKey,
1065
+ provider: agentContext.provider,
1066
+ content: textMessageContent,
1067
+ metadata
1068
+ });
1069
+ }
1070
+ }
1071
+ const invokeElapsed = ((Date.now() - invokeStart) / 1e3).toFixed(2);
1072
+ agentContext.currentUsage = this.getUsageMetadata(result.messages?.[0]);
1073
+ if (agentContext.currentUsage) {
1074
+ agentContext.updateLastCallUsage(agentContext.currentUsage);
1075
+ emitAgentLog(config, "debug", "graph", `LLM call complete (${invokeElapsed}s)`, {
1076
+ ...agentContext.currentUsage,
1077
+ elapsedSeconds: Number(invokeElapsed),
1078
+ instructionTokens: agentContext.instructionTokens,
1079
+ toolSchemaTokens: agentContext.toolSchemaTokens,
1080
+ messageCount: finalMessages.length
1081
+ }, invokeMeta, { force: true });
1082
+ } else emitAgentLog(config, "debug", "graph", `LLM call complete (${invokeElapsed}s)`, {
1083
+ elapsedSeconds: Number(invokeElapsed),
1084
+ messageCount: finalMessages.length
1085
+ }, invokeMeta, { force: true });
1086
+ this.cleanupSignalListener();
1087
+ return result;
1088
+ };
1089
+ }
1090
+ createAgentNode(agentId) {
1091
+ const getConfig = () => this.config;
1092
+ const agentContext = this.agentContexts.get(agentId);
1093
+ if (!agentContext) throw new Error(`Agent context not found for agentId: ${agentId}`);
1094
+ /**
1095
+ * Depth countdown across graph boundaries: the parent's `maxSubagentDepth`
1096
+ * becomes this executor's `maxDepth`. When the child graph is constructed,
1097
+ * `buildChildInputs()` decrements `maxSubagentDepth` on the child's
1098
+ * `AgentInputs` (only when `allowNested: true`; otherwise subagentConfigs
1099
+ * are stripped entirely). The child graph's own `createAgentNode()` then
1100
+ * reads the decremented value here and creates a narrower executor —
1101
+ * recursion is bounded even though each graph has its own separate
1102
+ * executor instance.
1103
+ */
1104
+ const effectiveSubagentDepth = agentContext.maxSubagentDepth ?? 1;
1105
+ if (agentContext.subagentConfigs != null && agentContext.subagentConfigs.length > 0 && effectiveSubagentDepth > 0) {
1106
+ const resolvedConfigs = resolveSubagentConfigs(agentContext.subagentConfigs, agentContext);
1107
+ if (resolvedConfigs.length > 0) {
1108
+ const getParentHandlerRegistry = () => this.handlerRegistry;
1109
+ const executor = new SubagentExecutor({
1110
+ configs: new Map(resolvedConfigs.map((c) => [c.type, c])),
1111
+ parentSignal: this.signal,
1112
+ hookRegistry: this.hookRegistry,
1113
+ /** Lazy — Run wires the registry onto the graph AFTER
1114
+ * `createWorkflow()` runs, so a direct capture here would be
1115
+ * `undefined` at construction time. */
1116
+ parentHandlerRegistry: getParentHandlerRegistry,
1117
+ parentRunId: this.runId ?? "",
1118
+ parentAgentId: agentContext.agentId,
1119
+ langfuse: this.langfuse,
1120
+ tokenCounter: agentContext.tokenCounter,
1121
+ maxDepth: effectiveSubagentDepth,
1122
+ createChildGraph: (input) => {
1123
+ const childGraph = new StandardGraph(input);
1124
+ childGraph.hookRegistry = this.hookRegistry;
1125
+ /**
1126
+ * Do not propagate `humanInTheLoop` into the child graph yet:
1127
+ * nested subagent interrupts need a stable child checkpoint and
1128
+ * resume bridge. Child hooks still fire; `ask` decisions fail
1129
+ * closed inside the subagent until that flow is implemented.
1130
+ */
1131
+ childGraph.toolOutputReferences = this.toolOutputReferences;
1132
+ childGraph.eagerEventToolExecution = this.eagerEventToolExecution;
1133
+ childGraph.toolExecution = this.toolExecution;
1134
+ childGraph.eventToolExecutionAvailable = this.handlerRegistry?.getHandler("on_tool_execute") != null;
1135
+ return childGraph;
1136
+ }
1137
+ });
1138
+ const subagentTool = tool(async (rawInput, config) => {
1139
+ const input = rawInput;
1140
+ const description = typeof input.description === "string" && input.description.trim().length > 0 ? input.description : "No task description provided";
1141
+ const subagentType = typeof input.subagent_type === "string" ? input.subagent_type : "";
1142
+ const threadId = config.configurable?.thread_id;
1143
+ /**
1144
+ * When the tool is dispatched from an LLM's `tool_call`, LangChain
1145
+ * threads the originating `ToolCall` onto the RunnableConfig as
1146
+ * `config.toolCall` (see `ToolRunnableConfig` in
1147
+ * `@langchain/core/tools` — internal but stable since ≥0.3.x).
1148
+ * Surfacing its id lets hosts correlate `SubagentUpdateEvent`s
1149
+ * back to the parent's `tool_call_id` deterministically — no
1150
+ * temporal heuristics needed. If a future LangChain version
1151
+ * changes the threading, the type-guarded read falls back to
1152
+ * `undefined` and the correlation degrades gracefully.
1153
+ */
1154
+ const toolCall = config.toolCall;
1155
+ const parentToolCallId = typeof toolCall?.id === "string" ? toolCall.id : void 0;
1156
+ return (await executor.execute({
1157
+ description,
1158
+ subagentType,
1159
+ threadId,
1160
+ parentToolCallId,
1161
+ /**
1162
+ * Forward the parent's `configurable` so host-set fields
1163
+ * (`requestBody`, `user`, etc.) propagate into the child
1164
+ * workflow. The executor scrubs run-identity fields before
1165
+ * forwarding — see `SubagentExecuteParams.parentConfigurable`.
1166
+ */
1167
+ parentConfigurable: config.configurable
1168
+ })).content;
1169
+ }, buildSubagentToolParams(resolvedConfigs));
1170
+ if (!agentContext.graphTools) agentContext.graphTools = [];
1171
+ agentContext.graphTools.push(subagentTool);
1172
+ /**
1173
+ * Refresh toolSchemaTokens to include the subagent tool's schema.
1174
+ * `calculateInstructionTokens()` was kicked off in `fromConfig()`
1175
+ * before graphTools was populated, so its result did not count this
1176
+ * tool. Without this retrigger, token-budget/pruning logic
1177
+ * underestimates prompt overhead.
1178
+ */
1179
+ if (agentContext.tokenCounter) {
1180
+ const { tokenCounter, baseIndexTokenCountMap } = agentContext;
1181
+ agentContext.tokenCalculationPromise = agentContext.calculateInstructionTokens(tokenCounter).then(() => {
1182
+ agentContext.updateTokenMapWithInstructions(baseIndexTokenCountMap);
1183
+ }).catch((err) => {
1184
+ console.error("Error recalculating instruction tokens after subagent tool injection:", err);
1185
+ });
1186
+ }
1187
+ }
1188
+ }
1189
+ const agentNode = `${AGENT}${agentId}`;
1190
+ const toolNode = `${TOOLS}${agentId}`;
1191
+ const summarizeNode = `${SUMMARIZE}${agentId}`;
1192
+ const routeMessage = (state, config) => {
1193
+ this.config = config;
1194
+ if (state.summarizationRequest != null) return summarizeNode;
1195
+ return toolsCondition(state, toolNode, this.invokedToolIds);
1196
+ };
1197
+ return new StateGraph(Annotation.Root({
1198
+ messages: Annotation({
1199
+ reducer: messagesStateReducer$1,
1200
+ default: () => []
1201
+ }),
1202
+ summarizationRequest: Annotation({
1203
+ reducer: (_, b) => b,
1204
+ default: () => void 0
1205
+ })
1206
+ })).addNode(agentNode, this.createCallModel(agentId)).addNode(toolNode, this.initializeTools({
1207
+ currentTools: agentContext.tools,
1208
+ currentToolMap: agentContext.toolMap,
1209
+ agentContext
1210
+ })).addNode(summarizeNode, createSummarizeNode({
1211
+ agentContext,
1212
+ graph: {
1213
+ contentData: this.contentData,
1214
+ contentIndexMap: this.contentIndexMap,
1215
+ get config() {
1216
+ return getConfig();
1217
+ },
1218
+ runId: this.runId,
1219
+ isMultiAgent: this.isMultiAgentGraph(),
1220
+ hookRegistry: this.hookRegistry,
1221
+ dispatchRunStep: async (runStep, nodeConfig) => {
1222
+ this.contentData.push(runStep);
1223
+ this.contentIndexMap.set(runStep.id, runStep.index);
1224
+ const resolvedConfig = nodeConfig ?? this.config;
1225
+ const handler = this.handlerRegistry?.getHandler("on_run_step");
1226
+ if (handler) {
1227
+ await handler.handle("on_run_step", runStep, resolvedConfig?.configurable, this);
1228
+ this.handlerDispatchedStepIds.add(runStep.id);
1229
+ }
1230
+ const unmarkHandlerDispatchedEvent = handler ? this.markHandlerDispatchedEvent("on_run_step", runStep.id) : void 0;
1231
+ try {
1232
+ if (resolvedConfig) await safeDispatchCustomEvent("on_run_step", runStep, resolvedConfig);
1233
+ } finally {
1234
+ unmarkHandlerDispatchedEvent?.();
1235
+ }
1236
+ },
1237
+ dispatchRunStepCompleted: async (stepId, result, nodeConfig) => {
1238
+ const resolvedConfig = nodeConfig ?? this.config;
1239
+ const runStep = this.contentData.find((s) => s.id === stepId);
1240
+ const handler = this.handlerRegistry?.getHandler("on_run_step_completed");
1241
+ if (handler) await handler.handle("on_run_step_completed", { result: {
1242
+ ...result,
1243
+ id: stepId,
1244
+ index: runStep?.index ?? 0
1245
+ } }, resolvedConfig?.configurable, this);
1246
+ }
1247
+ },
1248
+ generateStepId: (stepKey) => this.generateStepId(stepKey)
1249
+ })).addEdge(START, agentNode).addConditionalEdges(agentNode, routeMessage).addEdge(summarizeNode, agentNode).addEdge(toolNode, agentContext.toolEnd ? END : agentNode).compile();
1250
+ }
1251
+ createWorkflow() {
1252
+ const agentNode = this.createAgentNode(this.defaultAgentId);
1253
+ return new StateGraph(Annotation.Root({ messages: Annotation({
1254
+ reducer: (a, b) => {
1255
+ if (!this.messages.length) this.startIndex = a.length + b.length;
1256
+ const result = messagesStateReducer$1(a, b);
1257
+ this.messages = result;
1258
+ return result;
1259
+ },
1260
+ default: () => []
1261
+ }) })).addNode(this.defaultAgentId, agentNode, { ends: [END] }).addEdge(START, this.defaultAgentId).compile(this.compileOptions);
1262
+ }
1263
+ /**
1264
+ * Indicates if this is a multi-agent graph.
1265
+ * Override in MultiAgentGraph to return true.
1266
+ * Used to conditionally include agentId in RunStep for frontend rendering.
1267
+ */
1268
+ isMultiAgentGraph() {
1269
+ return false;
1270
+ }
1271
+ /**
1272
+ * Get the parallel group ID for an agent, if any.
1273
+ * Override in MultiAgentGraph to provide actual group IDs.
1274
+ * Group IDs are incrementing numbers (1, 2, 3...) reflecting execution order.
1275
+ * @param _agentId - The agent ID to look up
1276
+ * @returns undefined for StandardGraph (no parallel groups), or group number for MultiAgentGraph
1277
+ */
1278
+ getParallelGroupIdForAgent(_agentId) {}
1279
+ /**
1280
+ * Dispatches a run step to the client, returns the step ID
1281
+ */
1282
+ async dispatchRunStep(stepKey, stepDetails, metadata) {
1283
+ if (!this.config) throw new Error("No config provided");
1284
+ const [stepId, stepIndex] = this.generateStepId(stepKey);
1285
+ if (stepDetails.type === "tool_calls" && stepDetails.tool_calls) for (const tool_call of stepDetails.tool_calls) {
1286
+ const toolCallId = tool_call.id ?? "";
1287
+ if (!toolCallId || this.toolCallStepIds.has(toolCallId)) continue;
1288
+ this.toolCallStepIds.set(toolCallId, stepId);
1289
+ }
1290
+ const runStep = {
1291
+ stepIndex,
1292
+ id: stepId,
1293
+ type: stepDetails.type,
1294
+ index: this.contentData.length,
1295
+ stepDetails,
1296
+ usage: null
1297
+ };
1298
+ const runId = this.runId ?? "";
1299
+ if (runId) runStep.runId = runId;
1300
+ if (metadata) try {
1301
+ const agentContext = this.getAgentContext(metadata);
1302
+ if (this.isMultiAgentGraph() && agentContext.agentId) {
1303
+ runStep.agentId = agentContext.agentId;
1304
+ const groupId = this.getParallelGroupIdForAgent(agentContext.agentId);
1305
+ if (groupId != null) runStep.groupId = groupId;
1306
+ }
1307
+ } catch (_e) {}
1308
+ this.contentData.push(runStep);
1309
+ this.contentIndexMap.set(stepId, runStep.index);
1310
+ const handler = this.handlerRegistry?.getHandler("on_run_step");
1311
+ if (handler) {
1312
+ await handler.handle("on_run_step", runStep, metadata, this);
1313
+ this.handlerDispatchedStepIds.add(stepId);
1314
+ }
1315
+ const unmarkHandlerDispatchedEvent = handler ? this.markHandlerDispatchedEvent("on_run_step", stepId) : void 0;
1316
+ try {
1317
+ await safeDispatchCustomEvent("on_run_step", runStep, this.config);
1318
+ } finally {
1319
+ unmarkHandlerDispatchedEvent?.();
1320
+ }
1321
+ return stepId;
1322
+ }
1323
+ /**
1324
+ * Static version of handleToolCallError to avoid creating strong references
1325
+ * that prevent garbage collection
1326
+ */
1327
+ static async handleToolCallErrorStatic(graph, data, metadata) {
1328
+ if (!graph.config) throw new Error("No config provided");
1329
+ if (!data.id) {
1330
+ console.warn("No Tool ID provided for Tool Error");
1331
+ return;
1332
+ }
1333
+ const stepId = graph.toolCallStepIds.get(data.id) ?? "";
1334
+ if (!stepId) throw new Error(`No stepId found for tool_call_id ${data.id}`);
1335
+ const { name, input: args, error } = data;
1336
+ const runStep = graph.getRunStep(stepId);
1337
+ if (!runStep) throw new Error(`No run step found for stepId ${stepId}`);
1338
+ const tool_call = {
1339
+ id: data.id,
1340
+ name: name || "",
1341
+ args: typeof args === "string" ? args : JSON.stringify(args),
1342
+ output: `Error processing tool${error?.message != null ? `: ${error.message}` : ""}`,
1343
+ progress: 1
1344
+ };
1345
+ await graph.handlerRegistry?.getHandler("on_run_step_completed")?.handle("on_run_step_completed", { result: {
1346
+ id: stepId,
1347
+ index: runStep.index,
1348
+ type: "tool_call",
1349
+ tool_call
1350
+ } }, metadata, graph);
1351
+ }
1352
+ /**
1353
+ * Instance method that delegates to the static method
1354
+ * Kept for backward compatibility
1355
+ */
1356
+ async handleToolCallError(data, metadata) {
1357
+ await StandardGraph.handleToolCallErrorStatic(this, data, metadata);
1358
+ }
1359
+ async dispatchRunStepDelta(id, delta, metadata) {
1360
+ if (!this.config) throw new Error("No config provided");
1361
+ else if (!id) throw new Error("No step ID found");
1362
+ const runStepDelta = {
1363
+ id,
1364
+ delta
1365
+ };
1366
+ const handler = this.handlerRegistry?.getHandler("on_run_step_delta");
1367
+ if (handler) {
1368
+ await handler.handle("on_run_step_delta", runStepDelta, metadata, this);
1369
+ this.handlerDispatchedStepIds.add(id);
1370
+ }
1371
+ const unmarkHandlerDispatchedEvent = handler ? this.markHandlerDispatchedEvent("on_run_step_delta", id) : void 0;
1372
+ try {
1373
+ await safeDispatchCustomEvent("on_run_step_delta", runStepDelta, this.config);
1374
+ } finally {
1375
+ unmarkHandlerDispatchedEvent?.();
1376
+ }
1377
+ }
1378
+ async dispatchMessageDelta(id, delta, metadata) {
1379
+ if (!this.config) throw new Error("No config provided");
1380
+ const messageDelta = {
1381
+ id,
1382
+ delta
1383
+ };
1384
+ if (hasTextDeltaContent(delta.content)) this.messageStepHasTextDeltas.add(id);
1385
+ const handler = this.handlerRegistry?.getHandler("on_message_delta");
1386
+ if (handler) {
1387
+ await handler.handle("on_message_delta", messageDelta, metadata, this);
1388
+ this.handlerDispatchedStepIds.add(id);
1389
+ }
1390
+ const unmarkHandlerDispatchedEvent = handler ? this.markHandlerDispatchedEvent("on_message_delta", id) : void 0;
1391
+ try {
1392
+ await safeDispatchCustomEvent("on_message_delta", messageDelta, this.config);
1393
+ } finally {
1394
+ unmarkHandlerDispatchedEvent?.();
1395
+ }
1396
+ }
1397
+ dispatchReasoningDelta = async (stepId, delta, metadata) => {
1398
+ if (!this.config) throw new Error("No config provided");
1399
+ const reasoningDelta = {
1400
+ id: stepId,
1401
+ delta
1402
+ };
1403
+ if (hasReasoningDeltaContent(delta.content)) this.reasoningStepHasDeltas.add(stepId);
1404
+ const handler = this.handlerRegistry?.getHandler("on_reasoning_delta");
1405
+ if (handler) {
1406
+ await handler.handle("on_reasoning_delta", reasoningDelta, metadata, this);
1407
+ this.handlerDispatchedStepIds.add(stepId);
1408
+ }
1409
+ const unmarkHandlerDispatchedEvent = handler ? this.markHandlerDispatchedEvent("on_reasoning_delta", stepId) : void 0;
1410
+ try {
1411
+ await safeDispatchCustomEvent("on_reasoning_delta", reasoningDelta, this.config);
1412
+ } finally {
1413
+ unmarkHandlerDispatchedEvent?.();
1414
+ }
1415
+ };
1416
+ };
1417
+ //#endregion
1835
1418
  export { Graph, StandardGraph };
1836
- //# sourceMappingURL=Graph.mjs.map
1419
+
1420
+ //# sourceMappingURL=Graph.mjs.map