@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
package/dist/cjs/run.cjs CHANGED
@@ -1,1129 +1,919 @@
1
- 'use strict';
2
-
3
- var messages = require('@langchain/core/messages');
4
- var prompts = require('@langchain/core/prompts');
5
- var runnables = require('@langchain/core/runnables');
6
- var openai = require('@langchain/openai');
7
- var base = require('@langchain/core/callbacks/base');
8
- var langgraph = require('@langchain/langgraph');
9
- var langfuse = require('./langfuse.cjs');
10
- var langfuseToolOutputTracing = require('./langfuseToolOutputTracing.cjs');
11
- var callbacks = require('./utils/callbacks.cjs');
12
- var title = require('./utils/title.cjs');
13
- var instrumentation = require('./instrumentation.cjs');
14
- var tokens = require('./utils/tokens.cjs');
15
- var _enum = require('./common/enum.cjs');
16
- var MultiAgentGraph = require('./graphs/MultiAgentGraph.cjs');
17
- var Graph = require('./graphs/Graph.cjs');
18
- var init = require('./llm/init.cjs');
19
- var events = require('./events.cjs');
20
- var llm = require('./utils/llm.cjs');
21
- var executeHooks = require('./hooks/executeHooks.cjs');
22
- require('./hooks/createWorkspacePolicyHook.cjs');
23
-
24
- // src/run.ts
1
+ const require_langfuse = require("./langfuse.cjs");
2
+ const require_langfuseToolOutputTracing = require("./langfuseToolOutputTracing.cjs");
3
+ const require_callbacks = require("./utils/callbacks.cjs");
4
+ require("./common/enum.cjs");
5
+ require("./common/index.cjs");
6
+ const require_title = require("./utils/title.cjs");
7
+ const require_instrumentation = require("./instrumentation.cjs");
8
+ const require_tokens = require("./utils/tokens.cjs");
9
+ const require_llm = require("./utils/llm.cjs");
10
+ const require_events = require("./events.cjs");
11
+ const require_executeHooks = require("./hooks/executeHooks.cjs");
12
+ require("./hooks/index.cjs");
13
+ const require_init = require("./llm/init.cjs");
14
+ const require_Graph = require("./graphs/Graph.cjs");
15
+ const require_MultiAgentGraph = require("./graphs/MultiAgentGraph.cjs");
16
+ let _langchain_core_messages = require("@langchain/core/messages");
17
+ let _langchain_core_prompts = require("@langchain/core/prompts");
18
+ let _langchain_core_runnables = require("@langchain/core/runnables");
19
+ let _langchain_openai = require("@langchain/openai");
20
+ let _langchain_core_callbacks_base = require("@langchain/core/callbacks/base");
21
+ let _langchain_langgraph = require("@langchain/langgraph");
22
+ //#region src/run.ts
25
23
  const defaultOmitOptions = new Set([
26
- 'stream',
27
- 'thinking',
28
- 'streaming',
29
- 'maxTokens',
30
- 'clientOptions',
31
- 'thinkingConfig',
32
- 'thinkingBudget',
33
- 'includeThoughts',
34
- 'maxOutputTokens',
35
- 'additionalModelRequestFields',
24
+ "stream",
25
+ "thinking",
26
+ "streaming",
27
+ "maxTokens",
28
+ "clientOptions",
29
+ "thinkingConfig",
30
+ "thinkingBudget",
31
+ "includeThoughts",
32
+ "maxOutputTokens",
33
+ "additionalModelRequestFields"
36
34
  ]);
37
35
  const CUSTOM_GRAPH_EVENTS = new Set([
38
- _enum.GraphEvents.ON_AGENT_UPDATE,
39
- _enum.GraphEvents.ON_RUN_STEP,
40
- _enum.GraphEvents.ON_RUN_STEP_DELTA,
41
- _enum.GraphEvents.ON_RUN_STEP_COMPLETED,
42
- _enum.GraphEvents.ON_MESSAGE_DELTA,
43
- _enum.GraphEvents.ON_REASONING_DELTA,
44
- _enum.GraphEvents.ON_TOOL_EXECUTE,
45
- _enum.GraphEvents.ON_SUMMARIZE_START,
46
- _enum.GraphEvents.ON_SUMMARIZE_DELTA,
47
- _enum.GraphEvents.ON_SUMMARIZE_COMPLETE,
48
- _enum.GraphEvents.ON_SUBAGENT_UPDATE,
49
- _enum.GraphEvents.ON_AGENT_LOG,
50
- _enum.GraphEvents.ON_CUSTOM_EVENT,
36
+ "on_agent_update",
37
+ "on_run_step",
38
+ "on_run_step_delta",
39
+ "on_run_step_completed",
40
+ "on_message_delta",
41
+ "on_reasoning_delta",
42
+ "on_tool_execute",
43
+ "on_summarize_start",
44
+ "on_summarize_delta",
45
+ "on_summarize_complete",
46
+ "on_subagent_update",
47
+ "on_agent_log",
48
+ "on_custom_event"
51
49
  ]);
52
50
  const DIRECT_DISPATCHED_STEP_EVENTS = new Set([
53
- _enum.GraphEvents.ON_RUN_STEP,
54
- _enum.GraphEvents.ON_RUN_STEP_DELTA,
55
- _enum.GraphEvents.ON_MESSAGE_DELTA,
56
- _enum.GraphEvents.ON_REASONING_DELTA,
51
+ "on_run_step",
52
+ "on_run_step_delta",
53
+ "on_message_delta",
54
+ "on_reasoning_delta"
57
55
  ]);
58
56
  function getStepScopedEventId(data) {
59
- if (data == null || typeof data !== 'object') {
60
- return undefined;
61
- }
62
- const candidate = data;
63
- return typeof candidate.id === 'string' ? candidate.id : undefined;
57
+ if (data == null || typeof data !== "object") return;
58
+ const candidate = data;
59
+ return typeof candidate.id === "string" ? candidate.id : void 0;
64
60
  }
