@librechat/agents 3.2.31 → 3.2.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (582) hide show
  1. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  2. package/dist/cjs/agents/AgentContext.cjs +844 -1046
  3. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  4. package/dist/cjs/common/constants.cjs +13 -13
  5. package/dist/cjs/common/constants.cjs.map +1 -1
  6. package/dist/cjs/common/enum.cjs +233 -240
  7. package/dist/cjs/common/enum.cjs.map +1 -1
  8. package/dist/cjs/common/index.cjs +2 -0
  9. package/dist/cjs/events.cjs +121 -169
  10. package/dist/cjs/events.cjs.map +1 -1
  11. package/dist/cjs/graphs/Graph.cjs +1389 -1807
  12. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  13. package/dist/cjs/graphs/MultiAgentGraph.cjs +713 -945
  14. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  15. package/dist/cjs/graphs/index.cjs +2 -0
  16. package/dist/cjs/hitl/askUserQuestion.cjs +60 -62
  17. package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -1
  18. package/dist/cjs/hitl/index.cjs +1 -0
  19. package/dist/cjs/hooks/HookRegistry.cjs +176 -202
  20. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  21. package/dist/cjs/hooks/createToolPolicyHook.cjs +71 -101
  22. package/dist/cjs/hooks/createToolPolicyHook.cjs.map +1 -1
  23. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +170 -273
  24. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -1
  25. package/dist/cjs/hooks/executeHooks.cjs +227 -282
  26. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  27. package/dist/cjs/hooks/index.cjs +6 -0
  28. package/dist/cjs/hooks/matchers.cjs +196 -230
  29. package/dist/cjs/hooks/matchers.cjs.map +1 -1
  30. package/dist/cjs/hooks/types.cjs +24 -24
  31. package/dist/cjs/hooks/types.cjs.map +1 -1
  32. package/dist/cjs/instrumentation.cjs +110 -137
  33. package/dist/cjs/instrumentation.cjs.map +1 -1
  34. package/dist/cjs/langchain/google-common.cjs +0 -3
  35. package/dist/cjs/langchain/index.cjs +80 -43
  36. package/dist/cjs/langchain/language_models/chat_models.cjs +0 -3
  37. package/dist/cjs/langchain/messages/tool.cjs +0 -3
  38. package/dist/cjs/langchain/messages.cjs +35 -18
  39. package/dist/cjs/langchain/openai.cjs +0 -3
  40. package/dist/cjs/langchain/prompts.cjs +5 -8
  41. package/dist/cjs/langchain/runnables.cjs +11 -10
  42. package/dist/cjs/langchain/tools.cjs +14 -11
  43. package/dist/cjs/langchain/utils/env.cjs +5 -8
  44. package/dist/cjs/langfuse.cjs +60 -79
  45. package/dist/cjs/langfuse.cjs.map +1 -1
  46. package/dist/cjs/langfuseToolOutputTracing.cjs +267 -399
  47. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  48. package/dist/cjs/llm/anthropic/index.cjs +432 -562
  49. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  50. package/dist/cjs/llm/anthropic/types.cjs +23 -47
  51. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  52. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +441 -696
  53. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  54. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +171 -252
  55. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  56. package/dist/cjs/llm/anthropic/utils/output_parsers.cjs +2 -0
  57. package/dist/cjs/llm/anthropic/utils/tools.cjs +12 -26
  58. package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -1
  59. package/dist/cjs/llm/bedrock/index.cjs +195 -240
  60. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  61. package/dist/cjs/llm/bedrock/toolCache.cjs +84 -106
  62. package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
  63. package/dist/cjs/llm/bedrock/utils/index.cjs +2 -0
  64. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +357 -620
  65. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  66. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +105 -149
  67. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  68. package/dist/cjs/llm/fake.cjs +86 -96
  69. package/dist/cjs/llm/fake.cjs.map +1 -1
  70. package/dist/cjs/llm/google/index.cjs +183 -237
  71. package/dist/cjs/llm/google/index.cjs.map +1 -1
  72. package/dist/cjs/llm/google/utils/common.cjs +398 -674
  73. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  74. package/dist/cjs/llm/google/utils/zod_to_genai_parameters.cjs +2 -0
  75. package/dist/cjs/llm/init.cjs +44 -53
  76. package/dist/cjs/llm/init.cjs.map +1 -1
  77. package/dist/cjs/llm/invoke.cjs +142 -182
  78. package/dist/cjs/llm/invoke.cjs.map +1 -1
  79. package/dist/cjs/llm/openai/index.cjs +991 -1276
  80. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  81. package/dist/cjs/llm/openai/utils/index.cjs +189 -316
  82. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  83. package/dist/cjs/llm/openrouter/index.cjs +102 -153
  84. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  85. package/dist/cjs/llm/openrouter/toolCache.cjs +35 -44
  86. package/dist/cjs/llm/openrouter/toolCache.cjs.map +1 -1
  87. package/dist/cjs/llm/providers.cjs +29 -37
  88. package/dist/cjs/llm/providers.cjs.map +1 -1
  89. package/dist/cjs/llm/request.cjs +20 -33
  90. package/dist/cjs/llm/request.cjs.map +1 -1
  91. package/dist/cjs/llm/vertexai/index.cjs +427 -453
  92. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  93. package/dist/cjs/main.cjs +547 -528
  94. package/dist/cjs/messages/anthropicToolCache.cjs +68 -119
  95. package/dist/cjs/messages/anthropicToolCache.cjs.map +1 -1
  96. package/dist/cjs/messages/cache.cjs +308 -401
  97. package/dist/cjs/messages/cache.cjs.map +1 -1
  98. package/dist/cjs/messages/content.cjs +36 -49
  99. package/dist/cjs/messages/content.cjs.map +1 -1
  100. package/dist/cjs/messages/contextPruning.cjs +112 -145
  101. package/dist/cjs/messages/contextPruning.cjs.map +1 -1
  102. package/dist/cjs/messages/contextPruningSettings.cjs +36 -46
  103. package/dist/cjs/messages/contextPruningSettings.cjs.map +1 -1
  104. package/dist/cjs/messages/core.cjs +256 -397
  105. package/dist/cjs/messages/core.cjs.map +1 -1
  106. package/dist/cjs/messages/format.cjs +904 -1382
  107. package/dist/cjs/messages/format.cjs.map +1 -1
  108. package/dist/cjs/messages/ids.cjs +16 -20
  109. package/dist/cjs/messages/ids.cjs.map +1 -1
  110. package/dist/cjs/messages/index.cjs +12 -0
  111. package/dist/cjs/messages/langchain.cjs +18 -18
  112. package/dist/cjs/messages/langchain.cjs.map +1 -1
  113. package/dist/cjs/messages/prune.cjs +1054 -1517
  114. package/dist/cjs/messages/prune.cjs.map +1 -1
  115. package/dist/cjs/messages/recency.cjs +77 -95
  116. package/dist/cjs/messages/recency.cjs.map +1 -1
  117. package/dist/cjs/messages/reducer.cjs +63 -78
  118. package/dist/cjs/messages/reducer.cjs.map +1 -1
  119. package/dist/cjs/messages/tools.cjs +51 -79
  120. package/dist/cjs/messages/tools.cjs.map +1 -1
  121. package/dist/cjs/openai/index.cjs +171 -217
  122. package/dist/cjs/openai/index.cjs.map +1 -1
  123. package/dist/cjs/responses/index.cjs +302 -391
  124. package/dist/cjs/responses/index.cjs.map +1 -1
  125. package/dist/cjs/run.cjs +903 -1113
  126. package/dist/cjs/run.cjs.map +1 -1
  127. package/dist/cjs/session/AgentSession.cjs +805 -986
  128. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  129. package/dist/cjs/session/JsonlSessionStore.cjs +327 -410
  130. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  131. package/dist/cjs/session/handlers.cjs +192 -208
  132. package/dist/cjs/session/handlers.cjs.map +1 -1
  133. package/dist/cjs/session/ids.cjs +9 -10
  134. package/dist/cjs/session/ids.cjs.map +1 -1
  135. package/dist/cjs/session/index.cjs +4 -0
  136. package/dist/cjs/session/messageSerialization.cjs +94 -156
  137. package/dist/cjs/session/messageSerialization.cjs.map +1 -1
  138. package/dist/cjs/splitStream.cjs +147 -206
  139. package/dist/cjs/splitStream.cjs.map +1 -1
  140. package/dist/cjs/stream.cjs +856 -1344
  141. package/dist/cjs/stream.cjs.map +1 -1
  142. package/dist/cjs/summarization/index.cjs +57 -101
  143. package/dist/cjs/summarization/index.cjs.map +1 -1
  144. package/dist/cjs/summarization/node.cjs +643 -796
  145. package/dist/cjs/summarization/node.cjs.map +1 -1
  146. package/dist/cjs/tools/BashExecutor.cjs +110 -136
  147. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  148. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +165 -245
  149. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  150. package/dist/cjs/tools/Calculator.cjs +36 -57
  151. package/dist/cjs/tools/Calculator.cjs.map +1 -1
  152. package/dist/cjs/tools/CodeExecutor.cjs +126 -168
  153. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  154. package/dist/cjs/tools/CodeSessionFileSummary.cjs +36 -46
  155. package/dist/cjs/tools/CodeSessionFileSummary.cjs.map +1 -1
  156. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +459 -649
  157. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  158. package/dist/cjs/tools/ReadFile.cjs +17 -20
  159. package/dist/cjs/tools/ReadFile.cjs.map +1 -1
  160. package/dist/cjs/tools/SkillTool.cjs +26 -27
  161. package/dist/cjs/tools/SkillTool.cjs.map +1 -1
  162. package/dist/cjs/tools/SubagentTool.cjs +59 -61
  163. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  164. package/dist/cjs/tools/ToolNode.cjs +2109 -2686
  165. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  166. package/dist/cjs/tools/ToolSearch.cjs +663 -825
  167. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  168. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs +248 -340
  169. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs.map +1 -1
  170. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +170 -197
  171. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -1
  172. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +425 -520
  173. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
  174. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +91 -124
  175. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -1
  176. package/dist/cjs/tools/cloudflare/index.cjs +4 -0
  177. package/dist/cjs/tools/eagerEventExecution.cjs +75 -99
  178. package/dist/cjs/tools/eagerEventExecution.cjs.map +1 -1
  179. package/dist/cjs/tools/handlers.cjs +200 -262
  180. package/dist/cjs/tools/handlers.cjs.map +1 -1
  181. package/dist/cjs/tools/local/CompileCheckTool.cjs +150 -212
  182. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
  183. package/dist/cjs/tools/local/FileCheckpointer.cjs +77 -85
  184. package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -1
  185. package/dist/cjs/tools/local/LocalCodingTools.cjs +763 -1022
  186. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
  187. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +666 -941
  188. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
  189. package/dist/cjs/tools/local/LocalExecutionTools.cjs +49 -92
  190. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
  191. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +286 -354
  192. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  193. package/dist/cjs/tools/local/attachments.cjs +108 -165
  194. package/dist/cjs/tools/local/attachments.cjs.map +1 -1
  195. package/dist/cjs/tools/local/bashAst.cjs +99 -113
  196. package/dist/cjs/tools/local/bashAst.cjs.map +1 -1
  197. package/dist/cjs/tools/local/editStrategies.cjs +126 -169
  198. package/dist/cjs/tools/local/editStrategies.cjs.map +1 -1
  199. package/dist/cjs/tools/local/index.cjs +12 -0
  200. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +136 -218
  201. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
  202. package/dist/cjs/tools/local/syntaxCheck.cjs +142 -161
  203. package/dist/cjs/tools/local/syntaxCheck.cjs.map +1 -1
  204. package/dist/cjs/tools/local/textEncoding.cjs +25 -23
  205. package/dist/cjs/tools/local/textEncoding.cjs.map +1 -1
  206. package/dist/cjs/tools/local/workspaceFS.cjs +38 -46
  207. package/dist/cjs/tools/local/workspaceFS.cjs.map +1 -1
  208. package/dist/cjs/tools/ptcTimeout.cjs +27 -47
  209. package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
  210. package/dist/cjs/tools/schema.cjs +24 -23
  211. package/dist/cjs/tools/schema.cjs.map +1 -1
  212. package/dist/cjs/tools/search/anthropic.cjs +24 -33
  213. package/dist/cjs/tools/search/anthropic.cjs.map +1 -1
  214. package/dist/cjs/tools/search/content.cjs +95 -137
  215. package/dist/cjs/tools/search/content.cjs.map +1 -1
  216. package/dist/cjs/tools/search/firecrawl.cjs +141 -172
  217. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  218. package/dist/cjs/tools/search/format.cjs +128 -196
  219. package/dist/cjs/tools/search/format.cjs.map +1 -1
  220. package/dist/cjs/tools/search/highlights.cjs +165 -232
  221. package/dist/cjs/tools/search/highlights.cjs.map +1 -1
  222. package/dist/cjs/tools/search/index.cjs +2 -0
  223. package/dist/cjs/tools/search/rerankers.cjs +151 -174
  224. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  225. package/dist/cjs/tools/search/schema.cjs +40 -39
  226. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  227. package/dist/cjs/tools/search/search.cjs +428 -530
  228. package/dist/cjs/tools/search/search.cjs.map +1 -1
  229. package/dist/cjs/tools/search/serper-scraper.cjs +106 -127
  230. package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
  231. package/dist/cjs/tools/search/tavily-scraper.cjs +129 -181
  232. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -1
  233. package/dist/cjs/tools/search/tavily-search.cjs +295 -359
  234. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
  235. package/dist/cjs/tools/search/tool.cjs +260 -299
  236. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  237. package/dist/cjs/tools/search/utils.cjs +74 -117
  238. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  239. package/dist/cjs/tools/skillCatalog.cjs +54 -72
  240. package/dist/cjs/tools/skillCatalog.cjs.map +1 -1
  241. package/dist/cjs/tools/streamedToolCallSeals.cjs +19 -36
  242. package/dist/cjs/tools/streamedToolCallSeals.cjs.map +1 -1
  243. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +612 -771
  244. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  245. package/dist/cjs/tools/subagent/index.cjs +1 -0
  246. package/dist/cjs/tools/toolOutputReferences.cjs +523 -630
  247. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  248. package/dist/cjs/utils/callbacks.cjs +11 -21
  249. package/dist/cjs/utils/callbacks.cjs.map +1 -1
  250. package/dist/cjs/utils/errors.cjs +70 -95
  251. package/dist/cjs/utils/errors.cjs.map +1 -1
  252. package/dist/cjs/utils/events.cjs +32 -42
  253. package/dist/cjs/utils/events.cjs.map +1 -1
  254. package/dist/cjs/utils/graph.cjs +8 -12
  255. package/dist/cjs/utils/graph.cjs.map +1 -1
  256. package/dist/cjs/utils/handlers.cjs +60 -82
  257. package/dist/cjs/utils/handlers.cjs.map +1 -1
  258. package/dist/cjs/utils/index.cjs +9 -0
  259. package/dist/cjs/utils/llm.cjs +19 -27
  260. package/dist/cjs/utils/llm.cjs.map +1 -1
  261. package/dist/cjs/utils/misc.cjs +30 -46
  262. package/dist/cjs/utils/misc.cjs.map +1 -1
  263. package/dist/cjs/utils/run.cjs +50 -66
  264. package/dist/cjs/utils/run.cjs.map +1 -1
  265. package/dist/cjs/utils/schema.cjs +11 -19
  266. package/dist/cjs/utils/schema.cjs.map +1 -1
  267. package/dist/cjs/utils/title.cjs +71 -106
  268. package/dist/cjs/utils/title.cjs.map +1 -1
  269. package/dist/cjs/utils/tokens.cjs +186 -283
  270. package/dist/cjs/utils/tokens.cjs.map +1 -1
  271. package/dist/cjs/utils/truncation.cjs +95 -114
  272. package/dist/cjs/utils/truncation.cjs.map +1 -1
  273. package/dist/esm/agents/AgentContext.mjs +844 -1044
  274. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  275. package/dist/esm/common/constants.mjs +13 -11
  276. package/dist/esm/common/constants.mjs.map +1 -1
  277. package/dist/esm/common/enum.mjs +221 -238
  278. package/dist/esm/common/enum.mjs.map +1 -1
  279. package/dist/esm/common/index.mjs +3 -0
  280. package/dist/esm/events.mjs +121 -167
  281. package/dist/esm/events.mjs.map +1 -1
  282. package/dist/esm/graphs/Graph.mjs +1388 -1804
  283. package/dist/esm/graphs/Graph.mjs.map +1 -1
  284. package/dist/esm/graphs/MultiAgentGraph.mjs +713 -943
  285. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  286. package/dist/esm/graphs/index.mjs +3 -0
  287. package/dist/esm/hitl/askUserQuestion.mjs +60 -60
  288. package/dist/esm/hitl/askUserQuestion.mjs.map +1 -1
  289. package/dist/esm/hitl/index.mjs +2 -0
  290. package/dist/esm/hooks/HookRegistry.mjs +176 -200
  291. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  292. package/dist/esm/hooks/createToolPolicyHook.mjs +71 -99
  293. package/dist/esm/hooks/createToolPolicyHook.mjs.map +1 -1
  294. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +170 -271
  295. package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -1
  296. package/dist/esm/hooks/executeHooks.mjs +227 -280
  297. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  298. package/dist/esm/hooks/index.mjs +7 -0
  299. package/dist/esm/hooks/matchers.mjs +196 -228
  300. package/dist/esm/hooks/matchers.mjs.map +1 -1
  301. package/dist/esm/hooks/types.mjs +24 -22
  302. package/dist/esm/hooks/types.mjs.map +1 -1
  303. package/dist/esm/instrumentation.mjs +109 -132
  304. package/dist/esm/instrumentation.mjs.map +1 -1
  305. package/dist/esm/langchain/google-common.mjs +1 -2
  306. package/dist/esm/langchain/index.mjs +5 -5
  307. package/dist/esm/langchain/language_models/chat_models.mjs +1 -2
  308. package/dist/esm/langchain/messages/tool.mjs +1 -2
  309. package/dist/esm/langchain/messages.mjs +2 -2
  310. package/dist/esm/langchain/openai.mjs +1 -2
  311. package/dist/esm/langchain/prompts.mjs +2 -2
  312. package/dist/esm/langchain/runnables.mjs +2 -2
  313. package/dist/esm/langchain/tools.mjs +2 -2
  314. package/dist/esm/langchain/utils/env.mjs +2 -2
  315. package/dist/esm/langfuse.mjs +60 -76
  316. package/dist/esm/langfuse.mjs.map +1 -1
  317. package/dist/esm/langfuseToolOutputTracing.mjs +267 -395
  318. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  319. package/dist/esm/llm/anthropic/index.mjs +432 -559
  320. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  321. package/dist/esm/llm/anthropic/types.mjs +23 -45
  322. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  323. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +439 -690
  324. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  325. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +171 -249
  326. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  327. package/dist/esm/llm/anthropic/utils/output_parsers.mjs +3 -0
  328. package/dist/esm/llm/anthropic/utils/tools.mjs +12 -24
  329. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -1
  330. package/dist/esm/llm/bedrock/index.mjs +195 -238
  331. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  332. package/dist/esm/llm/bedrock/toolCache.mjs +84 -104
  333. package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
  334. package/dist/esm/llm/bedrock/utils/index.mjs +3 -0
  335. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +357 -618
  336. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  337. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +105 -147
  338. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  339. package/dist/esm/llm/fake.mjs +86 -94
  340. package/dist/esm/llm/fake.mjs.map +1 -1
  341. package/dist/esm/llm/google/index.mjs +183 -235
  342. package/dist/esm/llm/google/index.mjs.map +1 -1
  343. package/dist/esm/llm/google/utils/common.mjs +397 -666
  344. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  345. package/dist/esm/llm/google/utils/zod_to_genai_parameters.mjs +3 -0
  346. package/dist/esm/llm/init.mjs +44 -51
  347. package/dist/esm/llm/init.mjs.map +1 -1
  348. package/dist/esm/llm/invoke.mjs +142 -180
  349. package/dist/esm/llm/invoke.mjs.map +1 -1
  350. package/dist/esm/llm/openai/index.mjs +991 -1271
  351. package/dist/esm/llm/openai/index.mjs.map +1 -1
  352. package/dist/esm/llm/openai/utils/index.mjs +188 -312
  353. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  354. package/dist/esm/llm/openrouter/index.mjs +102 -151
  355. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  356. package/dist/esm/llm/openrouter/toolCache.mjs +35 -42
  357. package/dist/esm/llm/openrouter/toolCache.mjs.map +1 -1
  358. package/dist/esm/llm/providers.mjs +29 -34
  359. package/dist/esm/llm/providers.mjs.map +1 -1
  360. package/dist/esm/llm/request.mjs +20 -31
  361. package/dist/esm/llm/request.mjs.map +1 -1
  362. package/dist/esm/llm/vertexai/index.mjs +427 -449
  363. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  364. package/dist/esm/main.mjs +99 -87
  365. package/dist/esm/messages/anthropicToolCache.mjs +68 -117
  366. package/dist/esm/messages/anthropicToolCache.mjs.map +1 -1
  367. package/dist/esm/messages/cache.mjs +308 -399
  368. package/dist/esm/messages/cache.mjs.map +1 -1
  369. package/dist/esm/messages/content.mjs +36 -47
  370. package/dist/esm/messages/content.mjs.map +1 -1
  371. package/dist/esm/messages/contextPruning.mjs +112 -143
  372. package/dist/esm/messages/contextPruning.mjs.map +1 -1
  373. package/dist/esm/messages/contextPruningSettings.mjs +36 -44
  374. package/dist/esm/messages/contextPruningSettings.mjs.map +1 -1
  375. package/dist/esm/messages/core.mjs +254 -393
  376. package/dist/esm/messages/core.mjs.map +1 -1
  377. package/dist/esm/messages/format.mjs +902 -1378
  378. package/dist/esm/messages/format.mjs.map +1 -1
  379. package/dist/esm/messages/ids.mjs +16 -18
  380. package/dist/esm/messages/ids.mjs.map +1 -1
  381. package/dist/esm/messages/index.mjs +13 -0
  382. package/dist/esm/messages/langchain.mjs +18 -16
  383. package/dist/esm/messages/langchain.mjs.map +1 -1
  384. package/dist/esm/messages/prune.mjs +1053 -1514
  385. package/dist/esm/messages/prune.mjs.map +1 -1
  386. package/dist/esm/messages/recency.mjs +77 -93
  387. package/dist/esm/messages/recency.mjs.map +1 -1
  388. package/dist/esm/messages/reducer.mjs +63 -76
  389. package/dist/esm/messages/reducer.mjs.map +1 -1
  390. package/dist/esm/messages/tools.mjs +49 -75
  391. package/dist/esm/messages/tools.mjs.map +1 -1
  392. package/dist/esm/openai/index.mjs +170 -215
  393. package/dist/esm/openai/index.mjs.map +1 -1
  394. package/dist/esm/responses/index.mjs +301 -389
  395. package/dist/esm/responses/index.mjs.map +1 -1
  396. package/dist/esm/run.mjs +903 -1111
  397. package/dist/esm/run.mjs.map +1 -1
  398. package/dist/esm/session/AgentSession.mjs +806 -985
  399. package/dist/esm/session/AgentSession.mjs.map +1 -1
  400. package/dist/esm/session/JsonlSessionStore.mjs +326 -407
  401. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  402. package/dist/esm/session/handlers.mjs +192 -206
  403. package/dist/esm/session/handlers.mjs.map +1 -1
  404. package/dist/esm/session/ids.mjs +9 -8
  405. package/dist/esm/session/ids.mjs.map +1 -1
  406. package/dist/esm/session/index.mjs +5 -0
  407. package/dist/esm/session/messageSerialization.mjs +94 -154
  408. package/dist/esm/session/messageSerialization.mjs.map +1 -1
  409. package/dist/esm/splitStream.mjs +147 -204
  410. package/dist/esm/splitStream.mjs.map +1 -1
  411. package/dist/esm/stream.mjs +854 -1341
  412. package/dist/esm/stream.mjs.map +1 -1
  413. package/dist/esm/summarization/index.mjs +57 -99
  414. package/dist/esm/summarization/index.mjs.map +1 -1
  415. package/dist/esm/summarization/node.mjs +640 -790
  416. package/dist/esm/summarization/node.mjs.map +1 -1
  417. package/dist/esm/tools/BashExecutor.mjs +103 -129
  418. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  419. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +162 -239
  420. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  421. package/dist/esm/tools/Calculator.mjs +34 -36
  422. package/dist/esm/tools/Calculator.mjs.map +1 -1
  423. package/dist/esm/tools/CodeExecutor.mjs +123 -164
  424. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  425. package/dist/esm/tools/CodeSessionFileSummary.mjs +36 -44
  426. package/dist/esm/tools/CodeSessionFileSummary.mjs.map +1 -1
  427. package/dist/esm/tools/ProgrammaticToolCalling.mjs +454 -644
  428. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  429. package/dist/esm/tools/ReadFile.mjs +17 -18
  430. package/dist/esm/tools/ReadFile.mjs.map +1 -1
  431. package/dist/esm/tools/SkillTool.mjs +26 -25
  432. package/dist/esm/tools/SkillTool.mjs.map +1 -1
  433. package/dist/esm/tools/SubagentTool.mjs +59 -59
  434. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  435. package/dist/esm/tools/ToolNode.mjs +2107 -2684
  436. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  437. package/dist/esm/tools/ToolSearch.mjs +659 -804
  438. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  439. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs +248 -338
  440. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs.map +1 -1
  441. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +170 -195
  442. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -1
  443. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +424 -517
  444. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
  445. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +91 -122
  446. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -1
  447. package/dist/esm/tools/cloudflare/index.mjs +5 -0
  448. package/dist/esm/tools/eagerEventExecution.mjs +75 -96
  449. package/dist/esm/tools/eagerEventExecution.mjs.map +1 -1
  450. package/dist/esm/tools/handlers.mjs +200 -260
  451. package/dist/esm/tools/handlers.mjs.map +1 -1
  452. package/dist/esm/tools/local/CompileCheckTool.mjs +150 -210
  453. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
  454. package/dist/esm/tools/local/FileCheckpointer.mjs +77 -83
  455. package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -1
  456. package/dist/esm/tools/local/LocalCodingTools.mjs +760 -1017
  457. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
  458. package/dist/esm/tools/local/LocalExecutionEngine.mjs +663 -936
  459. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
  460. package/dist/esm/tools/local/LocalExecutionTools.mjs +49 -90
  461. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
  462. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +283 -349
  463. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  464. package/dist/esm/tools/local/attachments.mjs +108 -163
  465. package/dist/esm/tools/local/attachments.mjs.map +1 -1
  466. package/dist/esm/tools/local/bashAst.mjs +99 -111
  467. package/dist/esm/tools/local/bashAst.mjs.map +1 -1
  468. package/dist/esm/tools/local/editStrategies.mjs +126 -167
  469. package/dist/esm/tools/local/editStrategies.mjs.map +1 -1
  470. package/dist/esm/tools/local/index.mjs +13 -0
  471. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +136 -216
  472. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
  473. package/dist/esm/tools/local/syntaxCheck.mjs +138 -155
  474. package/dist/esm/tools/local/syntaxCheck.mjs.map +1 -1
  475. package/dist/esm/tools/local/textEncoding.mjs +25 -21
  476. package/dist/esm/tools/local/textEncoding.mjs.map +1 -1
  477. package/dist/esm/tools/local/workspaceFS.mjs +38 -44
  478. package/dist/esm/tools/local/workspaceFS.mjs.map +1 -1
  479. package/dist/esm/tools/ptcTimeout.mjs +27 -42
  480. package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
  481. package/dist/esm/tools/schema.mjs +24 -21
  482. package/dist/esm/tools/schema.mjs.map +1 -1
  483. package/dist/esm/tools/search/anthropic.mjs +24 -31
  484. package/dist/esm/tools/search/anthropic.mjs.map +1 -1
  485. package/dist/esm/tools/search/content.mjs +93 -116
  486. package/dist/esm/tools/search/content.mjs.map +1 -1
  487. package/dist/esm/tools/search/firecrawl.mjs +139 -169
  488. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  489. package/dist/esm/tools/search/format.mjs +128 -194
  490. package/dist/esm/tools/search/format.mjs.map +1 -1
  491. package/dist/esm/tools/search/highlights.mjs +165 -230
  492. package/dist/esm/tools/search/highlights.mjs.map +1 -1
  493. package/dist/esm/tools/search/index.mjs +3 -0
  494. package/dist/esm/tools/search/rerankers.mjs +149 -168
  495. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  496. package/dist/esm/tools/search/schema.mjs +39 -37
  497. package/dist/esm/tools/search/schema.mjs.map +1 -1
  498. package/dist/esm/tools/search/search.mjs +426 -528
  499. package/dist/esm/tools/search/search.mjs.map +1 -1
  500. package/dist/esm/tools/search/serper-scraper.mjs +104 -124
  501. package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
  502. package/dist/esm/tools/search/tavily-scraper.mjs +127 -178
  503. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -1
  504. package/dist/esm/tools/search/tavily-search.mjs +293 -357
  505. package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
  506. package/dist/esm/tools/search/tool.mjs +259 -297
  507. package/dist/esm/tools/search/tool.mjs.map +1 -1
  508. package/dist/esm/tools/search/utils.mjs +74 -115
  509. package/dist/esm/tools/search/utils.mjs.map +1 -1
  510. package/dist/esm/tools/skillCatalog.mjs +54 -70
  511. package/dist/esm/tools/skillCatalog.mjs.map +1 -1
  512. package/dist/esm/tools/streamedToolCallSeals.mjs +19 -31
  513. package/dist/esm/tools/streamedToolCallSeals.mjs.map +1 -1
  514. package/dist/esm/tools/subagent/SubagentExecutor.mjs +612 -768
  515. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  516. package/dist/esm/tools/subagent/index.mjs +2 -0
  517. package/dist/esm/tools/toolOutputReferences.mjs +523 -624
  518. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  519. package/dist/esm/utils/callbacks.mjs +11 -19
  520. package/dist/esm/utils/callbacks.mjs.map +1 -1
  521. package/dist/esm/utils/errors.mjs +70 -93
  522. package/dist/esm/utils/errors.mjs.map +1 -1
  523. package/dist/esm/utils/events.mjs +32 -40
  524. package/dist/esm/utils/events.mjs.map +1 -1
  525. package/dist/esm/utils/graph.mjs +8 -10
  526. package/dist/esm/utils/graph.mjs.map +1 -1
  527. package/dist/esm/utils/handlers.mjs +60 -80
  528. package/dist/esm/utils/handlers.mjs.map +1 -1
  529. package/dist/esm/utils/index.mjs +10 -0
  530. package/dist/esm/utils/llm.mjs +19 -25
  531. package/dist/esm/utils/llm.mjs.map +1 -1
  532. package/dist/esm/utils/misc.mjs +30 -44
  533. package/dist/esm/utils/misc.mjs.map +1 -1
  534. package/dist/esm/utils/run.mjs +50 -64
  535. package/dist/esm/utils/run.mjs.map +1 -1
  536. package/dist/esm/utils/schema.mjs +11 -17
  537. package/dist/esm/utils/schema.mjs.map +1 -1
  538. package/dist/esm/utils/title.mjs +71 -104
  539. package/dist/esm/utils/title.mjs.map +1 -1
  540. package/dist/esm/utils/tokens.mjs +186 -281
  541. package/dist/esm/utils/tokens.mjs.map +1 -1
  542. package/dist/esm/utils/truncation.mjs +95 -112
  543. package/dist/esm/utils/truncation.mjs.map +1 -1
  544. package/dist/types/messages/format.d.ts +5 -0
  545. package/dist/types/tools/search/tool.d.ts +17 -0
  546. package/dist/types/tools/search/types.d.ts +4 -0
  547. package/package.json +11 -17
  548. package/src/llm/anthropic/llm.spec.ts +36 -0
  549. package/src/llm/anthropic/utils/message_inputs.ts +45 -3
  550. package/src/llm/anthropic/utils/message_outputs.ts +6 -2
  551. package/src/llm/anthropic/utils/streaming-tool-input.test.ts +186 -0
  552. package/src/messages/cache.test.ts +122 -0
  553. package/src/messages/cache.ts +25 -1
  554. package/src/messages/format.ts +9 -0
  555. package/src/messages/formatAgentMessages.skills.test.ts +100 -0
  556. package/src/tools/search/highlights.ts +9 -1
  557. package/src/tools/search/search.ts +41 -3
  558. package/src/tools/search/source-processing.test.ts +373 -0
  559. package/src/tools/search/tool.ts +22 -2
  560. package/src/tools/search/types.ts +4 -0
  561. package/dist/cjs/langchain/google-common.cjs.map +0 -1
  562. package/dist/cjs/langchain/index.cjs.map +0 -1
  563. package/dist/cjs/langchain/language_models/chat_models.cjs.map +0 -1
  564. package/dist/cjs/langchain/messages/tool.cjs.map +0 -1
  565. package/dist/cjs/langchain/messages.cjs.map +0 -1
  566. package/dist/cjs/langchain/openai.cjs.map +0 -1
  567. package/dist/cjs/langchain/prompts.cjs.map +0 -1
  568. package/dist/cjs/langchain/runnables.cjs.map +0 -1
  569. package/dist/cjs/langchain/tools.cjs.map +0 -1
  570. package/dist/cjs/langchain/utils/env.cjs.map +0 -1
  571. package/dist/cjs/main.cjs.map +0 -1
  572. package/dist/esm/langchain/google-common.mjs.map +0 -1
  573. package/dist/esm/langchain/index.mjs.map +0 -1
  574. package/dist/esm/langchain/language_models/chat_models.mjs.map +0 -1
  575. package/dist/esm/langchain/messages/tool.mjs.map +0 -1
  576. package/dist/esm/langchain/messages.mjs.map +0 -1
  577. package/dist/esm/langchain/openai.mjs.map +0 -1
  578. package/dist/esm/langchain/prompts.mjs.map +0 -1
  579. package/dist/esm/langchain/runnables.mjs.map +0 -1
  580. package/dist/esm/langchain/tools.mjs.map +0 -1
  581. package/dist/esm/langchain/utils/env.mjs.map +0 -1
  582. package/dist/esm/main.mjs.map +0 -1