65
61
  function isLangGraphResumeMapForInterrupt(value, interruptId) {
66
- if (value === null || typeof value !== 'object' || Array.isArray(value)) {
67
- return false;
68
- }
69
- return Object.prototype.hasOwnProperty.call(value, interruptId);
70
- }
71
- class Run {
72
- id;
73
- tokenCounter;
74
- handlerRegistry;
75
- hookRegistry;
76
- humanInTheLoop;
77
- langfuse;
78
- toolOutputReferences;
79
- eagerEventToolExecution;
80
- toolExecution;
81
- indexTokenCountMap;
82
- calibrationRatio = 1;
83
- graphRunnable;
84
- Graph;
85
- returnContent = false;
86
- skipCleanup = false;
87
- _streamResult;
88
- /**
89
- * Captured interrupt payload typed as `unknown` because the SDK
90
- * does not validate the runtime shape — custom graph nodes can
91
- * raise interrupts with arbitrary payloads (not just the SDK's
92
- * `HumanInterruptPayload` union). The public `getInterrupt<T>()`
93
- * lets callers assert the type they expect.
94
- */
95
- _interrupt;
96
- _haltedReason;
97
- constructor(config) {
98
- const runId = config.runId ?? '';
99
- if (!runId) {
100
- throw new Error('Run ID not provided');
101
- }
102
- this.id = runId;
103
- this.tokenCounter = config.tokenCounter;
104
- this.indexTokenCountMap = config.indexTokenCountMap;
105
- if (config.calibrationRatio != null && config.calibrationRatio > 0) {
106
- this.calibrationRatio = config.calibrationRatio;
107
- }
108
- const handlerRegistry = new events.HandlerRegistry();
109
- if (config.customHandlers) {
110
- for (const [eventType, handler] of Object.entries(config.customHandlers)) {
111
- handlerRegistry.register(eventType, handler);
112
- }
113
- }
114
- this.handlerRegistry = handlerRegistry;
115
- this.hookRegistry = config.hooks;
116
- this.humanInTheLoop = config.humanInTheLoop;
117
- this.langfuse = config.langfuse;
118
- this.toolOutputReferences = config.toolOutputReferences;
119
- this.eagerEventToolExecution = config.eagerEventToolExecution;
120
- this.toolExecution = config.toolExecution;
121
- if (!config.graphConfig) {
122
- throw new Error('Graph config not provided');
123
- }
124
- /** Handle different graph types */
125
- if (config.graphConfig.type === 'multi-agent') {
126
- this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);
127
- if (this.Graph) {
128
- this.Graph.handlerRegistry = handlerRegistry;
129
- }
130
- }
131
- else {
132
- /** Default to legacy graph for 'standard' or undefined type */
133
- this.graphRunnable = this.createLegacyGraph(config.graphConfig);
134
- if (this.Graph) {
135
- this.Graph.compileOptions =
136
- config.graphConfig.compileOptions ?? this.Graph.compileOptions;
137
- this.Graph.handlerRegistry = handlerRegistry;
138
- }
139
- }
140
- if (config.initialSessions && this.Graph) {
141
- for (const [key, value] of config.initialSessions) {
142
- this.Graph.sessions.set(key, value);
143
- }
144
- }
145
- this.returnContent = config.returnContent ?? false;
146
- this.skipCleanup = config.skipCleanup ?? false;
147
- }
148
- createLegacyGraph(config) {
149
- let agentConfig;
150
- let signal;
151
- /** Check if this is a multi-agent style config (has agents array) */
152
- if ('agents' in config && Array.isArray(config.agents)) {
153
- if (config.agents.length === 0) {
154
- throw new Error('At least one agent must be provided');
155
- }
156
- agentConfig = config.agents[0];
157
- signal = config.signal;
158
- }
159
- else {
160
- /** Legacy path: build agent config from llmConfig */
161
- const { type: _type, llmConfig, signal: legacySignal, tools = [], ...agentInputs } = config;
162
- const { provider, ...clientOptions } = llmConfig;
163
- agentConfig = {
164
- ...agentInputs,
165
- tools,
166
- provider,
167
- clientOptions,
168
- agentId: 'default',
169
- };
170
- signal = legacySignal;
171
- }
172
- const standardGraph = new Graph.StandardGraph({
173
- signal,
174
- runId: this.id,
175
- agents: [agentConfig],
176
- langfuse: this.langfuse,
177
- tokenCounter: this.tokenCounter,
178
- indexTokenCountMap: this.indexTokenCountMap,
179
- calibrationRatio: this.calibrationRatio,
180
- });
181
- /** Propagate compile options from graph config */
182
- standardGraph.compileOptions = this.applyHITLCheckpointerFallback(config.compileOptions);
183
- standardGraph.hookRegistry = this.hookRegistry;
184
- standardGraph.humanInTheLoop = this.humanInTheLoop;
185
- standardGraph.toolOutputReferences = this.toolOutputReferences;
186
- standardGraph.eagerEventToolExecution = this.eagerEventToolExecution;
187
- standardGraph.toolExecution = this.toolExecution;
188
- this.Graph = standardGraph;
189
- return standardGraph.createWorkflow();
190
- }
191
- createMultiAgentGraph(config) {
192
- const { agents, edges, compileOptions } = config;
193
- const multiAgentGraph = new MultiAgentGraph.MultiAgentGraph({
194
- runId: this.id,
195
- agents,
196
- edges,
197
- langfuse: this.langfuse,
198
- tokenCounter: this.tokenCounter,
199
- indexTokenCountMap: this.indexTokenCountMap,
200
- calibrationRatio: this.calibrationRatio,
201
- });
202
- multiAgentGraph.compileOptions =
203
- this.applyHITLCheckpointerFallback(compileOptions);
204
- multiAgentGraph.hookRegistry = this.hookRegistry;
205
- multiAgentGraph.humanInTheLoop = this.humanInTheLoop;
206
- multiAgentGraph.toolOutputReferences = this.toolOutputReferences;
207
- multiAgentGraph.eagerEventToolExecution = this.eagerEventToolExecution;
208
- multiAgentGraph.toolExecution = this.toolExecution;
209
- this.Graph = multiAgentGraph;
210
- return multiAgentGraph.createWorkflow();
211
- }
212
- /**
213
- * When the host opted into HITL via `humanInTheLoop: { enabled: true }`
214
- * and did not supply a checkpointer, install an in-memory `MemorySaver`
215
- * so `interrupt()` can persist checkpoints and `Command({ resume })`
216
- * can rebuild state. The fallback is intentionally process-local:
217
- * production hosts that need durable resumption across processes /
218
- * restarts must provide their own checkpointer (Redis, Postgres, etc.)
219
- * on `compileOptions.checkpointer`.
220
- *
221
- * No-op when HITL is off (the default — omitted, or
222
- * `{ enabled: false }`) or the host already supplied a checkpointer
223
- * of their own. See `HumanInTheLoopConfig` JSDoc for the rationale
224
- * behind the default-off stance.
225
- */
226
- applyHITLCheckpointerFallback(compileOptions) {
227
- if (this.humanInTheLoop?.enabled !== true) {
228
- return compileOptions;
229
- }
230
- if (compileOptions?.checkpointer != null) {
231
- return compileOptions;
232
- }
233
- return {
234
- ...(compileOptions ?? {}),
235
- checkpointer: new langgraph.MemorySaver(),
236
- };
237
- }
238
- /**
239
- * Run RunStart + UserPromptSubmit hooks before the graph stream
240
- * begins, accumulate any `additionalContext` strings into the input
241
- * messages, and short-circuit when a hook signals the run should not
242
- * proceed (deny / ask decision on the prompt, or `preventContinuation`
243
- * on either hook).
244
- *
245
- * Returns `true` when the caller should bail with `undefined` (run
246
- * was halted before any model call); returns `false` to proceed
247
- * into the stream loop.
248
- *
249
- * ## Side effects
250
- *
251
- * On the success path:
252
- * - Mutates `stateInputs.messages` in place to append a
253
- * consolidated `HumanMessage` carrying any hook
254
- * `additionalContext` strings. Safe because the host owns the
255
- * array and `processStream` is the only consumer until LangGraph
256
- * reads it.
257
- *
258
- * On the halt path (returning `true`):
259
- * - Sets `this._haltedReason` so callers (and the eventual host)
260
- * can distinguish a hook-driven halt from a natural completion.
261
- * - Calls `registry.clearSession(this.id)` and
262
- * `registry.clearHaltSignal(this.id)` because no resume is
263
- * expected from a pre-stream halt — the run never entered the
264
- * graph, so the session/halt state for this run would otherwise
265
- * leak to the next `processStream` invocation on the same
266
- * registry. Other concurrent runs on the same registry are
267
- * untouched (halt signals are scoped per session id).
268
- * - Sets `config.callbacks = undefined` to drop the callback
269
- * references the caller built (langfuse handler, custom event
270
- * handler, etc.) since they won't be exercised. Mirrors the
271
- * equivalent cleanup the `processStream` `finally` block does
272
- * on the natural-completion path.
273
- */
274
- async runPreStreamHooks(stateInputs, threadId, config) {
275
- const registry = this.hookRegistry;
276
- /**
277
- * Defensive guard: `processStream` already validated `this.Graph`
278
- * before calling this helper, but TypeScript can't propagate that
279
- * narrowing across method boundaries. The check keeps the body
280
- * free of `this.Graph!` non-null assertions.
281
- */
282
- if (registry == null || this.Graph == null) {
283
- return false;
284
- }
285
- const preStreamContexts = [];
286
- const runStartResult = await executeHooks.executeHooks({
287
- registry,
288
- input: {
289
- hook_event_name: 'RunStart',
290
- runId: this.id,
291
- threadId,
292
- agentId: this.Graph.defaultAgentId,
293
- messages: stateInputs.messages,
294
- },
295
- sessionId: this.id,
296
- });
297
- for (const ctx of runStartResult.additionalContexts) {
298
- preStreamContexts.push(ctx);
299
- }
300
- /**
301
- * Honor `preventContinuation` from RunStart before the stream
302
- * starts. Mid-flight halts (from tool/compact/subagent hooks)
303
- * route through `HookRegistry.haltRun` and are polled by the
304
- * stream loop in `processStream` — different mechanism, same
305
- * intent.
306
- */
307
- if (runStartResult.preventContinuation === true) {
308
- this._haltedReason = runStartResult.stopReason ?? 'preventContinuation';
309
- registry.clearSession(this.id);
310
- registry.clearHaltSignal(this.id);
311
- config.callbacks = undefined;
312
- return true;
313
- }
314
- const lastHuman = findLastMessageOfType(stateInputs.messages, 'human');
315
- if (lastHuman != null) {
316
- const promptResult = await executeHooks.executeHooks({
317
- registry,
318
- input: {
319
- hook_event_name: 'UserPromptSubmit',
320
- runId: this.id,
321
- threadId,
322
- agentId: this.Graph.defaultAgentId,
323
- prompt: extractPromptText(lastHuman),
324
- // attachments: not yet wired — Phase 2 will extract
325
- // non-text content blocks (images, files) from messages
326
- },
327
- sessionId: this.id,
328
- });
329
- if (promptResult.decision === 'deny' ||
330
- promptResult.decision === 'ask' ||
331
- promptResult.preventContinuation === true) {
332
- /**
333
- * Always set `_haltedReason` so the host can call
334
- * `getHaltReason()` and distinguish a hook-blocked prompt
335
- * from a natural empty-output completion. Three signals can
336
- * land here, each with its own canonical reason string when
337
- * the hook didn't supply one.
338
- */
339
- if (promptResult.preventContinuation === true) {
340
- this._haltedReason = promptResult.stopReason ?? 'preventContinuation';
341
- }
342
- else if (promptResult.decision === 'deny') {
343
- this._haltedReason = promptResult.reason ?? 'prompt_denied';
344
- }
345
- else {
346
- this._haltedReason =
347
- promptResult.reason ?? 'prompt_requires_approval';
348
- }
349
- registry.clearSession(this.id);
350
- registry.clearHaltSignal(this.id);
351
- config.callbacks = undefined;
352
- return true;
353
- }
354
- for (const ctx of promptResult.additionalContexts) {
355
- preStreamContexts.push(ctx);
356
- }
357
- }
358
- if (preStreamContexts.length > 0) {
359
- /**
360
- * Wraps the joined hook contexts as a `HumanMessage` even though
361
- * the intent is system-level guidance. Using a `SystemMessage`
362
- * mid-conversation is rejected by Anthropic and Google providers
363
- * (system messages must be the leading entry), so the LangChain
364
- * convention — also used by `ToolNode.convertInjectedMessages`
365
- * — is `HumanMessage` carrying `additional_kwargs.role` as a
366
- * marker for hosts inspecting state. The model still sees a
367
- * user-role message; the `role: 'system'` field is metadata
368
- * only. Hosts that want a true system message should compose
369
- * it into the agent's `instructions` config instead.
370
- */
371
- stateInputs.messages.push(new messages.HumanMessage({
372
- content: preStreamContexts.join('\n\n'),
373
- additional_kwargs: { role: 'system', source: 'hook' },
374
- }));
375
- }
376
- return false;
377
- }
378
- static async create(config) {
379
- /** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */
380
- if (config.indexTokenCountMap && !config.tokenCounter) {
381
- const gc = config.graphConfig;
382
- const clientOpts = 'agents' in gc ? gc.agents[0]?.clientOptions : gc.clientOptions;
383
- const model = clientOpts?.model ?? '';
384
- config.tokenCounter = await tokens.createTokenCounter(tokens.encodingForModel(model));
385
- }
386
- return new Run(config);
387
- }
388
- getRunMessages() {
389
- if (!this.Graph) {
390
- throw new Error('Graph not initialized. Make sure to use Run.create() to instantiate the Run.');
391
- }
392
- return this.Graph.getRunMessages();
393
- }
394
- /**
395
- * Returns the current calibration ratio (EMA of provider-vs-estimate token ratios).
396
- * Hosts should persist this value and pass it back as `RunConfig.calibrationRatio`
397
- * on the next run for the same conversation so the pruner starts with an accurate
398
- * scaling factor instead of the default (1).
399
- */
400
- getCalibrationRatio() {
401
- return this.calibrationRatio;
402
- }
403
- getResolvedInstructionOverhead() {
404
- return this.Graph?.getResolvedInstructionOverhead();
405
- }
406
- getToolCount() {
407
- return this.Graph?.getToolCount() ?? 0;
408
- }
409
- /**
410
- * Creates a custom event callback handler that intercepts custom events
411
- * and processes them through our handler registry instead of EventStreamCallbackHandler
412
- */
413
- createCustomEventCallback() {
414
- return async (eventName, data, runId, tags, metadata) => {
415
- // Step-scoped SDK events are dispatched directly via the handler
416
- // registry first. Skip callback-based echoes to prevent double
417
- // handling when LangGraph invokes custom callbacks more than once.
418
- const stepScopedEventId = getStepScopedEventId(data);
419
- if (DIRECT_DISPATCHED_STEP_EVENTS.has(eventName) &&
420
- this.Graph != null &&
421
- stepScopedEventId != null &&
422
- this.Graph.hasHandlerDispatchedEvent(eventName, stepScopedEventId)) {
423
- return;
424
- }
425
- const handler = this.handlerRegistry?.getHandler(eventName);
426
- if (handler && this.Graph) {
427
- return await handler.handle(eventName, data, metadata, this.Graph);
428
- }
429
- };
430
- }
431
- shouldClearHookSession(streamThrew) {
432
- return this._interrupt == null || this._haltedReason != null || streamThrew;
433
- }
434
- isAwaitingResume(streamThrew) {
435
- return (this._interrupt != null && this._haltedReason == null && !streamThrew);
436
- }
437
- getStreamLangfuseConfig(graph) {
438
- const primaryContext = graph.agentContexts.get(graph.defaultAgentId);
439
- if (primaryContext != null) {
440
- return langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, primaryContext.langfuse);
441
- }
442
- for (const context of graph.agentContexts.values()) {
443
- const langfuse = langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, context.langfuse);
444
- if (langfuse != null) {
445
- return langfuse;
446
- }
447
- }
448
- return this.langfuse;
449
- }
450
- getStreamToolOutputTracingLangfuseConfig(graph) {
451
- const toolOutputTracingConfigs = Array.from(graph.agentContexts.values())
452
- .map((context) => {
453
- return langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, context.langfuse)
454
- ?.toolOutputTracing;
455
- })
456
- .filter((config) => {
457
- return config != null;
458
- });
459
- if (toolOutputTracingConfigs.length === 0) {
460
- return this.langfuse?.toolOutputTracing != null
461
- ? { toolOutputTracing: this.langfuse.toolOutputTracing }
462
- : undefined;
463
- }
464
- if (toolOutputTracingConfigs.length === 1) {
465
- return { toolOutputTracing: toolOutputTracingConfigs[0] };
466
- }
467
- let enabled;
468
- let redactionText;
469
- let redactedToolNameMatchMode;
470
- const redactedToolNames = new Set();
471
- for (const config of toolOutputTracingConfigs) {
472
- if (config.enabled === false) {
473
- enabled = false;
474
- }
475
- else if (enabled !== false && config.enabled != null) {
476
- enabled = config.enabled;
477
- }
478
- redactionText ??= config.redactionText;
479
- if (config.redactedToolNameMatchMode === 'partial') {
480
- redactedToolNameMatchMode = 'partial';
481
- }
482
- else {
483
- redactedToolNameMatchMode ??= config.redactedToolNameMatchMode;
484
- }
485
- for (const toolName of config.redactedToolNames ?? []) {
486
- redactedToolNames.add(toolName);
487
- }
488
- }
489
- return {
490
- toolOutputTracing: {
491
- ...(enabled != null ? { enabled } : {}),
492
- ...(redactedToolNames.size > 0
493
- ? { redactedToolNames: Array.from(redactedToolNames) }
494
- : {}),
495
- ...(redactedToolNameMatchMode != null
496
- ? { redactedToolNameMatchMode }
497
- : {}),
498
- ...(redactionText != null ? { redactionText } : {}),
499
- },
500
- };
501
- }
502
- async processStream(inputs, callerConfig, streamOptions) {
503
- if (this.graphRunnable == null) {
504
- throw new Error('Run not initialized. Make sure to use Run.create() to instantiate the Run.');
505
- }
506
- if (!this.Graph) {
507
- throw new Error('Graph not initialized. Make sure to use Run.create() to instantiate the Run.');
508
- }
509
- const graphRunnable = this.graphRunnable;
510
- const graph = this.Graph;
511
- /**
512
- * `Command` inputs (currently only `Command({ resume })`) are
513
- * resume-mode invocations: LangGraph rebuilds graph state from the
514
- * checkpointer, so we skip RunStart / UserPromptSubmit hooks (no
515
- * new prompt to evaluate) and read run-state from the Graph wrapper
516
- * instead of `inputs.messages`.
517
- */
518
- const isResume = inputs instanceof langgraph.Command;
519
- const stateInputs = isResume ? undefined : inputs;
520
- const config = {
521
- recursionLimit: 50,
522
- ...callerConfig,
523
- configurable: { ...callerConfig.configurable },
524
- };
525
- /**
526
- * Skip `resetValues` on resume — we're continuing an in-flight
527
- * run, not starting a fresh one. Resetting would wipe the
528
- * sidecars (`toolCallStepIds`, `stepKeyIds`, accumulated
529
- * `messages`, etc.) the resumed `ToolNode` needs to dispatch
530
- * tool completions with the correct step ids and re-resolve
531
- * `{{tool<i>turn<n>}}` references. Pairs with the
532
- * `awaitingResume` gate on `clearHeavyState` in the `finally`
533
- * block so the sidecars survive both ends of the interrupt
534
- * boundary.
535
- */
536
- if (!isResume) {
537
- graph.resetValues(streamOptions?.keepContent);
538
- }
539
- this._interrupt = undefined;
540
- this._haltedReason = undefined;
541
- this.hookRegistry?.clearHaltSignal(this.id);
542
- /** Custom event callback to intercept and handle custom events */
543
- const customEventCallback = this.createCustomEventCallback();
544
- const streamCallbacks = streamOptions?.callbacks
545
- ? this.getCallbacks(streamOptions.callbacks)
546
- : undefined;
547
- const customHandler = base.BaseCallbackHandler.fromMethods({
548
- [_enum.Callback.CUSTOM_EVENT]: customEventCallback,
549
- });
550
- customHandler.awaitHandlers = true;
551
- config.callbacks = callbacks.appendCallbacks(config.callbacks, streamCallbacks ? [streamCallbacks, customHandler] : [customHandler]);
552
- const primaryContext = graph.agentContexts.get(graph.defaultAgentId);
553
- const userId = typeof config.configurable?.user_id === 'string'
554
- ? config.configurable.user_id
555
- : undefined;
556
- const sessionId = typeof config.configurable?.thread_id === 'string'
557
- ? config.configurable.thread_id
558
- : undefined;
559
- const traceMetadata = langfuse.createLangfuseTraceMetadata({
560
- messageId: this.id,
561
- parentMessageId: config.configurable?.requestBody?.parentMessageId,
562
- agentId: graph.defaultAgentId,
563
- agentName: primaryContext?.name,
564
- });
565
- const traceName = config.runName ?? langfuse.getLangfuseTraceName(traceMetadata);
566
- const streamLangfuseConfig = this.getStreamLangfuseConfig(graph);
567
- instrumentation.initializeLangfuseTracing(streamLangfuseConfig);
568
- const langfuseHandler = langfuse.createLangfuseHandler({
569
- langfuse: streamLangfuseConfig,
570
- userId,
571
- sessionId,
572
- traceMetadata,
573
- tags: ['librechat', 'agent'],
574
- });
575
- if (langfuseHandler != null) {
576
- config.runName = traceName;
577
- config.callbacks = callbacks.appendCallbacks(config.callbacks, [langfuseHandler]);
578
- }
579
- if (!this.id) {
580
- throw new Error('Run ID not provided');
581
- }
582
- config.run_id = this.id;
583
- config.configurable = Object.assign(config.configurable ?? {}, {
584
- run_id: this.id,
585
- });
586
- const threadId = config.configurable.thread_id;
587
- if (this.hookRegistry != null && stateInputs != null) {
588
- const shouldHalt = await this.runPreStreamHooks(stateInputs, threadId, config);
589
- if (shouldHalt) {
590
- return undefined;
591
- }
592
- }
593
- /**
594
- * Tracks whether the stream loop threw. Used by the `finally`
595
- * block to decide whether to honor the interrupt-preservation
596
- * guard for session hooks: a captured `_interrupt` is only
597
- * meaningful if the stream completed cleanly. If the loop errored
598
- * after stashing an interrupt (e.g. a downstream handler throws
599
- * after the interrupt event landed), the interrupt is stale —
600
- * preserving session hooks would leak them into the next run.
601
- */
602
- let streamThrew = false;
603
- const consumeStream = async () => {
604
- /**
605
- * `streamEvents` accepts both state inputs and `Command` (resume) at
606
- * runtime, but our `CompiledStateWorkflow` type narrows the first
607
- * arg to `BaseGraphState`. Cast on the call so the resume path
608
- * type-checks without widening the wrapper for every caller.
609
- */
610
- const stream = graphRunnable.streamEvents(inputs, config, {
611
- raiseError: true,
612
- /**
613
- * Prevent EventStreamCallbackHandler from processing custom events.
614
- * Custom events are already handled via our createCustomEventCallback()
615
- * which routes them through the handlerRegistry.
616
- * Without this flag, EventStreamCallbackHandler throws errors when
617
- * custom events are dispatched for run IDs not in its internal map
618
- * (due to timing issues in parallel execution or after run cleanup).
619
- */
620
- ignoreCustomEvent: true,
621
- });
622
- for await (const event of stream) {
623
- const { data, metadata, ...info } = event;
624
- const eventName = info.event;
625
- /** Skip custom events as they're handled by our callback */
626
- if (CUSTOM_GRAPH_EVENTS.has(eventName)) {
627
- continue;
628
- }
629
- /**
630
- * Detect interrupts surfaced by LangGraph as a synthetic
631
- * `__interrupt__` field on the streamed chunk and stash the
632
- * first one for the host to read via `run.getInterrupt()`
633
- * once the stream drains. Captured as `unknown` because the
634
- * SDK does not validate the runtime payload shape — the
635
- * built-in ToolNode raises a `HumanInterruptPayload`
636
- * (`tool_approval` / `ask_user_question`), but custom nodes
637
- * can pass any payload to `interrupt()`. Callers narrow with
638
- * the `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt`
639
- * guards or assert via `getInterrupt<T>()`.
640
- */
641
- if (this._interrupt == null &&
642
- data.chunk != null &&
643
- langgraph.isInterrupted(data.chunk)) {
644
- const interrupts = data.chunk[langgraph.INTERRUPT];
645
- if (interrupts.length > 0) {
646
- const first = interrupts[0];
647
- /**
648
- * Capture the interrupt unconditionally — `interrupt(null)`
649
- * and `interrupt(undefined)` are valid pauses (a custom
650
- * node may want to pause without metadata) and the host
651
- * still needs to know the run is awaiting resume. Gating
652
- * on `payload != null` would silently downgrade a paused
653
- * run to "completed" and let the `Stop` hook fire,
654
- * breaking host resume handling.
655
- */
656
- this._interrupt = {
657
- interruptId: first.id ?? '',
658
- threadId,
659
- payload: first.value,
660
- };
661
- }
662
- }
663
- const handler = this.handlerRegistry?.getHandler(eventName);
664
- if (handler) {
665
- await handler.handle(eventName, data, metadata, this.Graph);
666
- }
667
- /**
668
- * Mid-flight halt: any hook (PreToolUse, PostToolUse,
669
- * PostToolBatch, SubagentStart/Stop, PreCompact, PostCompact)
670
- * that returned `preventContinuation: true` raises a halt
671
- * signal on the registry via `executeHooks`. We poll between
672
- * stream events and break out as soon as one is set so the
673
- * graph doesn't take another model turn after the halting
674
- * operation completes.
675
- *
676
- * Limitation: the current step (in-flight model call, ongoing
677
- * tool batch) is not aborted — only the next step is skipped.
678
- * This matches Claude Code's `continue: false` semantic where
679
- * the active operation finishes before halting takes effect.
680
- */
681
- const haltSignal = this.hookRegistry?.getHaltSignal(this.id);
682
- if (haltSignal != null) {
683
- this._haltedReason = haltSignal.reason;
684
- break;
685
- }
686
- }
687
- if (this._interrupt != null) {
688
- await this.resolveInterruptResumeConfig(config);
689
- }
690
- /**
691
- * Skip the Stop hook when the run paused on a HITL interrupt
692
- * (still pending human input) or was halted by a hook (the host
693
- * already chose to stop, so a Stop hook firing now would be
694
- * misleading). The host fires Stop on the resumed-and-completed
695
- * run instead.
696
- */
697
- if (this._interrupt == null &&
698
- this._haltedReason == null &&
699
- this.hookRegistry?.hasHookFor('Stop', this.id) === true) {
700
- await executeHooks.executeHooks({
701
- registry: this.hookRegistry,
702
- input: {
703
- hook_event_name: 'Stop',
704
- runId: this.id,
705
- threadId,
706
- agentId: graph.defaultAgentId,
707
- messages: graph.getRunMessages() ?? stateInputs?.messages ?? [],
708
- stopHookActive: false, // will be true when stop is triggered by a hook (Phase 2)
709
- },
710
- sessionId: this.id,
711
- }).catch(() => {
712
- /* Stop hook errors must not masquerade as stream failures */
713
- });
714
- }
715
- };
716
- try {
717
- // When opted in, seed the root trace id from this run's id so feedback /
718
- // other external signals can be attached to the trace later without a
719
- // lookup (see SeededTraceIdGenerator in ./instrumentation).
720
- await instrumentation.runWithTraceIdSeed(streamLangfuseConfig?.deterministicTraceId === true
721
- ? this.id
722
- : undefined, () => langfuseToolOutputTracing.withLangfuseToolOutputTracingConfig(streamLangfuseConfig, () => langfuse.withLangfuseAttributes({
723
- langfuse: streamLangfuseConfig,
724
- userId,
725
- sessionId,
726
- traceName,
727
- traceMetadata,
728
- tags: ['librechat', 'agent'],
729
- }, consumeStream), this.getStreamToolOutputTracingLangfuseConfig(graph)));
730
- }
731
- catch (err) {
732
- streamThrew = true;
733
- if (this.hookRegistry?.hasHookFor('StopFailure', this.id) === true) {
734
- const runMessages = this.Graph.getRunMessages() ?? [];
735
- await executeHooks.executeHooks({
736
- registry: this.hookRegistry,
737
- input: {
738
- hook_event_name: 'StopFailure',
739
- runId: this.id,
740
- threadId,
741
- agentId: this.Graph.defaultAgentId,
742
- error: err instanceof Error ? err.message : String(err),
743
- lastAssistantMessage: findLastMessageOfType(runMessages, 'ai'),
744
- },
745
- sessionId: this.id,
746
- }).catch(() => {
747
- /* swallow hook errors — the original error must propagate */
748
- });
749
- }
750
- throw err;
751
- }
752
- finally {
753
- /**
754
- * Preserve session-scoped hooks when the run paused on a HITL
755
- * interrupt — the very next call will be `Run.resume()`, which
756
- * needs the same policy hooks (e.g., the `PreToolUse` matcher
757
- * that triggered the interrupt) to fire on the re-executed node
758
- * and uphold the approval flow. Clearing here would leak the
759
- * approval gate on resume. The session is cleared instead at
760
- * natural completion, error (including errors that happen AFTER
761
- * an interrupt was captured — those interrupts are stale), or
762
- * hook-driven halt (including hooks that returned BOTH `ask`
763
- * and `preventContinuation` — the halt wins, no resume is
764
- * expected, sessions must drop). Every state where no resume
765
- * is expected clears.
766
- */
767
- if (this.shouldClearHookSession(streamThrew)) {
768
- this.hookRegistry?.clearSession(this.id);
769
- }
770
- /**
771
- * Drop any halt signal raised mid-stream for this run so a
772
- * subsequent `processStream` / `resume` starts with clean state.
773
- * The Run captured `_haltedReason` already; the registry entry
774
- * for this `sessionId` would otherwise spuriously trip the next
775
- * loop. Other concurrent runs sharing this registry are
776
- * unaffected — their entries live under their own session ids.
777
- */
778
- this.hookRegistry?.clearHaltSignal(this.id);
779
- await langfuse.disposeLangfuseHandler(langfuseHandler);
780
- /**
781
- * Break the reference chain that keeps heavy data alive via
782
- * LangGraph's internal `__pregel_scratchpad.currentTaskInput` →
783
- * `@langchain/core` `RunTree.extra[lc:child_config]` →
784
- * Node.js `AsyncLocalStorage` context captured by timers/promises.
785
- *
786
- * Without this, base64-encoded images/PDFs in message content remain
787
- * reachable from lingering `Timeout` handles until GC runs.
788
- */
789
- if (!this.skipCleanup) {
790
- if (config.configurable != null) {
791
- for (const key of Object.getOwnPropertySymbols(config.configurable)) {
792
- const val = config.configurable[key];
793
- if (val != null &&
794
- typeof val === 'object' &&
795
- 'currentTaskInput' in val) {
796
- val.currentTaskInput = undefined;
797
- }
798
- delete config.configurable[key];
799
- }
800
- config.configurable = undefined;
801
- }
802
- config.callbacks = undefined;
803
- }
804
- const result = this.returnContent
805
- ? this.Graph.getContentParts()
806
- : undefined;
807
- this.calibrationRatio = this.Graph.getCalibrationRatio();
808
- /**
809
- * Skip `clearHeavyState()` when the run paused on a clean HITL
810
- * interrupt awaiting resume — `Run.resume()` re-enters the same
811
- * `ToolNode` instance and needs the sidecars `clearHeavyState`
812
- * would wipe (`toolCallStepIds` for completion-event step ids,
813
- * the `_toolOutputRegistry` for `{{tool<i>turn<n>}}`
814
- * substitutions, `sessions` for code-env continuity, plus the
815
- * `hookRegistry` and `humanInTheLoop` config the interrupt
816
- * branch itself relies on). Without preservation, the resumed
817
- * tool completion would dispatch `ON_RUN_STEP_COMPLETED` with
818
- * an empty step id and downstream stream consumers would drop
819
- * the result.
820
- *
821
- * The natural-completion / error / hook-driven-halt paths still
822
- * clean up — `_haltedReason != null` or `streamThrew` mean no
823
- * resume is expected. Cross-process resume (host rebuilds the
824
- * Run from scratch) is a separate concern; see
825
- * `HumanInTheLoopConfig` JSDoc.
826
- */
827
- const awaitingResume = this.isAwaitingResume(streamThrew);
828
- if (!this.skipCleanup && !awaitingResume) {
829
- this.Graph.clearHeavyState();
830
- }
831
- this._streamResult = result;
832
- }
833
- return this._streamResult;
834
- }
835
- /**
836
- * Returns the pending interrupt captured during the most recent
837
- * `processStream` (or `resume`) invocation. `undefined` when the run
838
- * either has not been streamed yet or completed without pausing.
839
- *
840
- * Hosts call this immediately after `processStream` returns to decide
841
- * whether the run is awaiting human input. Persist the returned
842
- * descriptor (alongside `thread_id` and the agent run config) so a
843
- * later `resume(decisions)` can rebuild the run.
844
- *
845
- * The default `TPayload` is the SDK's `HumanInterruptPayload` union
846
- * (`tool_approval` / `ask_user_question`), suitable for the common
847
- * case where interrupts come from the built-in ToolNode or
848
- * `askUserQuestion()` helper. Hosts that raise custom interrupts
849
- * from custom graph nodes pass their own type — the SDK does not
850
- * validate the runtime shape, it just transports whatever the
851
- * `interrupt()` call carried. When in doubt, narrow with the
852
- * `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt` type
853
- * guards (which accept `unknown`) before reading variant-specific
854
- * fields.
855
- */
856
- getInterrupt() {
857
- return this._interrupt;
858
- }
859
- /**
860
- * Returns the reason a hook halted the run via
861
- * `preventContinuation: true`, or `undefined` if no hook halted.
862
- *
863
- * Hosts inspect this after `processStream` returns to distinguish a
864
- * natural completion (`undefined`) from a hook-driven halt (a
865
- * truthy string). Independent from `getInterrupt()` — a halted run
866
- * has no interrupt; an interrupted run has no halt reason.
867
- */
868
- getHaltReason() {
869
- return this._haltedReason;
870
- }
871
- /**
872
- * Resume a paused HITL run with the value the user (or whatever
873
- * decided the interrupt) supplied. The default `TResume` covers the
874
- * `tool_approval` interrupt (the common case): an array of decisions
875
- * in `action_requests` order, or a record keyed by `tool_call_id`.
876
- *
877
- * For other interrupt types (e.g., `ask_user_question` →
878
- * `AskUserQuestionResolution`, or any custom interrupt a host raises
879
- * from a custom node), pass the type parameter and the SDK forwards
880
- * the value through unchanged. LangGraph delivers it as the return
881
- * value of the original `interrupt()` call inside the paused node.
882
- *
883
- * The host MUST construct this Run with the same `thread_id` and the
884
- * same checkpointer as the original paused run; LangGraph rebuilds
885
- * graph state from the checkpoint and re-enters the interrupted node
886
- * from the start.
887
- */
888
- /**
889
- * Returns the per-Run file checkpointer when
890
- * `toolExecution.local.fileCheckpointing === true` was set on the
891
- * RunConfig. Hosts can capture extra paths or call `rewind()`
892
- * directly. Returns undefined when checkpointing is disabled.
893
- *
894
- * Construction-time invariant: the checkpointer is shared across
895
- * every ToolNode the graph compiles (single-agent and multi-agent),
896
- * so a `rewind()` call here unwinds writes made by ANY agent in the
897
- * run.
898
- */
899
- getFileCheckpointer() {
900
- return this.Graph?.getOrCreateFileCheckpointer();
901
- }
902
- /**
903
- * Convenience wrapper that calls `rewind()` on the per-Run file
904
- * checkpointer. Restores every file the local engine snapshotted
905
- * during this Run to its pre-write content (and deletes any path
906
- * that didn't exist before being created). Returns the count of
907
- * paths processed; returns 0 when checkpointing is disabled.
908
- */
909
- async rewindFiles() {
910
- const cp = this.getFileCheckpointer();
911
- return cp == null ? 0 : cp.rewind();
912
- }
913
- async resume(resumeValue, callerConfig, streamOptions) {
914
- const interruptId = this._interrupt?.interruptId;
915
- const scopedResume = typeof interruptId === 'string' &&
916
- interruptId.length > 0 &&
917
- !isLangGraphResumeMapForInterrupt(resumeValue, interruptId)
918
- ? { [interruptId]: resumeValue }
919
- : resumeValue;
920
- const resumeConfig = await this.resolveInterruptResumeConfig(callerConfig);
921
- return this.processStream(new langgraph.Command({ resume: scopedResume }), resumeConfig, streamOptions);
922
- }
923
- async resolveInterruptResumeConfig(callerConfig) {
924
- const interrupt = this._interrupt;
925
- const interruptId = interrupt?.interruptId;
926
- const workflow = this.graphRunnable;
927
- const stateHistory = workflow?.getStateHistory;
928
- if (interrupt?.checkpointId != null && interrupt.checkpointId.length > 0) {
929
- return {
930
- ...callerConfig,
931
- configurable: {
932
- ...callerConfig.configurable,
933
- checkpoint_id: interrupt.checkpointId,
934
- ...(typeof interrupt.checkpointNs === 'string'
935
- ? { checkpoint_ns: interrupt.checkpointNs }
936
- : {}),
937
- },
938
- };
939
- }
940
- if (interrupt == null ||
941
- typeof interruptId !== 'string' ||
942
- interruptId.length === 0 ||
943
- typeof stateHistory !== 'function') {
944
- return callerConfig;
945
- }
946
- for await (const snapshot of stateHistory.call(this.graphRunnable, callerConfig)) {
947
- const hasMatchingInterrupt = snapshot.tasks?.some((task) => task.interrupts?.some((interrupt) => interrupt.id === interruptId) === true) === true;
948
- const checkpointConfigurable = snapshot.config?.configurable;
949
- if (!hasMatchingInterrupt || checkpointConfigurable == null) {
950
- continue;
951
- }
952
- const checkpointId = checkpointConfigurable.checkpoint_id;
953
- const checkpointNs = checkpointConfigurable.checkpoint_ns;
954
- if (typeof checkpointId === 'string' && checkpointId.length > 0) {
955
- this._interrupt = {
956
- ...interrupt,
957
- checkpointId,
958
- ...(typeof checkpointNs === 'string' ? { checkpointNs } : {}),
959
- };
960
- return {
961
- ...callerConfig,
962
- configurable: {
963
- ...callerConfig.configurable,
964
- checkpoint_id: checkpointId,
965
- ...(typeof checkpointNs === 'string'
966
- ? { checkpoint_ns: checkpointNs }
967
- : {}),
968
- },
969
- };
970
- }
971
- }
972
- return callerConfig;
973
- }
974
- createSystemCallback(clientCallbacks, key) {
975
- return ((...args) => {
976
- const clientCallback = clientCallbacks[key];
977
- if (clientCallback && this.Graph) {
978
- clientCallback(this.Graph, ...args);
979
- }
980
- });
981
- }
982
- getCallbacks(clientCallbacks) {
983
- return {
984
- [_enum.Callback.TOOL_ERROR]: this.createSystemCallback(clientCallbacks, _enum.Callback.TOOL_ERROR),
985
- [_enum.Callback.TOOL_START]: this.createSystemCallback(clientCallbacks, _enum.Callback.TOOL_START),
986
- [_enum.Callback.TOOL_END]: this.createSystemCallback(clientCallbacks, _enum.Callback.TOOL_END),
987
- };
988
- }
989
- async generateTitle({ provider, inputText, contentParts, titlePrompt, clientOptions, chainOptions, skipLanguage, titleMethod = _enum.TitleMethod.COMPLETION, titlePromptTemplate, }) {
990
- let titleLangfuseHandler;
991
- let titleLangfuseConfig;
992
- let titleUserId;
993
- let titleSessionId;
994
- const titleContext = this.Graph == null
995
- ? undefined
996
- : this.Graph.agentContexts.get(this.Graph.defaultAgentId);
997
- const traceMetadata = langfuse.createLangfuseTraceMetadata({
998
- messageId: 'title-' + this.id,
999
- agentName: titleContext?.name,
1000
- });
1001
- const titleRunName = langfuse.getLangfuseTraceName(traceMetadata, 'LibreChat Title');
1002
- if (chainOptions != null) {
1003
- titleUserId =
1004
- typeof chainOptions.configurable?.user_id === 'string'
1005
- ? chainOptions.configurable.user_id
1006
- : undefined;
1007
- titleSessionId =
1008
- typeof chainOptions.configurable?.thread_id === 'string'
1009
- ? chainOptions.configurable.thread_id
1010
- : undefined;
1011
- titleLangfuseConfig = langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, titleContext?.langfuse);
1012
- instrumentation.initializeLangfuseTracing(titleLangfuseConfig);
1013
- titleLangfuseHandler = langfuse.createLangfuseHandler({
1014
- langfuse: titleLangfuseConfig,
1015
- userId: titleUserId,
1016
- sessionId: titleSessionId,
1017
- traceMetadata,
1018
- tags: ['librechat', 'title'],
1019
- });
1020
- if (titleLangfuseHandler != null) {
1021
- chainOptions.callbacks = callbacks.appendCallbacks(chainOptions.callbacks, [
1022
- titleLangfuseHandler,
1023
- ]);
1024
- }
1025
- }
1026
- const convoTemplate = prompts.PromptTemplate.fromTemplate(titlePromptTemplate ?? 'User: {input}\nAI: {output}');
1027
- const response = contentParts
1028
- .map((part) => {
1029
- if (part?.type === 'text')
1030
- return part.text;
1031
- return '';
1032
- })
1033
- .join('\n');
1034
- const model = init.initializeModel({
1035
- provider,
1036
- clientOptions,
1037
- });
1038
- if (llm.isOpenAILike(provider) &&
1039
- (model instanceof openai.ChatOpenAI || model instanceof openai.AzureChatOpenAI)) {
1040
- model.temperature = clientOptions
1041
- ?.temperature;
1042
- model.topP = clientOptions
1043
- ?.topP;
1044
- model.frequencyPenalty = clientOptions?.frequencyPenalty;
1045
- model.presencePenalty = clientOptions?.presencePenalty;
1046
- model.n = clientOptions
1047
- ?.n;
1048
- }
1049
- const convoToTitleInput = new runnables.RunnableLambda({
1050
- func: (promptValue) => ({
1051
- convo: promptValue.value,
1052
- inputText,
1053
- skipLanguage,
1054
- }),
1055
- }).withConfig({ runName: 'ConvoTransform' });
1056
- const titleChain = titleMethod === _enum.TitleMethod.COMPLETION
1057
- ? await title.createCompletionTitleRunnable(model, titlePrompt)
1058
- : await title.createTitleRunnable(model, titlePrompt);
1059
- /** Pipes `convoTemplate` -> `transformer` -> `titleChain` */
1060
- const fullChain = convoTemplate
1061
- .withConfig({ runName: 'ConvoTemplate' })
1062
- .pipe(convoToTitleInput)
1063
- .pipe(titleChain)
1064
- .withConfig({ runName: 'TitleChain' });
1065
- const invokeConfig = Object.assign({}, chainOptions, {
1066
- run_id: this.id,
1067
- runId: this.id,
1068
- runName: chainOptions?.runName ?? titleRunName,
1069
- });
1070
- const invokeTitleChain = (runtimeConfig) => langfuse.withLangfuseAttributes({
1071
- langfuse: titleLangfuseConfig,
1072
- userId: titleUserId,
1073
- sessionId: titleSessionId,
1074
- traceName: runtimeConfig.runName ?? titleRunName,
1075
- traceMetadata,
1076
- tags: ['librechat', 'title'],
1077
- }, () => fullChain.invoke({ input: inputText, output: response }, runtimeConfig));
1078
- try {
1079
- try {
1080
- return await langfuseToolOutputTracing.withLangfuseToolOutputTracingConfig(this.langfuse, () => invokeTitleChain(invokeConfig), titleContext?.langfuse);
1081
- }
1082
- catch (_e) {
1083
- // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments
1084
- // but preserve Langfuse tracing if it exists.
1085
- const langfuseHandler = callbacks.findCallback(invokeConfig.callbacks, langfuse.isLangfuseCallbackHandler);
1086
- const { callbacks: _cb, ...rest } = invokeConfig;
1087
- const safeConfig = Object.assign({}, rest, {
1088
- callbacks: langfuseHandler ? [langfuseHandler] : [],
1089
- });
1090
- return await langfuseToolOutputTracing.withLangfuseToolOutputTracingConfig(this.langfuse, () => invokeTitleChain(safeConfig), titleContext?.langfuse);
1091
- }
1092
- }
1093
- finally {
1094
- await langfuse.disposeLangfuseHandler(titleLangfuseHandler);
1095
- }
1096
- }
62
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
63
+ return Object.prototype.hasOwnProperty.call(value, interruptId);
1097
64
  }
65
+ var Run = class Run {
66
+ id;
67
+ tokenCounter;
68
+ handlerRegistry;
69
+ hookRegistry;
70
+ humanInTheLoop;
71
+ langfuse;
72
+ toolOutputReferences;
73
+ eagerEventToolExecution;
74
+ toolExecution;
75
+ indexTokenCountMap;
76
+ calibrationRatio = 1;
77
+ graphRunnable;
78
+ Graph;
79
+ returnContent = false;
80
+ skipCleanup = false;
81
+ _streamResult;
82
+ /**
83
+ * Captured interrupt payload typed as `unknown` because the SDK
84
+ * does not validate the runtime shape — custom graph nodes can
85
+ * raise interrupts with arbitrary payloads (not just the SDK's
86
+ * `HumanInterruptPayload` union). The public `getInterrupt<T>()`
87
+ * lets callers assert the type they expect.
88
+ */
89
+ _interrupt;
90
+ _haltedReason;
91
+ constructor(config) {
92
+ const runId = config.runId ?? "";
93
+ if (!runId) throw new Error("Run ID not provided");
94
+ this.id = runId;
95
+ this.tokenCounter = config.tokenCounter;
96
+ this.indexTokenCountMap = config.indexTokenCountMap;
97
+ if (config.calibrationRatio != null && config.calibrationRatio > 0) this.calibrationRatio = config.calibrationRatio;
98
+ const handlerRegistry = new require_events.HandlerRegistry();
99
+ if (config.customHandlers) for (const [eventType, handler] of Object.entries(config.customHandlers)) handlerRegistry.register(eventType, handler);
100
+ this.handlerRegistry = handlerRegistry;
101
+ this.hookRegistry = config.hooks;
102
+ this.humanInTheLoop = config.humanInTheLoop;
103
+ this.langfuse = config.langfuse;
104
+ this.toolOutputReferences = config.toolOutputReferences;
105
+ this.eagerEventToolExecution = config.eagerEventToolExecution;
106
+ this.toolExecution = config.toolExecution;
107
+ if (!config.graphConfig) throw new Error("Graph config not provided");
108
+ /** Handle different graph types */
109
+ if (config.graphConfig.type === "multi-agent") {
110
+ this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);
111
+ if (this.Graph) this.Graph.handlerRegistry = handlerRegistry;
112
+ } else {
113
+ /** Default to legacy graph for 'standard' or undefined type */
114
+ this.graphRunnable = this.createLegacyGraph(config.graphConfig);
115
+ if (this.Graph) {
116
+ this.Graph.compileOptions = config.graphConfig.compileOptions ?? this.Graph.compileOptions;
117
+ this.Graph.handlerRegistry = handlerRegistry;
118
+ }
119
+ }
120
+ if (config.initialSessions && this.Graph) for (const [key, value] of config.initialSessions) this.Graph.sessions.set(key, value);
121
+ this.returnContent = config.returnContent ?? false;
122
+ this.skipCleanup = config.skipCleanup ?? false;
123
+ }
124
+ createLegacyGraph(config) {
125
+ let agentConfig;
126
+ let signal;
127
+ /** Check if this is a multi-agent style config (has agents array) */
128
+ if ("agents" in config && Array.isArray(config.agents)) {
129
+ if (config.agents.length === 0) throw new Error("At least one agent must be provided");
130
+ agentConfig = config.agents[0];
131
+ signal = config.signal;
132
+ } else {
133
+ /** Legacy path: build agent config from llmConfig */
134
+ const { type: _type, llmConfig, signal: legacySignal, tools = [], ...agentInputs } = config;
135
+ const { provider, ...clientOptions } = llmConfig;
136
+ agentConfig = {
137
+ ...agentInputs,
138
+ tools,
139
+ provider,
140
+ clientOptions,
141
+ agentId: "default"
142
+ };
143
+ signal = legacySignal;
144
+ }
145
+ const standardGraph = new require_Graph.StandardGraph({
146
+ signal,
147
+ runId: this.id,
148
+ agents: [agentConfig],
149
+ langfuse: this.langfuse,
150
+ tokenCounter: this.tokenCounter,
151
+ indexTokenCountMap: this.indexTokenCountMap,
152
+ calibrationRatio: this.calibrationRatio
153
+ });
154
+ /** Propagate compile options from graph config */
155
+ standardGraph.compileOptions = this.applyHITLCheckpointerFallback(config.compileOptions);
156
+ standardGraph.hookRegistry = this.hookRegistry;
157
+ standardGraph.humanInTheLoop = this.humanInTheLoop;
158
+ standardGraph.toolOutputReferences = this.toolOutputReferences;
159
+ standardGraph.eagerEventToolExecution = this.eagerEventToolExecution;
160
+ standardGraph.toolExecution = this.toolExecution;
161
+ this.Graph = standardGraph;
162
+ return standardGraph.createWorkflow();
163
+ }
164
+ createMultiAgentGraph(config) {
165
+ const { agents, edges, compileOptions } = config;
166
+ const multiAgentGraph = new require_MultiAgentGraph.MultiAgentGraph({
167
+ runId: this.id,
168
+ agents,
169
+ edges,
170
+ langfuse: this.langfuse,
171
+ tokenCounter: this.tokenCounter,
172
+ indexTokenCountMap: this.indexTokenCountMap,
173
+ calibrationRatio: this.calibrationRatio
174
+ });
175
+ multiAgentGraph.compileOptions = this.applyHITLCheckpointerFallback(compileOptions);
176
+ multiAgentGraph.hookRegistry = this.hookRegistry;
177
+ multiAgentGraph.humanInTheLoop = this.humanInTheLoop;
178
+ multiAgentGraph.toolOutputReferences = this.toolOutputReferences;
179
+ multiAgentGraph.eagerEventToolExecution = this.eagerEventToolExecution;
180
+ multiAgentGraph.toolExecution = this.toolExecution;
181
+ this.Graph = multiAgentGraph;
182
+ return multiAgentGraph.createWorkflow();
183
+ }
184
+ /**
185
+ * When the host opted into HITL via `humanInTheLoop: { enabled: true }`
186
+ * and did not supply a checkpointer, install an in-memory `MemorySaver`
187
+ * so `interrupt()` can persist checkpoints and `Command({ resume })`
188
+ * can rebuild state. The fallback is intentionally process-local:
189
+ * production hosts that need durable resumption across processes /
190
+ * restarts must provide their own checkpointer (Redis, Postgres, etc.)
191
+ * on `compileOptions.checkpointer`.
192
+ *
193
+ * No-op when HITL is off (the default — omitted, or
194
+ * `{ enabled: false }`) or the host already supplied a checkpointer
195
+ * of their own. See `HumanInTheLoopConfig` JSDoc for the rationale
196
+ * behind the default-off stance.
197
+ */
198
+ applyHITLCheckpointerFallback(compileOptions) {
199
+ if (this.humanInTheLoop?.enabled !== true) return compileOptions;
200
+ if (compileOptions?.checkpointer != null) return compileOptions;
201
+ return {
202
+ ...compileOptions ?? {},
203
+ checkpointer: new _langchain_langgraph.MemorySaver()
204
+ };
205
+ }
206
+ /**
207
+ * Run RunStart + UserPromptSubmit hooks before the graph stream
208
+ * begins, accumulate any `additionalContext` strings into the input
209
+ * messages, and short-circuit when a hook signals the run should not
210
+ * proceed (deny / ask decision on the prompt, or `preventContinuation`
211
+ * on either hook).
212
+ *
213
+ * Returns `true` when the caller should bail with `undefined` (run
214
+ * was halted before any model call); returns `false` to proceed
215
+ * into the stream loop.
216
+ *
217
+ * ## Side effects
218
+ *
219
+ * On the success path:
220
+ * - Mutates `stateInputs.messages` in place to append a
221
+ * consolidated `HumanMessage` carrying any hook
222
+ * `additionalContext` strings. Safe because the host owns the
223
+ * array and `processStream` is the only consumer until LangGraph
224
+ * reads it.
225
+ *
226
+ * On the halt path (returning `true`):
227
+ * - Sets `this._haltedReason` so callers (and the eventual host)
228
+ * can distinguish a hook-driven halt from a natural completion.
229
+ * - Calls `registry.clearSession(this.id)` and
230
+ * `registry.clearHaltSignal(this.id)` because no resume is
231
+ * expected from a pre-stream halt — the run never entered the
232
+ * graph, so the session/halt state for this run would otherwise
233
+ * leak to the next `processStream` invocation on the same
234
+ * registry. Other concurrent runs on the same registry are
235
+ * untouched (halt signals are scoped per session id).
236
+ * - Sets `config.callbacks = undefined` to drop the callback
237
+ * references the caller built (langfuse handler, custom event
238
+ * handler, etc.) since they won't be exercised. Mirrors the
239
+ * equivalent cleanup the `processStream` `finally` block does
240
+ * on the natural-completion path.
241
+ */
242
+ async runPreStreamHooks(stateInputs, threadId, config) {
243
+ const registry = this.hookRegistry;
244
+ /**
245
+ * Defensive guard: `processStream` already validated `this.Graph`
246
+ * before calling this helper, but TypeScript can't propagate that
247
+ * narrowing across method boundaries. The check keeps the body
248
+ * free of `this.Graph!` non-null assertions.
249
+ */
250
+ if (registry == null || this.Graph == null) return false;
251
+ const preStreamContexts = [];
252
+ const runStartResult = await require_executeHooks.executeHooks({
253
+ registry,
254
+ input: {
255
+ hook_event_name: "RunStart",
256
+ runId: this.id,
257
+ threadId,
258
+ agentId: this.Graph.defaultAgentId,
259
+ messages: stateInputs.messages
260
+ },
261
+ sessionId: this.id
262
+ });
263
+ for (const ctx of runStartResult.additionalContexts) preStreamContexts.push(ctx);
264
+ /**
265
+ * Honor `preventContinuation` from RunStart before the stream
266
+ * starts. Mid-flight halts (from tool/compact/subagent hooks)
267
+ * route through `HookRegistry.haltRun` and are polled by the
268
+ * stream loop in `processStream` — different mechanism, same
269
+ * intent.
270
+ */
271
+ if (runStartResult.preventContinuation === true) {
272
+ this._haltedReason = runStartResult.stopReason ?? "preventContinuation";
273
+ registry.clearSession(this.id);
274
+ registry.clearHaltSignal(this.id);
275
+ config.callbacks = void 0;
276
+ return true;
277
+ }
278
+ const lastHuman = findLastMessageOfType(stateInputs.messages, "human");
279
+ if (lastHuman != null) {
280
+ const promptResult = await require_executeHooks.executeHooks({
281
+ registry,
282
+ input: {
283
+ hook_event_name: "UserPromptSubmit",
284
+ runId: this.id,
285
+ threadId,
286
+ agentId: this.Graph.defaultAgentId,
287
+ prompt: extractPromptText(lastHuman)
288
+ },
289
+ sessionId: this.id
290
+ });
291
+ if (promptResult.decision === "deny" || promptResult.decision === "ask" || promptResult.preventContinuation === true) {
292
+ /**
293
+ * Always set `_haltedReason` so the host can call
294
+ * `getHaltReason()` and distinguish a hook-blocked prompt
295
+ * from a natural empty-output completion. Three signals can
296
+ * land here, each with its own canonical reason string when
297
+ * the hook didn't supply one.
298
+ */
299
+ if (promptResult.preventContinuation === true) this._haltedReason = promptResult.stopReason ?? "preventContinuation";
300
+ else if (promptResult.decision === "deny") this._haltedReason = promptResult.reason ?? "prompt_denied";
301
+ else this._haltedReason = promptResult.reason ?? "prompt_requires_approval";
302
+ registry.clearSession(this.id);
303
+ registry.clearHaltSignal(this.id);
304
+ config.callbacks = void 0;
305
+ return true;
306
+ }
307
+ for (const ctx of promptResult.additionalContexts) preStreamContexts.push(ctx);
308
+ }
309
+ if (preStreamContexts.length > 0)
310
+ /**
311
+ * Wraps the joined hook contexts as a `HumanMessage` even though
312
+ * the intent is system-level guidance. Using a `SystemMessage`
313
+ * mid-conversation is rejected by Anthropic and Google providers
314
+ * (system messages must be the leading entry), so the LangChain
315
+ * convention — also used by `ToolNode.convertInjectedMessages`
316
+ * — is `HumanMessage` carrying `additional_kwargs.role` as a
317
+ * marker for hosts inspecting state. The model still sees a
318
+ * user-role message; the `role: 'system'` field is metadata
319
+ * only. Hosts that want a true system message should compose
320
+ * it into the agent's `instructions` config instead.
321
+ */
322
+ stateInputs.messages.push(new _langchain_core_messages.HumanMessage({
323
+ content: preStreamContexts.join("\n\n"),
324
+ additional_kwargs: {
325
+ role: "system",
326
+ source: "hook"
327
+ }
328
+ }));
329
+ return false;
330
+ }
331
+ static async create(config) {
332
+ /** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */
333
+ if (config.indexTokenCountMap && !config.tokenCounter) {
334
+ const gc = config.graphConfig;
335
+ config.tokenCounter = await require_tokens.createTokenCounter(require_tokens.encodingForModel(("agents" in gc ? gc.agents[0]?.clientOptions : gc.clientOptions)?.model ?? ""));
336
+ }
337
+ return new Run(config);
338
+ }
339
+ getRunMessages() {
340
+ if (!this.Graph) throw new Error("Graph not initialized. Make sure to use Run.create() to instantiate the Run.");
341
+ return this.Graph.getRunMessages();
342
+ }
343
+ /**
344
+ * Returns the current calibration ratio (EMA of provider-vs-estimate token ratios).
345
+ * Hosts should persist this value and pass it back as `RunConfig.calibrationRatio`
346
+ * on the next run for the same conversation so the pruner starts with an accurate
347
+ * scaling factor instead of the default (1).
348
+ */
349
+ getCalibrationRatio() {
350
+ return this.calibrationRatio;
351
+ }
352
+ getResolvedInstructionOverhead() {
353
+ return this.Graph?.getResolvedInstructionOverhead();
354
+ }
355
+ getToolCount() {
356
+ return this.Graph?.getToolCount() ?? 0;
357
+ }
358
+ /**
359
+ * Creates a custom event callback handler that intercepts custom events
360
+ * and processes them through our handler registry instead of EventStreamCallbackHandler
361
+ */
362
+ createCustomEventCallback() {
363
+ return async (eventName, data, runId, tags, metadata) => {
364
+ const stepScopedEventId = getStepScopedEventId(data);
365
+ if (DIRECT_DISPATCHED_STEP_EVENTS.has(eventName) && this.Graph != null && stepScopedEventId != null && this.Graph.hasHandlerDispatchedEvent(eventName, stepScopedEventId)) return;
366
+ const handler = this.handlerRegistry?.getHandler(eventName);
367
+ if (handler && this.Graph) return await handler.handle(eventName, data, metadata, this.Graph);
368
+ };
369
+ }
370
+ shouldClearHookSession(streamThrew) {
371
+ return this._interrupt == null || this._haltedReason != null || streamThrew;
372
+ }
373
+ isAwaitingResume(streamThrew) {
374
+ return this._interrupt != null && this._haltedReason == null && !streamThrew;
375
+ }
376
+ getStreamLangfuseConfig(graph) {
377
+ const primaryContext = graph.agentContexts.get(graph.defaultAgentId);
378
+ if (primaryContext != null) return require_langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, primaryContext.langfuse);
379
+ for (const context of graph.agentContexts.values()) {
380
+ const langfuse = require_langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, context.langfuse);
381
+ if (langfuse != null) return langfuse;
382
+ }
383
+ return this.langfuse;
384
+ }
385
+ getStreamToolOutputTracingLangfuseConfig(graph) {
386
+ const toolOutputTracingConfigs = Array.from(graph.agentContexts.values()).map((context) => {
387
+ return require_langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, context.langfuse)?.toolOutputTracing;
388
+ }).filter((config) => {
389
+ return config != null;
390
+ });
391
+ if (toolOutputTracingConfigs.length === 0) return this.langfuse?.toolOutputTracing != null ? { toolOutputTracing: this.langfuse.toolOutputTracing } : void 0;
392
+ if (toolOutputTracingConfigs.length === 1) return { toolOutputTracing: toolOutputTracingConfigs[0] };
393
+ let enabled;
394
+ let redactionText;
395
+ let redactedToolNameMatchMode;
396
+ const redactedToolNames = /* @__PURE__ */ new Set();
397
+ for (const config of toolOutputTracingConfigs) {
398
+ if (config.enabled === false) enabled = false;
399
+ else if (enabled !== false && config.enabled != null) enabled = config.enabled;
400
+ redactionText ??= config.redactionText;
401
+ if (config.redactedToolNameMatchMode === "partial") redactedToolNameMatchMode = "partial";
402
+ else redactedToolNameMatchMode ??= config.redactedToolNameMatchMode;
403
+ for (const toolName of config.redactedToolNames ?? []) redactedToolNames.add(toolName);
404
+ }
405
+ return { toolOutputTracing: {
406
+ ...enabled != null ? { enabled } : {},
407
+ ...redactedToolNames.size > 0 ? { redactedToolNames: Array.from(redactedToolNames) } : {},
408
+ ...redactedToolNameMatchMode != null ? { redactedToolNameMatchMode } : {},
409
+ ...redactionText != null ? { redactionText } : {}
410
+ } };
411
+ }
412
+ async processStream(inputs, callerConfig, streamOptions) {
413
+ if (this.graphRunnable == null) throw new Error("Run not initialized. Make sure to use Run.create() to instantiate the Run.");
414
+ if (!this.Graph) throw new Error("Graph not initialized. Make sure to use Run.create() to instantiate the Run.");
415
+ const graphRunnable = this.graphRunnable;
416
+ const graph = this.Graph;
417
+ /**
418
+ * `Command` inputs (currently only `Command({ resume })`) are
419
+ * resume-mode invocations: LangGraph rebuilds graph state from the
420
+ * checkpointer, so we skip RunStart / UserPromptSubmit hooks (no
421
+ * new prompt to evaluate) and read run-state from the Graph wrapper
422
+ * instead of `inputs.messages`.
423
+ */
424
+ const isResume = inputs instanceof _langchain_langgraph.Command;
425
+ const stateInputs = isResume ? void 0 : inputs;
426
+ const config = {
427
+ recursionLimit: 50,
428
+ ...callerConfig,
429
+ configurable: { ...callerConfig.configurable }
430
+ };
431
+ /**
432
+ * Skip `resetValues` on resume — we're continuing an in-flight
433
+ * run, not starting a fresh one. Resetting would wipe the
434
+ * sidecars (`toolCallStepIds`, `stepKeyIds`, accumulated
435
+ * `messages`, etc.) the resumed `ToolNode` needs to dispatch
436
+ * tool completions with the correct step ids and re-resolve
437
+ * `{{tool<i>turn<n>}}` references. Pairs with the
438
+ * `awaitingResume` gate on `clearHeavyState` in the `finally`
439
+ * block so the sidecars survive both ends of the interrupt
440
+ * boundary.
441
+ */
442
+ if (!isResume) graph.resetValues(streamOptions?.keepContent);
443
+ this._interrupt = void 0;
444
+ this._haltedReason = void 0;
445
+ this.hookRegistry?.clearHaltSignal(this.id);
446
+ /** Custom event callback to intercept and handle custom events */
447
+ const customEventCallback = this.createCustomEventCallback();
448
+ const streamCallbacks = streamOptions?.callbacks ? this.getCallbacks(streamOptions.callbacks) : void 0;
449
+ const customHandler = _langchain_core_callbacks_base.BaseCallbackHandler.fromMethods({ ["handleCustomEvent"]: customEventCallback });
450
+ customHandler.awaitHandlers = true;
451
+ config.callbacks = require_callbacks.appendCallbacks(config.callbacks, streamCallbacks ? [streamCallbacks, customHandler] : [customHandler]);
452
+ const primaryContext = graph.agentContexts.get(graph.defaultAgentId);
453
+ const userId = typeof config.configurable?.user_id === "string" ? config.configurable.user_id : void 0;
454
+ const sessionId = typeof config.configurable?.thread_id === "string" ? config.configurable.thread_id : void 0;
455
+ const traceMetadata = require_langfuse.createLangfuseTraceMetadata({
456
+ messageId: this.id,
457
+ parentMessageId: config.configurable?.requestBody?.parentMessageId,
458
+ agentId: graph.defaultAgentId,
459
+ agentName: primaryContext?.name
460
+ });
461
+ const traceName = config.runName ?? require_langfuse.getLangfuseTraceName(traceMetadata);
462
+ const streamLangfuseConfig = this.getStreamLangfuseConfig(graph);
463
+ require_instrumentation.initializeLangfuseTracing(streamLangfuseConfig);
464
+ const langfuseHandler = require_langfuse.createLangfuseHandler({
465
+ langfuse: streamLangfuseConfig,
466
+ userId,
467
+ sessionId,
468
+ traceMetadata,
469
+ tags: ["librechat", "agent"]
470
+ });
471
+ if (langfuseHandler != null) {
472
+ config.runName = traceName;
473
+ config.callbacks = require_callbacks.appendCallbacks(config.callbacks, [langfuseHandler]);
474
+ }
475
+ if (!this.id) throw new Error("Run ID not provided");
476
+ config.run_id = this.id;
477
+ config.configurable = Object.assign(config.configurable ?? {}, { run_id: this.id });
478
+ const threadId = config.configurable.thread_id;
479
+ if (this.hookRegistry != null && stateInputs != null) {
480
+ if (await this.runPreStreamHooks(stateInputs, threadId, config)) return;
481
+ }
482
+ /**
483
+ * Tracks whether the stream loop threw. Used by the `finally`
484
+ * block to decide whether to honor the interrupt-preservation
485
+ * guard for session hooks: a captured `_interrupt` is only
486
+ * meaningful if the stream completed cleanly. If the loop errored
487
+ * after stashing an interrupt (e.g. a downstream handler throws
488
+ * after the interrupt event landed), the interrupt is stale —
489
+ * preserving session hooks would leak them into the next run.
490
+ */
491
+ let streamThrew = false;
492
+ const consumeStream = async () => {
493
+ /**
494
+ * `streamEvents` accepts both state inputs and `Command` (resume) at
495
+ * runtime, but our `CompiledStateWorkflow` type narrows the first
496
+ * arg to `BaseGraphState`. Cast on the call so the resume path
497
+ * type-checks without widening the wrapper for every caller.
498
+ */
499
+ const stream = graphRunnable.streamEvents(inputs, config, {
500
+ raiseError: true,
501
+ /**
502
+ * Prevent EventStreamCallbackHandler from processing custom events.
503
+ * Custom events are already handled via our createCustomEventCallback()
504
+ * which routes them through the handlerRegistry.
505
+ * Without this flag, EventStreamCallbackHandler throws errors when
506
+ * custom events are dispatched for run IDs not in its internal map
507
+ * (due to timing issues in parallel execution or after run cleanup).
508
+ */
509
+ ignoreCustomEvent: true
510
+ });
511
+ for await (const event of stream) {
512
+ const { data, metadata, ...info } = event;
513
+ const eventName = info.event;
514
+ /** Skip custom events as they're handled by our callback */
515
+ if (CUSTOM_GRAPH_EVENTS.has(eventName)) continue;
516
+ /**
517
+ * Detect interrupts surfaced by LangGraph as a synthetic
518
+ * `__interrupt__` field on the streamed chunk and stash the
519
+ * first one for the host to read via `run.getInterrupt()`
520
+ * once the stream drains. Captured as `unknown` because the
521
+ * SDK does not validate the runtime payload shape — the
522
+ * built-in ToolNode raises a `HumanInterruptPayload`
523
+ * (`tool_approval` / `ask_user_question`), but custom nodes
524
+ * can pass any payload to `interrupt()`. Callers narrow with
525
+ * the `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt`
526
+ * guards or assert via `getInterrupt<T>()`.
527
+ */
528
+ if (this._interrupt == null && data.chunk != null && (0, _langchain_langgraph.isInterrupted)(data.chunk)) {
529
+ const interrupts = data.chunk[_langchain_langgraph.INTERRUPT];
530
+ if (interrupts.length > 0) {
531
+ const first = interrupts[0];
532
+ /**
533
+ * Capture the interrupt unconditionally — `interrupt(null)`
534
+ * and `interrupt(undefined)` are valid pauses (a custom
535
+ * node may want to pause without metadata) and the host
536
+ * still needs to know the run is awaiting resume. Gating
537
+ * on `payload != null` would silently downgrade a paused
538
+ * run to "completed" and let the `Stop` hook fire,
539
+ * breaking host resume handling.
540
+ */
541
+ this._interrupt = {
542
+ interruptId: first.id ?? "",
543
+ threadId,
544
+ payload: first.value
545
+ };
546
+ }
547
+ }
548
+ const handler = this.handlerRegistry?.getHandler(eventName);
549
+ if (handler) await handler.handle(eventName, data, metadata, this.Graph);
550
+ /**
551
+ * Mid-flight halt: any hook (PreToolUse, PostToolUse,
552
+ * PostToolBatch, SubagentStart/Stop, PreCompact, PostCompact)
553
+ * that returned `preventContinuation: true` raises a halt
554
+ * signal on the registry via `executeHooks`. We poll between
555
+ * stream events and break out as soon as one is set so the
556
+ * graph doesn't take another model turn after the halting
557
+ * operation completes.
558
+ *
559
+ * Limitation: the current step (in-flight model call, ongoing
560
+ * tool batch) is not aborted — only the next step is skipped.
561
+ * This matches Claude Code's `continue: false` semantic where
562
+ * the active operation finishes before halting takes effect.
563
+ */
564
+ const haltSignal = this.hookRegistry?.getHaltSignal(this.id);
565
+ if (haltSignal != null) {
566
+ this._haltedReason = haltSignal.reason;
567
+ break;
568
+ }
569
+ }
570
+ if (this._interrupt != null) await this.resolveInterruptResumeConfig(config);
571
+ /**
572
+ * Skip the Stop hook when the run paused on a HITL interrupt
573
+ * (still pending human input) or was halted by a hook (the host
574
+ * already chose to stop, so a Stop hook firing now would be
575
+ * misleading). The host fires Stop on the resumed-and-completed
576
+ * run instead.
577
+ */
578
+ if (this._interrupt == null && this._haltedReason == null && this.hookRegistry?.hasHookFor("Stop", this.id) === true) await require_executeHooks.executeHooks({
579
+ registry: this.hookRegistry,
580
+ input: {
581
+ hook_event_name: "Stop",
582
+ runId: this.id,
583
+ threadId,
584
+ agentId: graph.defaultAgentId,
585
+ messages: graph.getRunMessages() ?? stateInputs?.messages ?? [],
586
+ stopHookActive: false
587
+ },
588
+ sessionId: this.id
589
+ }).catch(() => {});
590
+ };
591
+ try {
592
+ await require_instrumentation.runWithTraceIdSeed(streamLangfuseConfig?.deterministicTraceId === true ? this.id : void 0, () => require_langfuseToolOutputTracing.withLangfuseToolOutputTracingConfig(streamLangfuseConfig, () => require_langfuse.withLangfuseAttributes({
593
+ langfuse: streamLangfuseConfig,
594
+ userId,
595
+ sessionId,
596
+ traceName,
597
+ traceMetadata,
598
+ tags: ["librechat", "agent"]
599
+ }, consumeStream), this.getStreamToolOutputTracingLangfuseConfig(graph)));
600
+ } catch (err) {
601
+ streamThrew = true;
602
+ if (this.hookRegistry?.hasHookFor("StopFailure", this.id) === true) {
603
+ const runMessages = this.Graph.getRunMessages() ?? [];
604
+ await require_executeHooks.executeHooks({
605
+ registry: this.hookRegistry,
606
+ input: {
607
+ hook_event_name: "StopFailure",
608
+ runId: this.id,
609
+ threadId,
610
+ agentId: this.Graph.defaultAgentId,
611
+ error: err instanceof Error ? err.message : String(err),
612
+ lastAssistantMessage: findLastMessageOfType(runMessages, "ai")
613
+ },
614
+ sessionId: this.id
615
+ }).catch(() => {});
616
+ }
617
+ throw err;
618
+ } finally {
619
+ /**
620
+ * Preserve session-scoped hooks when the run paused on a HITL
621
+ * interrupt — the very next call will be `Run.resume()`, which
622
+ * needs the same policy hooks (e.g., the `PreToolUse` matcher
623
+ * that triggered the interrupt) to fire on the re-executed node
624
+ * and uphold the approval flow. Clearing here would leak the
625
+ * approval gate on resume. The session is cleared instead at
626
+ * natural completion, error (including errors that happen AFTER
627
+ * an interrupt was captured — those interrupts are stale), or
628
+ * hook-driven halt (including hooks that returned BOTH `ask`
629
+ * and `preventContinuation` — the halt wins, no resume is
630
+ * expected, sessions must drop). Every state where no resume
631
+ * is expected clears.
632
+ */
633
+ if (this.shouldClearHookSession(streamThrew)) this.hookRegistry?.clearSession(this.id);
634
+ /**
635
+ * Drop any halt signal raised mid-stream for this run so a
636
+ * subsequent `processStream` / `resume` starts with clean state.
637
+ * The Run captured `_haltedReason` already; the registry entry
638
+ * for this `sessionId` would otherwise spuriously trip the next
639
+ * loop. Other concurrent runs sharing this registry are
640
+ * unaffected — their entries live under their own session ids.
641
+ */
642
+ this.hookRegistry?.clearHaltSignal(this.id);
643
+ await require_langfuse.disposeLangfuseHandler(langfuseHandler);
644
+ /**
645
+ * Break the reference chain that keeps heavy data alive via
646
+ * LangGraph's internal `__pregel_scratchpad.currentTaskInput` →
647
+ * `@langchain/core` `RunTree.extra[lc:child_config]` →
648
+ * Node.js `AsyncLocalStorage` context captured by timers/promises.
649
+ *
650
+ * Without this, base64-encoded images/PDFs in message content remain
651
+ * reachable from lingering `Timeout` handles until GC runs.
652
+ */
653
+ if (!this.skipCleanup) {
654
+ if (config.configurable != null) {
655
+ for (const key of Object.getOwnPropertySymbols(config.configurable)) {
656
+ const val = config.configurable[key];
657
+ if (val != null && typeof val === "object" && "currentTaskInput" in val) val.currentTaskInput = void 0;
658
+ delete config.configurable[key];
659
+ }
660
+ config.configurable = void 0;
661
+ }
662
+ config.callbacks = void 0;
663
+ }
664
+ const result = this.returnContent ? this.Graph.getContentParts() : void 0;
665
+ this.calibrationRatio = this.Graph.getCalibrationRatio();
666
+ /**
667
+ * Skip `clearHeavyState()` when the run paused on a clean HITL
668
+ * interrupt awaiting resume — `Run.resume()` re-enters the same
669
+ * `ToolNode` instance and needs the sidecars `clearHeavyState`
670
+ * would wipe (`toolCallStepIds` for completion-event step ids,
671
+ * the `_toolOutputRegistry` for `{{tool<i>turn<n>}}`
672
+ * substitutions, `sessions` for code-env continuity, plus the
673
+ * `hookRegistry` and `humanInTheLoop` config the interrupt
674
+ * branch itself relies on). Without preservation, the resumed
675
+ * tool completion would dispatch `ON_RUN_STEP_COMPLETED` with
676
+ * an empty step id and downstream stream consumers would drop
677
+ * the result.
678
+ *
679
+ * The natural-completion / error / hook-driven-halt paths still
680
+ * clean up — `_haltedReason != null` or `streamThrew` mean no
681
+ * resume is expected. Cross-process resume (host rebuilds the
682
+ * Run from scratch) is a separate concern; see
683
+ * `HumanInTheLoopConfig` JSDoc.
684
+ */
685
+ const awaitingResume = this.isAwaitingResume(streamThrew);
686
+ if (!this.skipCleanup && !awaitingResume) this.Graph.clearHeavyState();
687
+ this._streamResult = result;
688
+ }
689
+ return this._streamResult;
690
+ }
691
+ /**
692
+ * Returns the pending interrupt captured during the most recent
693
+ * `processStream` (or `resume`) invocation. `undefined` when the run
694
+ * either has not been streamed yet or completed without pausing.
695
+ *
696
+ * Hosts call this immediately after `processStream` returns to decide
697
+ * whether the run is awaiting human input. Persist the returned
698
+ * descriptor (alongside `thread_id` and the agent run config) so a
699
+ * later `resume(decisions)` can rebuild the run.
700
+ *
701
+ * The default `TPayload` is the SDK's `HumanInterruptPayload` union
702
+ * (`tool_approval` / `ask_user_question`), suitable for the common
703
+ * case where interrupts come from the built-in ToolNode or
704
+ * `askUserQuestion()` helper. Hosts that raise custom interrupts
705
+ * from custom graph nodes pass their own type — the SDK does not
706
+ * validate the runtime shape, it just transports whatever the
707
+ * `interrupt()` call carried. When in doubt, narrow with the
708
+ * `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt` type
709
+ * guards (which accept `unknown`) before reading variant-specific
710
+ * fields.
711
+ */
712
+ getInterrupt() {
713
+ return this._interrupt;
714
+ }
715
+ /**
716
+ * Returns the reason a hook halted the run via
717
+ * `preventContinuation: true`, or `undefined` if no hook halted.
718
+ *
719
+ * Hosts inspect this after `processStream` returns to distinguish a
720
+ * natural completion (`undefined`) from a hook-driven halt (a
721
+ * truthy string). Independent from `getInterrupt()` — a halted run
722
+ * has no interrupt; an interrupted run has no halt reason.
723
+ */
724
+ getHaltReason() {
725
+ return this._haltedReason;
726
+ }
727
+ /**
728
+ * Resume a paused HITL run with the value the user (or whatever
729
+ * decided the interrupt) supplied. The default `TResume` covers the
730
+ * `tool_approval` interrupt (the common case): an array of decisions
731
+ * in `action_requests` order, or a record keyed by `tool_call_id`.
732
+ *
733
+ * For other interrupt types (e.g., `ask_user_question` →
734
+ * `AskUserQuestionResolution`, or any custom interrupt a host raises
735
+ * from a custom node), pass the type parameter and the SDK forwards
736
+ * the value through unchanged. LangGraph delivers it as the return
737
+ * value of the original `interrupt()` call inside the paused node.
738
+ *
739
+ * The host MUST construct this Run with the same `thread_id` and the
740
+ * same checkpointer as the original paused run; LangGraph rebuilds
741
+ * graph state from the checkpoint and re-enters the interrupted node
742
+ * from the start.
743
+ */
744
+ /**
745
+ * Returns the per-Run file checkpointer when
746
+ * `toolExecution.local.fileCheckpointing === true` was set on the
747
+ * RunConfig. Hosts can capture extra paths or call `rewind()`
748
+ * directly. Returns undefined when checkpointing is disabled.
749
+ *
750
+ * Construction-time invariant: the checkpointer is shared across
751
+ * every ToolNode the graph compiles (single-agent and multi-agent),
752
+ * so a `rewind()` call here unwinds writes made by ANY agent in the
753
+ * run.
754
+ */
755
+ getFileCheckpointer() {
756
+ return this.Graph?.getOrCreateFileCheckpointer();
757
+ }
758
+ /**
759
+ * Convenience wrapper that calls `rewind()` on the per-Run file
760
+ * checkpointer. Restores every file the local engine snapshotted
761
+ * during this Run to its pre-write content (and deletes any path
762
+ * that didn't exist before being created). Returns the count of
763
+ * paths processed; returns 0 when checkpointing is disabled.
764
+ */
765
+ async rewindFiles() {
766
+ const cp = this.getFileCheckpointer();
767
+ return cp == null ? 0 : cp.rewind();
768
+ }
769
+ async resume(resumeValue, callerConfig, streamOptions) {
770
+ const interruptId = this._interrupt?.interruptId;
771
+ const scopedResume = typeof interruptId === "string" && interruptId.length > 0 && !isLangGraphResumeMapForInterrupt(resumeValue, interruptId) ? { [interruptId]: resumeValue } : resumeValue;
772
+ const resumeConfig = await this.resolveInterruptResumeConfig(callerConfig);
773
+ return this.processStream(new _langchain_langgraph.Command({ resume: scopedResume }), resumeConfig, streamOptions);
774
+ }
775
+ async resolveInterruptResumeConfig(callerConfig) {
776
+ const interrupt = this._interrupt;
777
+ const interruptId = interrupt?.interruptId;
778
+ const stateHistory = this.graphRunnable?.getStateHistory;
779
+ if (interrupt?.checkpointId != null && interrupt.checkpointId.length > 0) return {
780
+ ...callerConfig,
781
+ configurable: {
782
+ ...callerConfig.configurable,
783
+ checkpoint_id: interrupt.checkpointId,
784
+ ...typeof interrupt.checkpointNs === "string" ? { checkpoint_ns: interrupt.checkpointNs } : {}
785
+ }
786
+ };
787
+ if (interrupt == null || typeof interruptId !== "string" || interruptId.length === 0 || typeof stateHistory !== "function") return callerConfig;
788
+ for await (const snapshot of stateHistory.call(this.graphRunnable, callerConfig)) {
789
+ const hasMatchingInterrupt = snapshot.tasks?.some((task) => task.interrupts?.some((interrupt) => interrupt.id === interruptId) === true) === true;
790
+ const checkpointConfigurable = snapshot.config?.configurable;
791
+ if (!hasMatchingInterrupt || checkpointConfigurable == null) continue;
792
+ const checkpointId = checkpointConfigurable.checkpoint_id;
793
+ const checkpointNs = checkpointConfigurable.checkpoint_ns;
794
+ if (typeof checkpointId === "string" && checkpointId.length > 0) {
795
+ this._interrupt = {
796
+ ...interrupt,
797
+ checkpointId,
798
+ ...typeof checkpointNs === "string" ? { checkpointNs } : {}
799
+ };
800
+ return {
801
+ ...callerConfig,
802
+ configurable: {
803
+ ...callerConfig.configurable,
804
+ checkpoint_id: checkpointId,
805
+ ...typeof checkpointNs === "string" ? { checkpoint_ns: checkpointNs } : {}
806
+ }
807
+ };
808
+ }
809
+ }
810
+ return callerConfig;
811
+ }
812
+ createSystemCallback(clientCallbacks, key) {
813
+ return ((...args) => {
814
+ const clientCallback = clientCallbacks[key];
815
+ if (clientCallback && this.Graph) clientCallback(this.Graph, ...args);
816
+ });
817
+ }
818
+ getCallbacks(clientCallbacks) {
819
+ return {
820
+ ["handleToolError"]: this.createSystemCallback(clientCallbacks, "handleToolError"),
821
+ ["handleToolStart"]: this.createSystemCallback(clientCallbacks, "handleToolStart"),
822
+ ["handleToolEnd"]: this.createSystemCallback(clientCallbacks, "handleToolEnd")
823
+ };
824
+ }
825
+ async generateTitle({ provider, inputText, contentParts, titlePrompt, clientOptions, chainOptions, skipLanguage, titleMethod = "completion", titlePromptTemplate }) {
826
+ let titleLangfuseHandler;
827
+ let titleLangfuseConfig;
828
+ let titleUserId;
829
+ let titleSessionId;
830
+ const titleContext = this.Graph == null ? void 0 : this.Graph.agentContexts.get(this.Graph.defaultAgentId);
831
+ const traceMetadata = require_langfuse.createLangfuseTraceMetadata({
832
+ messageId: "title-" + this.id,
833
+ agentName: titleContext?.name
834
+ });
835
+ const titleRunName = require_langfuse.getLangfuseTraceName(traceMetadata, "LibreChat Title");
836
+ if (chainOptions != null) {
837
+ titleUserId = typeof chainOptions.configurable?.user_id === "string" ? chainOptions.configurable.user_id : void 0;
838
+ titleSessionId = typeof chainOptions.configurable?.thread_id === "string" ? chainOptions.configurable.thread_id : void 0;
839
+ titleLangfuseConfig = require_langfuseToolOutputTracing.resolveLangfuseConfig(this.langfuse, titleContext?.langfuse);
840
+ require_instrumentation.initializeLangfuseTracing(titleLangfuseConfig);
841
+ titleLangfuseHandler = require_langfuse.createLangfuseHandler({
842
+ langfuse: titleLangfuseConfig,
843
+ userId: titleUserId,
844
+ sessionId: titleSessionId,
845
+ traceMetadata,
846
+ tags: ["librechat", "title"]
847
+ });
848
+ if (titleLangfuseHandler != null) chainOptions.callbacks = require_callbacks.appendCallbacks(chainOptions.callbacks, [titleLangfuseHandler]);
849
+ }
850
+ const convoTemplate = _langchain_core_prompts.PromptTemplate.fromTemplate(titlePromptTemplate ?? "User: {input}\nAI: {output}");
851
+ const response = contentParts.map((part) => {
852
+ if (part?.type === "text") return part.text;
853
+ return "";
854
+ }).join("\n");
855
+ const model = require_init.initializeModel({
856
+ provider,
857
+ clientOptions
858
+ });
859
+ if (require_llm.isOpenAILike(provider) && (model instanceof _langchain_openai.ChatOpenAI || model instanceof _langchain_openai.AzureChatOpenAI)) {
860
+ model.temperature = clientOptions?.temperature;
861
+ model.topP = clientOptions?.topP;
862
+ model.frequencyPenalty = clientOptions?.frequencyPenalty;
863
+ model.presencePenalty = clientOptions?.presencePenalty;
864
+ model.n = clientOptions?.n;
865
+ }
866
+ const convoToTitleInput = new _langchain_core_runnables.RunnableLambda({ func: (promptValue) => ({
867
+ convo: promptValue.value,
868
+ inputText,
869
+ skipLanguage
870
+ }) }).withConfig({ runName: "ConvoTransform" });
871
+ const titleChain = titleMethod === "completion" ? await require_title.createCompletionTitleRunnable(model, titlePrompt) : await require_title.createTitleRunnable(model, titlePrompt);
872
+ /** Pipes `convoTemplate` -> `transformer` -> `titleChain` */
873
+ const fullChain = convoTemplate.withConfig({ runName: "ConvoTemplate" }).pipe(convoToTitleInput).pipe(titleChain).withConfig({ runName: "TitleChain" });
874
+ const invokeConfig = Object.assign({}, chainOptions, {
875
+ run_id: this.id,
876
+ runId: this.id,
877
+ runName: chainOptions?.runName ?? titleRunName
878
+ });
879
+ const invokeTitleChain = (runtimeConfig) => require_langfuse.withLangfuseAttributes({
880
+ langfuse: titleLangfuseConfig,
881
+ userId: titleUserId,
882
+ sessionId: titleSessionId,
883
+ traceName: runtimeConfig.runName ?? titleRunName,
884
+ traceMetadata,
885
+ tags: ["librechat", "title"]
886
+ }, () => fullChain.invoke({
887
+ input: inputText,
888
+ output: response
889
+ }, runtimeConfig));
890
+ try {
891
+ try {
892
+ return await require_langfuseToolOutputTracing.withLangfuseToolOutputTracingConfig(this.langfuse, () => invokeTitleChain(invokeConfig), titleContext?.langfuse);
893
+ } catch (_e) {
894
+ const langfuseHandler = require_callbacks.findCallback(invokeConfig.callbacks, require_langfuse.isLangfuseCallbackHandler);
895
+ const { callbacks: _cb, ...rest } = invokeConfig;
896
+ const safeConfig = Object.assign({}, rest, { callbacks: langfuseHandler ? [langfuseHandler] : [] });
897
+ return await require_langfuseToolOutputTracing.withLangfuseToolOutputTracingConfig(this.langfuse, () => invokeTitleChain(safeConfig), titleContext?.langfuse);
898
+ }
899
+ } finally {
900
+ await require_langfuse.disposeLangfuseHandler(titleLangfuseHandler);
901
+ }
902
+ }
903
+ };
1098
904
  function findLastMessageOfType(messages, type) {
1099
- for (let i = messages.length - 1; i >= 0; i--) {
1100
- if (messages[i].getType() === type) {
1101
- return messages[i];
1102
- }
1103
- }
1104
- return undefined;
905
+ for (let i = messages.length - 1; i >= 0; i--) if (messages[i].getType() === type) return messages[i];
1105
906
  }
1106
907
  function extractPromptText(message) {
1107
- const content = message.content;
1108
- if (typeof content === 'string') {
1109
- return content;
1110
- }
1111
- if (!Array.isArray(content)) {
1112
- return String(content);
1113
- }
1114
- const parts = [];
1115
- for (const block of content) {
1116
- if (typeof block === 'object' &&
1117
- 'type' in block &&
1118
- block.type === 'text' &&
1119
- 'text' in block &&
1120
- typeof block.text === 'string') {
1121
- parts.push(block.text);
1122
- }
1123
- }
1124
- return parts.join('\n');
908
+ const content = message.content;
909
+ if (typeof content === "string") return content;
910
+ if (!Array.isArray(content)) return String(content);
911
+ const parts = [];
912
+ for (const block of content) if (typeof block === "object" && "type" in block && block.type === "text" && "text" in block && typeof block.text === "string") parts.push(block.text);
913
+ return parts.join("\n");
1125
914
  }
1126
-
915
+ //#endregion
1127
916
  exports.Run = Run;
1128
917
  exports.defaultOmitOptions = defaultOmitOptions;
1129
- //# sourceMappingURL=run.cjs.map
918
+
919
+ //# sourceMappingURL=run.cjs.map