@@ -1,216 +1,190 @@
1
- 'use strict';
2
-
1
+ //#region src/hooks/HookRegistry.ts
3
2
  /**
4
- * Run-scoped storage for hook matchers with an additional layer for
5
- * session-scoped matchers that should be cleaned up between sessions.
6
- *
7
- * Hosts construct one registry per `Run` (mirroring how `HandlerRegistry` is
8
- * scoped) and register global matchers + per-session matchers against it.
9
- * Registration is strictly additive — nothing in this class mutates a
10
- * matcher's callbacks or flags after insertion.
11
- *
12
- * ## Why `Map<sessionId, MatcherBucket>` and not `Record`
13
- *
14
- * LibreChat runs thousands of parallel sessions in one Node process, and
15
- * hook registration happens inside hot paths (tool loading, agent spawning).
16
- * A `Record<sessionId, ...>` has to be spread on every insertion, which is
17
- * O(n) per call and O(n²) total for a batch of parallel registrations. A
18
- * Map mutates in place, keeping insertions O(1). This mirrors the reasoning
19
- * Claude Code documents at `utils/hooks/sessionHooks.ts:62`.
20
- */
21
- class HookRegistry {
22
- global = {};
23
- sessions = new Map();
24
- /**
25
- * Per-session halt signals. Scoped by `sessionId` (= the run id the
26
- * hook fired under) so a host that shares one registry across
27
- * concurrent runs cannot leak `preventContinuation` from one run
28
- * into another. Without scoping, a halt raised by run A's hook
29
- * would trip run B's stream-loop poll on the next iteration —
30
- * silently terminating an unrelated run.
31
- *
32
- * Map storage mirrors the reasoning above for session matchers:
33
- * O(1) insertion in hot paths, no spread-on-write.
34
- */
35
- haltSignals = new Map();
36
- /**
37
- * Register a matcher for the lifetime of this registry (= one Run).
38
- * Returns an unregister function that removes the matcher by reference.
39
- */
40
- register(event, matcher) {
41
- const list = ensureList(this.global, event);
42
- list.push(widen(matcher));
43
- return () => {
44
- removeFromList(list, matcher);
45
- };
46
- }
47
- /**
48
- * Register a matcher for a specific session. Cleared automatically when
49
- * `clearSession(sessionId)` is called, or can be removed directly via the
50
- * returned unregister function.
51
- */
52
- registerSession(sessionId, event, matcher) {
53
- const bucket = this.ensureSessionBucket(sessionId);
54
- const list = ensureList(bucket, event);
55
- list.push(widen(matcher));
56
- return () => {
57
- removeFromList(list, matcher);
58
- };
59
- }
60
- /**
61
- * Returns all matchers registered for `event`, concatenating global first
62
- * and then session-specific (when `sessionId` is supplied). The caller
63
- * receives a fresh array, so iterating it is safe even if a matcher is
64
- * removed mid-iteration (e.g. via `once: true`).
65
- */
66
- getMatchers(event, sessionId) {
67
- const globalList = readList(this.global, event);
68
- if (sessionId === undefined) {
69
- return snapshot(globalList);
70
- }
71
- const bucket = this.sessions.get(sessionId);
72
- if (bucket === undefined) {
73
- return snapshot(globalList);
74
- }
75
- const sessionList = readList(bucket, event);
76
- if (globalList.length === 0) {
77
- return snapshot(sessionList);
78
- }
79
- if (sessionList.length === 0) {
80
- return snapshot(globalList);
81
- }
82
- return snapshot([...globalList, ...sessionList]);
83
- }
84
- /**
85
- * Removes `matcher` by reference from global storage first, falling back
86
- * to the session bucket when `sessionId` is supplied. Used by
87
- * `executeHooks` to drop `once: true` matchers after they fire.
88
- */
89
- removeMatcher(event, matcher, sessionId) {
90
- if (removeFromList(readList(this.global, event), matcher)) {
91
- return true;
92
- }
93
- if (sessionId === undefined) {
94
- return false;
95
- }
96
- const bucket = this.sessions.get(sessionId);
97
- if (bucket === undefined) {
98
- return false;
99
- }
100
- return removeFromList(readList(bucket, event), matcher);
101
- }
102
- /**
103
- * Drops every session-scoped matcher for `sessionId`. Call this in the
104
- * `finally` block around a Run so a `once: true` hook that never fired
105
- * cannot leak into the next session on the same registry.
106
- */
107
- clearSession(sessionId) {
108
- this.sessions.delete(sessionId);
109
- }
110
- /**
111
- * Raise a halt signal scoped to `sessionId` (= the run id the hook
112
- * fired under). The SDK's run loop polls for this between stream
113
- * events with the run's own id. First-write-wins per session: a
114
- * halt already raised by an earlier hook in the same run is
115
- * preserved so the original `reason` / `source` aren't overwritten.
116
- *
117
- * Per-session scoping is critical when hosts share one registry
118
- * across concurrent runs (e.g. a global policy registered once and
119
- * reused). Without it, a `preventContinuation` from run A would
120
- * trip run B's stream-loop poll on the next iteration and silently
121
- * terminate an unrelated run.
122
- *
123
- * Called by the SDK after `executeHooks` returns an aggregate with
124
- * `preventContinuation: true`. Hosts can also call it directly from
125
- * inside a hook callback if they want to halt without going through
126
- * the aggregated return value, but `preventContinuation` is the
127
- * canonical path.
128
- */
129
- haltRun(sessionId, reason, source) {
130
- if (this.haltSignals.has(sessionId)) {
131
- return;
132
- }
133
- this.haltSignals.set(sessionId, { reason, source });
134
- }
135
- /**
136
- * Returns the halt signal raised by hooks running under `sessionId`,
137
- * or `undefined` if no hook in that run has halted. Polled by
138
- * `Run.processStream` between stream events using the run's own id.
139
- */
140
- getHaltSignal(sessionId) {
141
- return this.haltSignals.get(sessionId);
142
- }
143
- /**
144
- * Clears the halt signal for `sessionId`. Called by
145
- * `Run.processStream` in its `finally` block so a subsequent
146
- * invocation of the same Run (e.g. resume) starts with a fresh
147
- * halt state. No-op when no signal exists for that session.
148
- */
149
- clearHaltSignal(sessionId) {
150
- this.haltSignals.delete(sessionId);
151
- }
152
- /** True if at least one matcher exists for `event` (global + session). */
153
- hasHookFor(event, sessionId) {
154
- if (readList(this.global, event).length > 0) {
155
- return true;
156
- }
157
- if (sessionId === undefined) {
158
- return false;
159
- }
160
- const bucket = this.sessions.get(sessionId);
161
- if (bucket === undefined) {
162
- return false;
163
- }
164
- return readList(bucket, event).length > 0;
165
- }
166
- ensureSessionBucket(sessionId) {
167
- const existing = this.sessions.get(sessionId);
168
- if (existing !== undefined) {
169
- return existing;
170
- }
171
- const fresh = {};
172
- this.sessions.set(sessionId, fresh);
173
- return fresh;
174
- }
175
- }
3
+ * Run-scoped storage for hook matchers with an additional layer for
4
+ * session-scoped matchers that should be cleaned up between sessions.
5
+ *
6
+ * Hosts construct one registry per `Run` (mirroring how `HandlerRegistry` is
7
+ * scoped) and register global matchers + per-session matchers against it.
8
+ * Registration is strictly additive — nothing in this class mutates a
9
+ * matcher's callbacks or flags after insertion.
10
+ *
11
+ * ## Why `Map<sessionId, MatcherBucket>` and not `Record`
12
+ *
13
+ * LibreChat runs thousands of parallel sessions in one Node process, and
14
+ * hook registration happens inside hot paths (tool loading, agent spawning).
15
+ * A `Record<sessionId, ...>` has to be spread on every insertion, which is
16
+ * O(n) per call and O(n²) total for a batch of parallel registrations. A
17
+ * Map mutates in place, keeping insertions O(1). This mirrors the reasoning
18
+ * Claude Code documents at `utils/hooks/sessionHooks.ts:62`.
19
+ */
20
+ var HookRegistry = class {
21
+ global = {};
22
+ sessions = /* @__PURE__ */ new Map();
23
+ /**
24
+ * Per-session halt signals. Scoped by `sessionId` (= the run id the
25
+ * hook fired under) so a host that shares one registry across
26
+ * concurrent runs cannot leak `preventContinuation` from one run
27
+ * into another. Without scoping, a halt raised by run A's hook
28
+ * would trip run B's stream-loop poll on the next iteration —
29
+ * silently terminating an unrelated run.
30
+ *
31
+ * Map storage mirrors the reasoning above for session matchers:
32
+ * O(1) insertion in hot paths, no spread-on-write.
33
+ */
34
+ haltSignals = /* @__PURE__ */ new Map();
35
+ /**
36
+ * Register a matcher for the lifetime of this registry (= one Run).
37
+ * Returns an unregister function that removes the matcher by reference.
38
+ */
39
+ register(event, matcher) {
40
+ const list = ensureList(this.global, event);
41
+ list.push(widen(matcher));
42
+ return () => {
43
+ removeFromList(list, matcher);
44
+ };
45
+ }
46
+ /**
47
+ * Register a matcher for a specific session. Cleared automatically when
48
+ * `clearSession(sessionId)` is called, or can be removed directly via the
49
+ * returned unregister function.
50
+ */
51
+ registerSession(sessionId, event, matcher) {
52
+ const list = ensureList(this.ensureSessionBucket(sessionId), event);
53
+ list.push(widen(matcher));
54
+ return () => {
55
+ removeFromList(list, matcher);
56
+ };
57
+ }
58
+ /**
59
+ * Returns all matchers registered for `event`, concatenating global first
60
+ * and then session-specific (when `sessionId` is supplied). The caller
61
+ * receives a fresh array, so iterating it is safe even if a matcher is
62
+ * removed mid-iteration (e.g. via `once: true`).
63
+ */
64
+ getMatchers(event, sessionId) {
65
+ const globalList = readList(this.global, event);
66
+ if (sessionId === void 0) return snapshot(globalList);
67
+ const bucket = this.sessions.get(sessionId);
68
+ if (bucket === void 0) return snapshot(globalList);
69
+ const sessionList = readList(bucket, event);
70
+ if (globalList.length === 0) return snapshot(sessionList);
71
+ if (sessionList.length === 0) return snapshot(globalList);
72
+ return snapshot([...globalList, ...sessionList]);
73
+ }
74
+ /**
75
+ * Removes `matcher` by reference from global storage first, falling back
76
+ * to the session bucket when `sessionId` is supplied. Used by
77
+ * `executeHooks` to drop `once: true` matchers after they fire.
78
+ */
79
+ removeMatcher(event, matcher, sessionId) {
80
+ if (removeFromList(readList(this.global, event), matcher)) return true;
81
+ if (sessionId === void 0) return false;
82
+ const bucket = this.sessions.get(sessionId);
83
+ if (bucket === void 0) return false;
84
+ return removeFromList(readList(bucket, event), matcher);
85
+ }
86
+ /**
87
+ * Drops every session-scoped matcher for `sessionId`. Call this in the
88
+ * `finally` block around a Run so a `once: true` hook that never fired
89
+ * cannot leak into the next session on the same registry.
90
+ */
91
+ clearSession(sessionId) {
92
+ this.sessions.delete(sessionId);
93
+ }
94
+ /**
95
+ * Raise a halt signal scoped to `sessionId` (= the run id the hook
96
+ * fired under). The SDK's run loop polls for this between stream
97
+ * events with the run's own id. First-write-wins per session: a
98
+ * halt already raised by an earlier hook in the same run is
99
+ * preserved so the original `reason` / `source` aren't overwritten.
100
+ *
101
+ * Per-session scoping is critical when hosts share one registry
102
+ * across concurrent runs (e.g. a global policy registered once and
103
+ * reused). Without it, a `preventContinuation` from run A would
104
+ * trip run B's stream-loop poll on the next iteration and silently
105
+ * terminate an unrelated run.
106
+ *
107
+ * Called by the SDK after `executeHooks` returns an aggregate with
108
+ * `preventContinuation: true`. Hosts can also call it directly from
109
+ * inside a hook callback if they want to halt without going through
110
+ * the aggregated return value, but `preventContinuation` is the
111
+ * canonical path.
112
+ */
113
+ haltRun(sessionId, reason, source) {
114
+ if (this.haltSignals.has(sessionId)) return;
115
+ this.haltSignals.set(sessionId, {
116
+ reason,
117
+ source
118
+ });
119
+ }
120
+ /**
121
+ * Returns the halt signal raised by hooks running under `sessionId`,
122
+ * or `undefined` if no hook in that run has halted. Polled by
123
+ * `Run.processStream` between stream events using the run's own id.
124
+ */
125
+ getHaltSignal(sessionId) {
126
+ return this.haltSignals.get(sessionId);
127
+ }
128
+ /**
129
+ * Clears the halt signal for `sessionId`. Called by
130
+ * `Run.processStream` in its `finally` block so a subsequent
131
+ * invocation of the same Run (e.g. resume) starts with a fresh
132
+ * halt state. No-op when no signal exists for that session.
133
+ */
134
+ clearHaltSignal(sessionId) {
135
+ this.haltSignals.delete(sessionId);
136
+ }
137
+ /** True if at least one matcher exists for `event` (global + session). */
138
+ hasHookFor(event, sessionId) {
139
+ if (readList(this.global, event).length > 0) return true;
140
+ if (sessionId === void 0) return false;
141
+ const bucket = this.sessions.get(sessionId);
142
+ if (bucket === void 0) return false;
143
+ return readList(bucket, event).length > 0;
144
+ }
145
+ ensureSessionBucket(sessionId) {
146
+ const existing = this.sessions.get(sessionId);
147
+ if (existing !== void 0) return existing;
148
+ const fresh = {};
149
+ this.sessions.set(sessionId, fresh);
150
+ return fresh;
151
+ }
152
+ };
176
153
  function ensureList(bucket, event) {
177
- const existing = bucket[event];
178
- if (existing !== undefined) {
179
- return existing;
180
- }
181
- const fresh = [];
182
- bucket[event] = fresh;
183
- return fresh;
154
+ const existing = bucket[event];
155
+ if (existing !== void 0) return existing;
156
+ const fresh = [];
157
+ bucket[event] = fresh;
158
+ return fresh;
184
159
  }
185
160
  function readList(bucket, event) {
186
- return bucket[event] ?? [];
161
+ return bucket[event] ?? [];
187
162
  }
188
163
  function removeFromList(list, matcher) {
189
- const idx = list.indexOf(widen(matcher));
190
- if (idx < 0) {
191
- return false;
192
- }
193
- list.splice(idx, 1);
194
- return true;
164
+ const idx = list.indexOf(widen(matcher));
165
+ if (idx < 0) return false;
166
+ list.splice(idx, 1);
167
+ return true;
195
168
  }
196
169
  /**
197
- * Widen a per-event matcher to the storage's uniform slot type. Unsound at
198
- * the type level (function parameters are contravariant) but safe by
199
- * construction: `HookRegistry.register<E>` only ever puts matchers into the
200
- * bucket slot for their own event, and reads go through `snapshot<E>`
201
- * which is only called with the same `E`.
202
- */
170
+ * Widen a per-event matcher to the storage's uniform slot type. Unsound at
171
+ * the type level (function parameters are contravariant) but safe by
172
+ * construction: `HookRegistry.register<E>` only ever puts matchers into the
173
+ * bucket slot for their own event, and reads go through `snapshot<E>`
174
+ * which is only called with the same `E`.
175
+ */
203
176
  function widen(matcher) {
204
- return matcher;
177
+ return matcher;
205
178
  }
206
179
  /**
207
- * Narrow a storage list back to a per-event matcher list on the way out.
208
- * Sound counterpart to `widen`: the list only contains matchers that were
209
- * registered against `E`, because the public API enforces it on insert.
210
- */
180
+ * Narrow a storage list back to a per-event matcher list on the way out.
181
+ * Sound counterpart to `widen`: the list only contains matchers that were
182
+ * registered against `E`, because the public API enforces it on insert.
183
+ */
211
184
  function snapshot(list) {
212
- return list.slice();
185
+ return list.slice();
213
186
  }
214
-
187
+ //#endregion
215
188
  exports.HookRegistry = HookRegistry;
216
- //# sourceMappingURL=HookRegistry.cjs.map
189
+
190
+ //# sourceMappingURL=HookRegistry.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"HookRegistry.cjs","sources":["../../../src/hooks/HookRegistry.ts"],"sourcesContent":["// src/hooks/HookRegistry.ts\nimport type { HookEvent, HookMatcher } from './types';\n\n/**\n * Internal matcher storage type.\n *\n * Matchers registered via the public `register<E>` API are strictly typed\n * to a single `E`, but the storage needs one uniform slot type per event.\n * We store them as `HookMatcher<HookEvent>` and cast once at the variance\n * boundary — see `ensureList` and `snapshot` below. The invariant (every\n * matcher in `bucket[event]` was registered with that exact event) is\n * enforced by the public API; breaking it requires bypassing the types.\n */\ntype MatcherBucket = Partial<Record<HookEvent, HookMatcher<HookEvent>[]>>;\n\n/**\n * Snapshot of a halt request raised by a hook returning\n * `preventContinuation: true`. The SDK's run loop polls for this between\n * stream events and exits cleanly when set, skipping the `Stop` hook\n * (the run is being halted, not naturally completing). One per registry\n * instance — the first hook to halt wins; subsequent halts are ignored\n * so the original reason isn't clobbered.\n */\nexport interface HookHaltSignal {\n reason: string;\n /** Event of the hook that triggered the halt (for diagnostics). */\n source: HookEvent;\n}\n\n/**\n * Run-scoped storage for hook matchers with an additional layer for\n * session-scoped matchers that should be cleaned up between sessions.\n *\n * Hosts construct one registry per `Run` (mirroring how `HandlerRegistry` is\n * scoped) and register global matchers + per-session matchers against it.\n * Registration is strictly additive — nothing in this class mutates a\n * matcher's callbacks or flags after insertion.\n *\n * ## Why `Map<sessionId, MatcherBucket>` and not `Record`\n *\n * LibreChat runs thousands of parallel sessions in one Node process, and\n * hook registration happens inside hot paths (tool loading, agent spawning).\n * A `Record<sessionId, ...>` has to be spread on every insertion, which is\n * O(n) per call and O(n²) total for a batch of parallel registrations. A\n * Map mutates in place, keeping insertions O(1). This mirrors the reasoning\n * Claude Code documents at `utils/hooks/sessionHooks.ts:62`.\n */\nexport class HookRegistry {\n private readonly global: MatcherBucket = {};\n private readonly sessions: Map<string, MatcherBucket> = new Map();\n /**\n * Per-session halt signals. Scoped by `sessionId` (= the run id the\n * hook fired under) so a host that shares one registry across\n * concurrent runs cannot leak `preventContinuation` from one run\n * into another. Without scoping, a halt raised by run A's hook\n * would trip run B's stream-loop poll on the next iteration —\n * silently terminating an unrelated run.\n *\n * Map storage mirrors the reasoning above for session matchers:\n * O(1) insertion in hot paths, no spread-on-write.\n */\n private readonly haltSignals: Map<string, HookHaltSignal> = new Map();\n\n /**\n * Register a matcher for the lifetime of this registry (= one Run).\n * Returns an unregister function that removes the matcher by reference.\n */\n register<E extends HookEvent>(event: E, matcher: HookMatcher<E>): () => void {\n const list = ensureList(this.global, event);\n list.push(widen(matcher));\n return () => {\n removeFromList(list, matcher);\n };\n }\n\n /**\n * Register a matcher for a specific session. Cleared automatically when\n * `clearSession(sessionId)` is called, or can be removed directly via the\n * returned unregister function.\n */\n registerSession<E extends HookEvent>(\n sessionId: string,\n event: E,\n matcher: HookMatcher<E>\n ): () => void {\n const bucket = this.ensureSessionBucket(sessionId);\n const list = ensureList(bucket, event);\n list.push(widen(matcher));\n return () => {\n removeFromList(list, matcher);\n };\n }\n\n /**\n * Returns all matchers registered for `event`, concatenating global first\n * and then session-specific (when `sessionId` is supplied). The caller\n * receives a fresh array, so iterating it is safe even if a matcher is\n * removed mid-iteration (e.g. via `once: true`).\n */\n getMatchers<E extends HookEvent>(\n event: E,\n sessionId?: string\n ): HookMatcher<E>[] {\n const globalList = readList(this.global, event);\n if (sessionId === undefined) {\n return snapshot<E>(globalList);\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return snapshot<E>(globalList);\n }\n const sessionList = readList(bucket, event);\n if (globalList.length === 0) {\n return snapshot<E>(sessionList);\n }\n if (sessionList.length === 0) {\n return snapshot<E>(globalList);\n }\n return snapshot<E>([...globalList, ...sessionList]);\n }\n\n /**\n * Removes `matcher` by reference from global storage first, falling back\n * to the session bucket when `sessionId` is supplied. Used by\n * `executeHooks` to drop `once: true` matchers after they fire.\n */\n removeMatcher<E extends HookEvent>(\n event: E,\n matcher: HookMatcher<E>,\n sessionId?: string\n ): boolean {\n if (removeFromList(readList(this.global, event), matcher)) {\n return true;\n }\n if (sessionId === undefined) {\n return false;\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return false;\n }\n return removeFromList(readList(bucket, event), matcher);\n }\n\n /**\n * Drops every session-scoped matcher for `sessionId`. Call this in the\n * `finally` block around a Run so a `once: true` hook that never fired\n * cannot leak into the next session on the same registry.\n */\n clearSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n /**\n * Raise a halt signal scoped to `sessionId` (= the run id the hook\n * fired under). The SDK's run loop polls for this between stream\n * events with the run's own id. First-write-wins per session: a\n * halt already raised by an earlier hook in the same run is\n * preserved so the original `reason` / `source` aren't overwritten.\n *\n * Per-session scoping is critical when hosts share one registry\n * across concurrent runs (e.g. a global policy registered once and\n * reused). Without it, a `preventContinuation` from run A would\n * trip run B's stream-loop poll on the next iteration and silently\n * terminate an unrelated run.\n *\n * Called by the SDK after `executeHooks` returns an aggregate with\n * `preventContinuation: true`. Hosts can also call it directly from\n * inside a hook callback if they want to halt without going through\n * the aggregated return value, but `preventContinuation` is the\n * canonical path.\n */\n haltRun(sessionId: string, reason: string, source: HookEvent): void {\n if (this.haltSignals.has(sessionId)) {\n return;\n }\n this.haltSignals.set(sessionId, { reason, source });\n }\n\n /**\n * Returns the halt signal raised by hooks running under `sessionId`,\n * or `undefined` if no hook in that run has halted. Polled by\n * `Run.processStream` between stream events using the run's own id.\n */\n getHaltSignal(sessionId: string): HookHaltSignal | undefined {\n return this.haltSignals.get(sessionId);\n }\n\n /**\n * Clears the halt signal for `sessionId`. Called by\n * `Run.processStream` in its `finally` block so a subsequent\n * invocation of the same Run (e.g. resume) starts with a fresh\n * halt state. No-op when no signal exists for that session.\n */\n clearHaltSignal(sessionId: string): void {\n this.haltSignals.delete(sessionId);\n }\n\n /** True if at least one matcher exists for `event` (global + session). */\n hasHookFor(event: HookEvent, sessionId?: string): boolean {\n if (readList(this.global, event).length > 0) {\n return true;\n }\n if (sessionId === undefined) {\n return false;\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return false;\n }\n return readList(bucket, event).length > 0;\n }\n\n private ensureSessionBucket(sessionId: string): MatcherBucket {\n const existing = this.sessions.get(sessionId);\n if (existing !== undefined) {\n return existing;\n }\n const fresh: MatcherBucket = {};\n this.sessions.set(sessionId, fresh);\n return fresh;\n }\n}\n\nfunction ensureList(\n bucket: MatcherBucket,\n event: HookEvent\n): HookMatcher<HookEvent>[] {\n const existing = bucket[event];\n if (existing !== undefined) {\n return existing;\n }\n const fresh: HookMatcher<HookEvent>[] = [];\n bucket[event] = fresh;\n return fresh;\n}\n\nfunction readList(\n bucket: MatcherBucket,\n event: HookEvent\n): HookMatcher<HookEvent>[] {\n return bucket[event] ?? [];\n}\n\nfunction removeFromList<E extends HookEvent>(\n list: HookMatcher<HookEvent>[],\n matcher: HookMatcher<E>\n): boolean {\n const idx = list.indexOf(widen(matcher));\n if (idx < 0) {\n return false;\n }\n list.splice(idx, 1);\n return true;\n}\n\n/**\n * Widen a per-event matcher to the storage's uniform slot type. Unsound at\n * the type level (function parameters are contravariant) but safe by\n * construction: `HookRegistry.register<E>` only ever puts matchers into the\n * bucket slot for their own event, and reads go through `snapshot<E>`\n * which is only called with the same `E`.\n */\nfunction widen<E extends HookEvent>(\n matcher: HookMatcher<E>\n): HookMatcher<HookEvent> {\n return matcher as unknown as HookMatcher<HookEvent>;\n}\n\n/**\n * Narrow a storage list back to a per-event matcher list on the way out.\n * Sound counterpart to `widen`: the list only contains matchers that were\n * registered against `E`, because the public API enforces it on insert.\n */\nfunction snapshot<E extends HookEvent>(\n list: readonly HookMatcher<HookEvent>[]\n): HookMatcher<E>[] {\n return list.slice() as unknown as HookMatcher<E>[];\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HookRegistry.cjs","names":[],"sources":["../../../src/hooks/HookRegistry.ts"],"sourcesContent":["// src/hooks/HookRegistry.ts\nimport type { HookEvent, HookMatcher } from './types';\n\n/**\n * Internal matcher storage type.\n *\n * Matchers registered via the public `register<E>` API are strictly typed\n * to a single `E`, but the storage needs one uniform slot type per event.\n * We store them as `HookMatcher<HookEvent>` and cast once at the variance\n * boundary — see `ensureList` and `snapshot` below. The invariant (every\n * matcher in `bucket[event]` was registered with that exact event) is\n * enforced by the public API; breaking it requires bypassing the types.\n */\ntype MatcherBucket = Partial<Record<HookEvent, HookMatcher<HookEvent>[]>>;\n\n/**\n * Snapshot of a halt request raised by a hook returning\n * `preventContinuation: true`. The SDK's run loop polls for this between\n * stream events and exits cleanly when set, skipping the `Stop` hook\n * (the run is being halted, not naturally completing). One per registry\n * instance — the first hook to halt wins; subsequent halts are ignored\n * so the original reason isn't clobbered.\n */\nexport interface HookHaltSignal {\n reason: string;\n /** Event of the hook that triggered the halt (for diagnostics). */\n source: HookEvent;\n}\n\n/**\n * Run-scoped storage for hook matchers with an additional layer for\n * session-scoped matchers that should be cleaned up between sessions.\n *\n * Hosts construct one registry per `Run` (mirroring how `HandlerRegistry` is\n * scoped) and register global matchers + per-session matchers against it.\n * Registration is strictly additive — nothing in this class mutates a\n * matcher's callbacks or flags after insertion.\n *\n * ## Why `Map<sessionId, MatcherBucket>` and not `Record`\n *\n * LibreChat runs thousands of parallel sessions in one Node process, and\n * hook registration happens inside hot paths (tool loading, agent spawning).\n * A `Record<sessionId, ...>` has to be spread on every insertion, which is\n * O(n) per call and O(n²) total for a batch of parallel registrations. A\n * Map mutates in place, keeping insertions O(1). This mirrors the reasoning\n * Claude Code documents at `utils/hooks/sessionHooks.ts:62`.\n */\nexport class HookRegistry {\n private readonly global: MatcherBucket = {};\n private readonly sessions: Map<string, MatcherBucket> = new Map();\n /**\n * Per-session halt signals. Scoped by `sessionId` (= the run id the\n * hook fired under) so a host that shares one registry across\n * concurrent runs cannot leak `preventContinuation` from one run\n * into another. Without scoping, a halt raised by run A's hook\n * would trip run B's stream-loop poll on the next iteration —\n * silently terminating an unrelated run.\n *\n * Map storage mirrors the reasoning above for session matchers:\n * O(1) insertion in hot paths, no spread-on-write.\n */\n private readonly haltSignals: Map<string, HookHaltSignal> = new Map();\n\n /**\n * Register a matcher for the lifetime of this registry (= one Run).\n * Returns an unregister function that removes the matcher by reference.\n */\n register<E extends HookEvent>(event: E, matcher: HookMatcher<E>): () => void {\n const list = ensureList(this.global, event);\n list.push(widen(matcher));\n return () => {\n removeFromList(list, matcher);\n };\n }\n\n /**\n * Register a matcher for a specific session. Cleared automatically when\n * `clearSession(sessionId)` is called, or can be removed directly via the\n * returned unregister function.\n */\n registerSession<E extends HookEvent>(\n sessionId: string,\n event: E,\n matcher: HookMatcher<E>\n ): () => void {\n const bucket = this.ensureSessionBucket(sessionId);\n const list = ensureList(bucket, event);\n list.push(widen(matcher));\n return () => {\n removeFromList(list, matcher);\n };\n }\n\n /**\n * Returns all matchers registered for `event`, concatenating global first\n * and then session-specific (when `sessionId` is supplied). The caller\n * receives a fresh array, so iterating it is safe even if a matcher is\n * removed mid-iteration (e.g. via `once: true`).\n */\n getMatchers<E extends HookEvent>(\n event: E,\n sessionId?: string\n ): HookMatcher<E>[] {\n const globalList = readList(this.global, event);\n if (sessionId === undefined) {\n return snapshot<E>(globalList);\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return snapshot<E>(globalList);\n }\n const sessionList = readList(bucket, event);\n if (globalList.length === 0) {\n return snapshot<E>(sessionList);\n }\n if (sessionList.length === 0) {\n return snapshot<E>(globalList);\n }\n return snapshot<E>([...globalList, ...sessionList]);\n }\n\n /**\n * Removes `matcher` by reference from global storage first, falling back\n * to the session bucket when `sessionId` is supplied. Used by\n * `executeHooks` to drop `once: true` matchers after they fire.\n */\n removeMatcher<E extends HookEvent>(\n event: E,\n matcher: HookMatcher<E>,\n sessionId?: string\n ): boolean {\n if (removeFromList(readList(this.global, event), matcher)) {\n return true;\n }\n if (sessionId === undefined) {\n return false;\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return false;\n }\n return removeFromList(readList(bucket, event), matcher);\n }\n\n /**\n * Drops every session-scoped matcher for `sessionId`. Call this in the\n * `finally` block around a Run so a `once: true` hook that never fired\n * cannot leak into the next session on the same registry.\n */\n clearSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n /**\n * Raise a halt signal scoped to `sessionId` (= the run id the hook\n * fired under). The SDK's run loop polls for this between stream\n * events with the run's own id. First-write-wins per session: a\n * halt already raised by an earlier hook in the same run is\n * preserved so the original `reason` / `source` aren't overwritten.\n *\n * Per-session scoping is critical when hosts share one registry\n * across concurrent runs (e.g. a global policy registered once and\n * reused). Without it, a `preventContinuation` from run A would\n * trip run B's stream-loop poll on the next iteration and silently\n * terminate an unrelated run.\n *\n * Called by the SDK after `executeHooks` returns an aggregate with\n * `preventContinuation: true`. Hosts can also call it directly from\n * inside a hook callback if they want to halt without going through\n * the aggregated return value, but `preventContinuation` is the\n * canonical path.\n */\n haltRun(sessionId: string, reason: string, source: HookEvent): void {\n if (this.haltSignals.has(sessionId)) {\n return;\n }\n this.haltSignals.set(sessionId, { reason, source });\n }\n\n /**\n * Returns the halt signal raised by hooks running under `sessionId`,\n * or `undefined` if no hook in that run has halted. Polled by\n * `Run.processStream` between stream events using the run's own id.\n */\n getHaltSignal(sessionId: string): HookHaltSignal | undefined {\n return this.haltSignals.get(sessionId);\n }\n\n /**\n * Clears the halt signal for `sessionId`. Called by\n * `Run.processStream` in its `finally` block so a subsequent\n * invocation of the same Run (e.g. resume) starts with a fresh\n * halt state. No-op when no signal exists for that session.\n */\n clearHaltSignal(sessionId: string): void {\n this.haltSignals.delete(sessionId);\n }\n\n /** True if at least one matcher exists for `event` (global + session). */\n hasHookFor(event: HookEvent, sessionId?: string): boolean {\n if (readList(this.global, event).length > 0) {\n return true;\n }\n if (sessionId === undefined) {\n return false;\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return false;\n }\n return readList(bucket, event).length > 0;\n }\n\n private ensureSessionBucket(sessionId: string): MatcherBucket {\n const existing = this.sessions.get(sessionId);\n if (existing !== undefined) {\n return existing;\n }\n const fresh: MatcherBucket = {};\n this.sessions.set(sessionId, fresh);\n return fresh;\n }\n}\n\nfunction ensureList(\n bucket: MatcherBucket,\n event: HookEvent\n): HookMatcher<HookEvent>[] {\n const existing = bucket[event];\n if (existing !== undefined) {\n return existing;\n }\n const fresh: HookMatcher<HookEvent>[] = [];\n bucket[event] = fresh;\n return fresh;\n}\n\nfunction readList(\n bucket: MatcherBucket,\n event: HookEvent\n): HookMatcher<HookEvent>[] {\n return bucket[event] ?? [];\n}\n\nfunction removeFromList<E extends HookEvent>(\n list: HookMatcher<HookEvent>[],\n matcher: HookMatcher<E>\n): boolean {\n const idx = list.indexOf(widen(matcher));\n if (idx < 0) {\n return false;\n }\n list.splice(idx, 1);\n return true;\n}\n\n/**\n * Widen a per-event matcher to the storage's uniform slot type. Unsound at\n * the type level (function parameters are contravariant) but safe by\n * construction: `HookRegistry.register<E>` only ever puts matchers into the\n * bucket slot for their own event, and reads go through `snapshot<E>`\n * which is only called with the same `E`.\n */\nfunction widen<E extends HookEvent>(\n matcher: HookMatcher<E>\n): HookMatcher<HookEvent> {\n return matcher as unknown as HookMatcher<HookEvent>;\n}\n\n/**\n * Narrow a storage list back to a per-event matcher list on the way out.\n * Sound counterpart to `widen`: the list only contains matchers that were\n * registered against `E`, because the public API enforces it on insert.\n */\nfunction snapshot<E extends HookEvent>(\n list: readonly HookMatcher<HookEvent>[]\n): HookMatcher<E>[] {\n return list.slice() as unknown as HookMatcher<E>[];\n}\n"],"mappings":"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"}