@librechat/agents 3.2.32 → 3.2.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (573) hide show
  1. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  2. package/dist/cjs/agents/AgentContext.cjs +844 -1046
  3. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  4. package/dist/cjs/common/constants.cjs +13 -13
  5. package/dist/cjs/common/constants.cjs.map +1 -1
  6. package/dist/cjs/common/enum.cjs +233 -240
  7. package/dist/cjs/common/enum.cjs.map +1 -1
  8. package/dist/cjs/common/index.cjs +2 -0
  9. package/dist/cjs/events.cjs +121 -169
  10. package/dist/cjs/events.cjs.map +1 -1
  11. package/dist/cjs/graphs/Graph.cjs +1389 -1807
  12. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  13. package/dist/cjs/graphs/MultiAgentGraph.cjs +713 -945
  14. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  15. package/dist/cjs/graphs/index.cjs +2 -0
  16. package/dist/cjs/hitl/askUserQuestion.cjs +60 -62
  17. package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -1
  18. package/dist/cjs/hitl/index.cjs +1 -0
  19. package/dist/cjs/hooks/HookRegistry.cjs +176 -202
  20. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  21. package/dist/cjs/hooks/createToolPolicyHook.cjs +71 -101
  22. package/dist/cjs/hooks/createToolPolicyHook.cjs.map +1 -1
  23. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +170 -273
  24. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -1
  25. package/dist/cjs/hooks/executeHooks.cjs +227 -282
  26. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  27. package/dist/cjs/hooks/index.cjs +6 -0
  28. package/dist/cjs/hooks/matchers.cjs +196 -230
  29. package/dist/cjs/hooks/matchers.cjs.map +1 -1
  30. package/dist/cjs/hooks/types.cjs +24 -24
  31. package/dist/cjs/hooks/types.cjs.map +1 -1
  32. package/dist/cjs/instrumentation.cjs +110 -137
  33. package/dist/cjs/instrumentation.cjs.map +1 -1
  34. package/dist/cjs/langchain/google-common.cjs +0 -3
  35. package/dist/cjs/langchain/index.cjs +80 -43
  36. package/dist/cjs/langchain/language_models/chat_models.cjs +0 -3
  37. package/dist/cjs/langchain/messages/tool.cjs +0 -3
  38. package/dist/cjs/langchain/messages.cjs +35 -18
  39. package/dist/cjs/langchain/openai.cjs +0 -3
  40. package/dist/cjs/langchain/prompts.cjs +5 -8
  41. package/dist/cjs/langchain/runnables.cjs +11 -10
  42. package/dist/cjs/langchain/tools.cjs +14 -11
  43. package/dist/cjs/langchain/utils/env.cjs +5 -8
  44. package/dist/cjs/langfuse.cjs +60 -79
  45. package/dist/cjs/langfuse.cjs.map +1 -1
  46. package/dist/cjs/langfuseToolOutputTracing.cjs +267 -399
  47. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  48. package/dist/cjs/llm/anthropic/index.cjs +432 -562
  49. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  50. package/dist/cjs/llm/anthropic/types.cjs +23 -47
  51. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  52. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +441 -731
  53. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  54. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +171 -256
  55. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  56. package/dist/cjs/llm/anthropic/utils/output_parsers.cjs +2 -0
  57. package/dist/cjs/llm/anthropic/utils/tools.cjs +12 -26
  58. package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -1
  59. package/dist/cjs/llm/bedrock/index.cjs +195 -240
  60. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  61. package/dist/cjs/llm/bedrock/toolCache.cjs +84 -106
  62. package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
  63. package/dist/cjs/llm/bedrock/utils/index.cjs +2 -0
  64. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +357 -620
  65. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  66. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +105 -149
  67. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  68. package/dist/cjs/llm/fake.cjs +86 -96
  69. package/dist/cjs/llm/fake.cjs.map +1 -1
  70. package/dist/cjs/llm/google/index.cjs +183 -237
  71. package/dist/cjs/llm/google/index.cjs.map +1 -1
  72. package/dist/cjs/llm/google/utils/common.cjs +398 -674
  73. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  74. package/dist/cjs/llm/google/utils/zod_to_genai_parameters.cjs +2 -0
  75. package/dist/cjs/llm/init.cjs +44 -53
  76. package/dist/cjs/llm/init.cjs.map +1 -1
  77. package/dist/cjs/llm/invoke.cjs +142 -182
  78. package/dist/cjs/llm/invoke.cjs.map +1 -1
  79. package/dist/cjs/llm/openai/index.cjs +991 -1276
  80. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  81. package/dist/cjs/llm/openai/utils/index.cjs +189 -316
  82. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  83. package/dist/cjs/llm/openrouter/index.cjs +102 -153
  84. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  85. package/dist/cjs/llm/openrouter/toolCache.cjs +35 -44
  86. package/dist/cjs/llm/openrouter/toolCache.cjs.map +1 -1
  87. package/dist/cjs/llm/providers.cjs +29 -37
  88. package/dist/cjs/llm/providers.cjs.map +1 -1
  89. package/dist/cjs/llm/request.cjs +20 -33
  90. package/dist/cjs/llm/request.cjs.map +1 -1
  91. package/dist/cjs/llm/vertexai/index.cjs +427 -453
  92. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  93. package/dist/cjs/main.cjs +547 -528
  94. package/dist/cjs/messages/anthropicToolCache.cjs +68 -119
  95. package/dist/cjs/messages/anthropicToolCache.cjs.map +1 -1
  96. package/dist/cjs/messages/cache.cjs +305 -418
  97. package/dist/cjs/messages/cache.cjs.map +1 -1
  98. package/dist/cjs/messages/content.cjs +36 -49
  99. package/dist/cjs/messages/content.cjs.map +1 -1
  100. package/dist/cjs/messages/contextPruning.cjs +112 -145
  101. package/dist/cjs/messages/contextPruning.cjs.map +1 -1
  102. package/dist/cjs/messages/contextPruningSettings.cjs +36 -46
  103. package/dist/cjs/messages/contextPruningSettings.cjs.map +1 -1
  104. package/dist/cjs/messages/core.cjs +256 -397
  105. package/dist/cjs/messages/core.cjs.map +1 -1
  106. package/dist/cjs/messages/format.cjs +904 -1387
  107. package/dist/cjs/messages/format.cjs.map +1 -1
  108. package/dist/cjs/messages/ids.cjs +16 -20
  109. package/dist/cjs/messages/ids.cjs.map +1 -1
  110. package/dist/cjs/messages/index.cjs +12 -0
  111. package/dist/cjs/messages/langchain.cjs +18 -18
  112. package/dist/cjs/messages/langchain.cjs.map +1 -1
  113. package/dist/cjs/messages/prune.cjs +1054 -1517
  114. package/dist/cjs/messages/prune.cjs.map +1 -1
  115. package/dist/cjs/messages/recency.cjs +77 -95
  116. package/dist/cjs/messages/recency.cjs.map +1 -1
  117. package/dist/cjs/messages/reducer.cjs +63 -78
  118. package/dist/cjs/messages/reducer.cjs.map +1 -1
  119. package/dist/cjs/messages/tools.cjs +51 -79
  120. package/dist/cjs/messages/tools.cjs.map +1 -1
  121. package/dist/cjs/openai/index.cjs +171 -217
  122. package/dist/cjs/openai/index.cjs.map +1 -1
  123. package/dist/cjs/responses/index.cjs +302 -391
  124. package/dist/cjs/responses/index.cjs.map +1 -1
  125. package/dist/cjs/run.cjs +903 -1113
  126. package/dist/cjs/run.cjs.map +1 -1
  127. package/dist/cjs/session/AgentSession.cjs +805 -986
  128. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  129. package/dist/cjs/session/JsonlSessionStore.cjs +327 -410
  130. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  131. package/dist/cjs/session/handlers.cjs +192 -208
  132. package/dist/cjs/session/handlers.cjs.map +1 -1
  133. package/dist/cjs/session/ids.cjs +9 -10
  134. package/dist/cjs/session/ids.cjs.map +1 -1
  135. package/dist/cjs/session/index.cjs +4 -0
  136. package/dist/cjs/session/messageSerialization.cjs +94 -156
  137. package/dist/cjs/session/messageSerialization.cjs.map +1 -1
  138. package/dist/cjs/splitStream.cjs +147 -206
  139. package/dist/cjs/splitStream.cjs.map +1 -1
  140. package/dist/cjs/stream.cjs +856 -1344
  141. package/dist/cjs/stream.cjs.map +1 -1
  142. package/dist/cjs/summarization/index.cjs +57 -101
  143. package/dist/cjs/summarization/index.cjs.map +1 -1
  144. package/dist/cjs/summarization/node.cjs +643 -796
  145. package/dist/cjs/summarization/node.cjs.map +1 -1
  146. package/dist/cjs/tools/BashExecutor.cjs +110 -136
  147. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  148. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +165 -245
  149. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  150. package/dist/cjs/tools/Calculator.cjs +36 -57
  151. package/dist/cjs/tools/Calculator.cjs.map +1 -1
  152. package/dist/cjs/tools/CodeExecutor.cjs +126 -168
  153. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  154. package/dist/cjs/tools/CodeSessionFileSummary.cjs +36 -46
  155. package/dist/cjs/tools/CodeSessionFileSummary.cjs.map +1 -1
  156. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +459 -649
  157. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  158. package/dist/cjs/tools/ReadFile.cjs +17 -20
  159. package/dist/cjs/tools/ReadFile.cjs.map +1 -1
  160. package/dist/cjs/tools/SkillTool.cjs +26 -27
  161. package/dist/cjs/tools/SkillTool.cjs.map +1 -1
  162. package/dist/cjs/tools/SubagentTool.cjs +59 -61
  163. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  164. package/dist/cjs/tools/ToolNode.cjs +2109 -2686
  165. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  166. package/dist/cjs/tools/ToolSearch.cjs +663 -825
  167. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  168. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs +248 -340
  169. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs.map +1 -1
  170. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +170 -197
  171. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -1
  172. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +425 -520
  173. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
  174. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +91 -124
  175. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -1
  176. package/dist/cjs/tools/cloudflare/index.cjs +4 -0
  177. package/dist/cjs/tools/eagerEventExecution.cjs +75 -99
  178. package/dist/cjs/tools/eagerEventExecution.cjs.map +1 -1
  179. package/dist/cjs/tools/handlers.cjs +200 -262
  180. package/dist/cjs/tools/handlers.cjs.map +1 -1
  181. package/dist/cjs/tools/local/CompileCheckTool.cjs +150 -212
  182. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
  183. package/dist/cjs/tools/local/FileCheckpointer.cjs +77 -85
  184. package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -1
  185. package/dist/cjs/tools/local/LocalCodingTools.cjs +763 -1022
  186. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
  187. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +666 -941
  188. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
  189. package/dist/cjs/tools/local/LocalExecutionTools.cjs +49 -92
  190. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
  191. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +286 -354
  192. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  193. package/dist/cjs/tools/local/attachments.cjs +108 -165
  194. package/dist/cjs/tools/local/attachments.cjs.map +1 -1
  195. package/dist/cjs/tools/local/bashAst.cjs +99 -113
  196. package/dist/cjs/tools/local/bashAst.cjs.map +1 -1
  197. package/dist/cjs/tools/local/editStrategies.cjs +126 -169
  198. package/dist/cjs/tools/local/editStrategies.cjs.map +1 -1
  199. package/dist/cjs/tools/local/index.cjs +12 -0
  200. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +136 -218
  201. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
  202. package/dist/cjs/tools/local/syntaxCheck.cjs +142 -161
  203. package/dist/cjs/tools/local/syntaxCheck.cjs.map +1 -1
  204. package/dist/cjs/tools/local/textEncoding.cjs +25 -23
  205. package/dist/cjs/tools/local/textEncoding.cjs.map +1 -1
  206. package/dist/cjs/tools/local/workspaceFS.cjs +38 -46
  207. package/dist/cjs/tools/local/workspaceFS.cjs.map +1 -1
  208. package/dist/cjs/tools/ptcTimeout.cjs +27 -47
  209. package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
  210. package/dist/cjs/tools/schema.cjs +24 -23
  211. package/dist/cjs/tools/schema.cjs.map +1 -1
  212. package/dist/cjs/tools/search/anthropic.cjs +24 -33
  213. package/dist/cjs/tools/search/anthropic.cjs.map +1 -1
  214. package/dist/cjs/tools/search/content.cjs +95 -137
  215. package/dist/cjs/tools/search/content.cjs.map +1 -1
  216. package/dist/cjs/tools/search/firecrawl.cjs +141 -172
  217. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  218. package/dist/cjs/tools/search/format.cjs +128 -196
  219. package/dist/cjs/tools/search/format.cjs.map +1 -1
  220. package/dist/cjs/tools/search/highlights.cjs +165 -232
  221. package/dist/cjs/tools/search/highlights.cjs.map +1 -1
  222. package/dist/cjs/tools/search/index.cjs +2 -0
  223. package/dist/cjs/tools/search/rerankers.cjs +151 -174
  224. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  225. package/dist/cjs/tools/search/schema.cjs +40 -39
  226. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  227. package/dist/cjs/tools/search/search.cjs +428 -530
  228. package/dist/cjs/tools/search/search.cjs.map +1 -1
  229. package/dist/cjs/tools/search/serper-scraper.cjs +106 -127
  230. package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
  231. package/dist/cjs/tools/search/tavily-scraper.cjs +129 -181
  232. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -1
  233. package/dist/cjs/tools/search/tavily-search.cjs +295 -359
  234. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
  235. package/dist/cjs/tools/search/tool.cjs +260 -299
  236. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  237. package/dist/cjs/tools/search/utils.cjs +74 -117
  238. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  239. package/dist/cjs/tools/skillCatalog.cjs +54 -72
  240. package/dist/cjs/tools/skillCatalog.cjs.map +1 -1
  241. package/dist/cjs/tools/streamedToolCallSeals.cjs +19 -36
  242. package/dist/cjs/tools/streamedToolCallSeals.cjs.map +1 -1
  243. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +612 -771
  244. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  245. package/dist/cjs/tools/subagent/index.cjs +1 -0
  246. package/dist/cjs/tools/toolOutputReferences.cjs +523 -630
  247. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  248. package/dist/cjs/utils/callbacks.cjs +11 -21
  249. package/dist/cjs/utils/callbacks.cjs.map +1 -1
  250. package/dist/cjs/utils/errors.cjs +70 -95
  251. package/dist/cjs/utils/errors.cjs.map +1 -1
  252. package/dist/cjs/utils/events.cjs +32 -42
  253. package/dist/cjs/utils/events.cjs.map +1 -1
  254. package/dist/cjs/utils/graph.cjs +8 -12
  255. package/dist/cjs/utils/graph.cjs.map +1 -1
  256. package/dist/cjs/utils/handlers.cjs +60 -82
  257. package/dist/cjs/utils/handlers.cjs.map +1 -1
  258. package/dist/cjs/utils/index.cjs +9 -0
  259. package/dist/cjs/utils/llm.cjs +19 -27
  260. package/dist/cjs/utils/llm.cjs.map +1 -1
  261. package/dist/cjs/utils/misc.cjs +30 -46
  262. package/dist/cjs/utils/misc.cjs.map +1 -1
  263. package/dist/cjs/utils/run.cjs +50 -66
  264. package/dist/cjs/utils/run.cjs.map +1 -1
  265. package/dist/cjs/utils/schema.cjs +11 -19
  266. package/dist/cjs/utils/schema.cjs.map +1 -1
  267. package/dist/cjs/utils/title.cjs +71 -106
  268. package/dist/cjs/utils/title.cjs.map +1 -1
  269. package/dist/cjs/utils/tokens.cjs +186 -283
  270. package/dist/cjs/utils/tokens.cjs.map +1 -1
  271. package/dist/cjs/utils/truncation.cjs +95 -114
  272. package/dist/cjs/utils/truncation.cjs.map +1 -1
  273. package/dist/esm/agents/AgentContext.mjs +844 -1044
  274. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  275. package/dist/esm/common/constants.mjs +13 -11
  276. package/dist/esm/common/constants.mjs.map +1 -1
  277. package/dist/esm/common/enum.mjs +221 -238
  278. package/dist/esm/common/enum.mjs.map +1 -1
  279. package/dist/esm/common/index.mjs +3 -0
  280. package/dist/esm/events.mjs +121 -167
  281. package/dist/esm/events.mjs.map +1 -1
  282. package/dist/esm/graphs/Graph.mjs +1388 -1804
  283. package/dist/esm/graphs/Graph.mjs.map +1 -1
  284. package/dist/esm/graphs/MultiAgentGraph.mjs +713 -943
  285. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  286. package/dist/esm/graphs/index.mjs +3 -0
  287. package/dist/esm/hitl/askUserQuestion.mjs +60 -60
  288. package/dist/esm/hitl/askUserQuestion.mjs.map +1 -1
  289. package/dist/esm/hitl/index.mjs +2 -0
  290. package/dist/esm/hooks/HookRegistry.mjs +176 -200
  291. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  292. package/dist/esm/hooks/createToolPolicyHook.mjs +71 -99
  293. package/dist/esm/hooks/createToolPolicyHook.mjs.map +1 -1
  294. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +170 -271
  295. package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -1
  296. package/dist/esm/hooks/executeHooks.mjs +227 -280
  297. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  298. package/dist/esm/hooks/index.mjs +7 -0
  299. package/dist/esm/hooks/matchers.mjs +196 -228
  300. package/dist/esm/hooks/matchers.mjs.map +1 -1
  301. package/dist/esm/hooks/types.mjs +24 -22
  302. package/dist/esm/hooks/types.mjs.map +1 -1
  303. package/dist/esm/instrumentation.mjs +109 -132
  304. package/dist/esm/instrumentation.mjs.map +1 -1
  305. package/dist/esm/langchain/google-common.mjs +1 -2
  306. package/dist/esm/langchain/index.mjs +5 -5
  307. package/dist/esm/langchain/language_models/chat_models.mjs +1 -2
  308. package/dist/esm/langchain/messages/tool.mjs +1 -2
  309. package/dist/esm/langchain/messages.mjs +2 -2
  310. package/dist/esm/langchain/openai.mjs +1 -2
  311. package/dist/esm/langchain/prompts.mjs +2 -2
  312. package/dist/esm/langchain/runnables.mjs +2 -2
  313. package/dist/esm/langchain/tools.mjs +2 -2
  314. package/dist/esm/langchain/utils/env.mjs +2 -2
  315. package/dist/esm/langfuse.mjs +60 -76
  316. package/dist/esm/langfuse.mjs.map +1 -1
  317. package/dist/esm/langfuseToolOutputTracing.mjs +267 -395
  318. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  319. package/dist/esm/llm/anthropic/index.mjs +432 -559
  320. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  321. package/dist/esm/llm/anthropic/types.mjs +23 -45
  322. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  323. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +439 -725
  324. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  325. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +171 -253
  326. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  327. package/dist/esm/llm/anthropic/utils/output_parsers.mjs +3 -0
  328. package/dist/esm/llm/anthropic/utils/tools.mjs +12 -24
  329. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -1
  330. package/dist/esm/llm/bedrock/index.mjs +195 -238
  331. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  332. package/dist/esm/llm/bedrock/toolCache.mjs +84 -104
  333. package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
  334. package/dist/esm/llm/bedrock/utils/index.mjs +3 -0
  335. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +357 -618
  336. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  337. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +105 -147
  338. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  339. package/dist/esm/llm/fake.mjs +86 -94
  340. package/dist/esm/llm/fake.mjs.map +1 -1
  341. package/dist/esm/llm/google/index.mjs +183 -235
  342. package/dist/esm/llm/google/index.mjs.map +1 -1
  343. package/dist/esm/llm/google/utils/common.mjs +397 -666
  344. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  345. package/dist/esm/llm/google/utils/zod_to_genai_parameters.mjs +3 -0
  346. package/dist/esm/llm/init.mjs +44 -51
  347. package/dist/esm/llm/init.mjs.map +1 -1
  348. package/dist/esm/llm/invoke.mjs +142 -180
  349. package/dist/esm/llm/invoke.mjs.map +1 -1
  350. package/dist/esm/llm/openai/index.mjs +991 -1271
  351. package/dist/esm/llm/openai/index.mjs.map +1 -1
  352. package/dist/esm/llm/openai/utils/index.mjs +188 -312
  353. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  354. package/dist/esm/llm/openrouter/index.mjs +102 -151
  355. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  356. package/dist/esm/llm/openrouter/toolCache.mjs +35 -42
  357. package/dist/esm/llm/openrouter/toolCache.mjs.map +1 -1
  358. package/dist/esm/llm/providers.mjs +29 -34
  359. package/dist/esm/llm/providers.mjs.map +1 -1
  360. package/dist/esm/llm/request.mjs +20 -31
  361. package/dist/esm/llm/request.mjs.map +1 -1
  362. package/dist/esm/llm/vertexai/index.mjs +427 -449
  363. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  364. package/dist/esm/main.mjs +99 -87
  365. package/dist/esm/messages/anthropicToolCache.mjs +68 -117
  366. package/dist/esm/messages/anthropicToolCache.mjs.map +1 -1
  367. package/dist/esm/messages/cache.mjs +305 -416
  368. package/dist/esm/messages/cache.mjs.map +1 -1
  369. package/dist/esm/messages/content.mjs +36 -47
  370. package/dist/esm/messages/content.mjs.map +1 -1
  371. package/dist/esm/messages/contextPruning.mjs +112 -143
  372. package/dist/esm/messages/contextPruning.mjs.map +1 -1
  373. package/dist/esm/messages/contextPruningSettings.mjs +36 -44
  374. package/dist/esm/messages/contextPruningSettings.mjs.map +1 -1
  375. package/dist/esm/messages/core.mjs +254 -393
  376. package/dist/esm/messages/core.mjs.map +1 -1
  377. package/dist/esm/messages/format.mjs +902 -1383
  378. package/dist/esm/messages/format.mjs.map +1 -1
  379. package/dist/esm/messages/ids.mjs +16 -18
  380. package/dist/esm/messages/ids.mjs.map +1 -1
  381. package/dist/esm/messages/index.mjs +13 -0
  382. package/dist/esm/messages/langchain.mjs +18 -16
  383. package/dist/esm/messages/langchain.mjs.map +1 -1
  384. package/dist/esm/messages/prune.mjs +1053 -1514
  385. package/dist/esm/messages/prune.mjs.map +1 -1
  386. package/dist/esm/messages/recency.mjs +77 -93
  387. package/dist/esm/messages/recency.mjs.map +1 -1
  388. package/dist/esm/messages/reducer.mjs +63 -76
  389. package/dist/esm/messages/reducer.mjs.map +1 -1
  390. package/dist/esm/messages/tools.mjs +49 -75
  391. package/dist/esm/messages/tools.mjs.map +1 -1
  392. package/dist/esm/openai/index.mjs +170 -215
  393. package/dist/esm/openai/index.mjs.map +1 -1
  394. package/dist/esm/responses/index.mjs +301 -389
  395. package/dist/esm/responses/index.mjs.map +1 -1
  396. package/dist/esm/run.mjs +903 -1111
  397. package/dist/esm/run.mjs.map +1 -1
  398. package/dist/esm/session/AgentSession.mjs +806 -985
  399. package/dist/esm/session/AgentSession.mjs.map +1 -1
  400. package/dist/esm/session/JsonlSessionStore.mjs +326 -407
  401. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  402. package/dist/esm/session/handlers.mjs +192 -206
  403. package/dist/esm/session/handlers.mjs.map +1 -1
  404. package/dist/esm/session/ids.mjs +9 -8
  405. package/dist/esm/session/ids.mjs.map +1 -1
  406. package/dist/esm/session/index.mjs +5 -0
  407. package/dist/esm/session/messageSerialization.mjs +94 -154
  408. package/dist/esm/session/messageSerialization.mjs.map +1 -1
  409. package/dist/esm/splitStream.mjs +147 -204
  410. package/dist/esm/splitStream.mjs.map +1 -1
  411. package/dist/esm/stream.mjs +854 -1341
  412. package/dist/esm/stream.mjs.map +1 -1
  413. package/dist/esm/summarization/index.mjs +57 -99
  414. package/dist/esm/summarization/index.mjs.map +1 -1
  415. package/dist/esm/summarization/node.mjs +640 -790
  416. package/dist/esm/summarization/node.mjs.map +1 -1
  417. package/dist/esm/tools/BashExecutor.mjs +103 -129
  418. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  419. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +162 -239
  420. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  421. package/dist/esm/tools/Calculator.mjs +34 -36
  422. package/dist/esm/tools/Calculator.mjs.map +1 -1
  423. package/dist/esm/tools/CodeExecutor.mjs +123 -164
  424. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  425. package/dist/esm/tools/CodeSessionFileSummary.mjs +36 -44
  426. package/dist/esm/tools/CodeSessionFileSummary.mjs.map +1 -1
  427. package/dist/esm/tools/ProgrammaticToolCalling.mjs +454 -644
  428. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  429. package/dist/esm/tools/ReadFile.mjs +17 -18
  430. package/dist/esm/tools/ReadFile.mjs.map +1 -1
  431. package/dist/esm/tools/SkillTool.mjs +26 -25
  432. package/dist/esm/tools/SkillTool.mjs.map +1 -1
  433. package/dist/esm/tools/SubagentTool.mjs +59 -59
  434. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  435. package/dist/esm/tools/ToolNode.mjs +2107 -2684
  436. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  437. package/dist/esm/tools/ToolSearch.mjs +659 -804
  438. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  439. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs +248 -338
  440. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs.map +1 -1
  441. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +170 -195
  442. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -1
  443. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +424 -517
  444. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
  445. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +91 -122
  446. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -1
  447. package/dist/esm/tools/cloudflare/index.mjs +5 -0
  448. package/dist/esm/tools/eagerEventExecution.mjs +75 -96
  449. package/dist/esm/tools/eagerEventExecution.mjs.map +1 -1
  450. package/dist/esm/tools/handlers.mjs +200 -260
  451. package/dist/esm/tools/handlers.mjs.map +1 -1
  452. package/dist/esm/tools/local/CompileCheckTool.mjs +150 -210
  453. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
  454. package/dist/esm/tools/local/FileCheckpointer.mjs +77 -83
  455. package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -1
  456. package/dist/esm/tools/local/LocalCodingTools.mjs +760 -1017
  457. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
  458. package/dist/esm/tools/local/LocalExecutionEngine.mjs +663 -936
  459. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
  460. package/dist/esm/tools/local/LocalExecutionTools.mjs +49 -90
  461. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
  462. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +283 -349
  463. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  464. package/dist/esm/tools/local/attachments.mjs +108 -163
  465. package/dist/esm/tools/local/attachments.mjs.map +1 -1
  466. package/dist/esm/tools/local/bashAst.mjs +99 -111
  467. package/dist/esm/tools/local/bashAst.mjs.map +1 -1
  468. package/dist/esm/tools/local/editStrategies.mjs +126 -167
  469. package/dist/esm/tools/local/editStrategies.mjs.map +1 -1
  470. package/dist/esm/tools/local/index.mjs +13 -0
  471. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +136 -216
  472. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
  473. package/dist/esm/tools/local/syntaxCheck.mjs +138 -155
  474. package/dist/esm/tools/local/syntaxCheck.mjs.map +1 -1
  475. package/dist/esm/tools/local/textEncoding.mjs +25 -21
  476. package/dist/esm/tools/local/textEncoding.mjs.map +1 -1
  477. package/dist/esm/tools/local/workspaceFS.mjs +38 -44
  478. package/dist/esm/tools/local/workspaceFS.mjs.map +1 -1
  479. package/dist/esm/tools/ptcTimeout.mjs +27 -42
  480. package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
  481. package/dist/esm/tools/schema.mjs +24 -21
  482. package/dist/esm/tools/schema.mjs.map +1 -1
  483. package/dist/esm/tools/search/anthropic.mjs +24 -31
  484. package/dist/esm/tools/search/anthropic.mjs.map +1 -1
  485. package/dist/esm/tools/search/content.mjs +93 -116
  486. package/dist/esm/tools/search/content.mjs.map +1 -1
  487. package/dist/esm/tools/search/firecrawl.mjs +139 -169
  488. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  489. package/dist/esm/tools/search/format.mjs +128 -194
  490. package/dist/esm/tools/search/format.mjs.map +1 -1
  491. package/dist/esm/tools/search/highlights.mjs +165 -230
  492. package/dist/esm/tools/search/highlights.mjs.map +1 -1
  493. package/dist/esm/tools/search/index.mjs +3 -0
  494. package/dist/esm/tools/search/rerankers.mjs +149 -168
  495. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  496. package/dist/esm/tools/search/schema.mjs +39 -37
  497. package/dist/esm/tools/search/schema.mjs.map +1 -1
  498. package/dist/esm/tools/search/search.mjs +426 -528
  499. package/dist/esm/tools/search/search.mjs.map +1 -1
  500. package/dist/esm/tools/search/serper-scraper.mjs +104 -124
  501. package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
  502. package/dist/esm/tools/search/tavily-scraper.mjs +127 -178
  503. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -1
  504. package/dist/esm/tools/search/tavily-search.mjs +293 -357
  505. package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
  506. package/dist/esm/tools/search/tool.mjs +259 -297
  507. package/dist/esm/tools/search/tool.mjs.map +1 -1
  508. package/dist/esm/tools/search/utils.mjs +74 -115
  509. package/dist/esm/tools/search/utils.mjs.map +1 -1
  510. package/dist/esm/tools/skillCatalog.mjs +54 -70
  511. package/dist/esm/tools/skillCatalog.mjs.map +1 -1
  512. package/dist/esm/tools/streamedToolCallSeals.mjs +19 -31
  513. package/dist/esm/tools/streamedToolCallSeals.mjs.map +1 -1
  514. package/dist/esm/tools/subagent/SubagentExecutor.mjs +612 -768
  515. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  516. package/dist/esm/tools/subagent/index.mjs +2 -0
  517. package/dist/esm/tools/toolOutputReferences.mjs +523 -624
  518. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  519. package/dist/esm/utils/callbacks.mjs +11 -19
  520. package/dist/esm/utils/callbacks.mjs.map +1 -1
  521. package/dist/esm/utils/errors.mjs +70 -93
  522. package/dist/esm/utils/errors.mjs.map +1 -1
  523. package/dist/esm/utils/events.mjs +32 -40
  524. package/dist/esm/utils/events.mjs.map +1 -1
  525. package/dist/esm/utils/graph.mjs +8 -10
  526. package/dist/esm/utils/graph.mjs.map +1 -1
  527. package/dist/esm/utils/handlers.mjs +60 -80
  528. package/dist/esm/utils/handlers.mjs.map +1 -1
  529. package/dist/esm/utils/index.mjs +10 -0
  530. package/dist/esm/utils/llm.mjs +19 -25
  531. package/dist/esm/utils/llm.mjs.map +1 -1
  532. package/dist/esm/utils/misc.mjs +30 -44
  533. package/dist/esm/utils/misc.mjs.map +1 -1
  534. package/dist/esm/utils/run.mjs +50 -64
  535. package/dist/esm/utils/run.mjs.map +1 -1
  536. package/dist/esm/utils/schema.mjs +11 -17
  537. package/dist/esm/utils/schema.mjs.map +1 -1
  538. package/dist/esm/utils/title.mjs +71 -104
  539. package/dist/esm/utils/title.mjs.map +1 -1
  540. package/dist/esm/utils/tokens.mjs +186 -281
  541. package/dist/esm/utils/tokens.mjs.map +1 -1
  542. package/dist/esm/utils/truncation.mjs +95 -112
  543. package/dist/esm/utils/truncation.mjs.map +1 -1
  544. package/dist/types/tools/search/tool.d.ts +17 -0
  545. package/dist/types/tools/search/types.d.ts +4 -0
  546. package/package.json +4 -10
  547. package/src/tools/search/highlights.ts +9 -1
  548. package/src/tools/search/search.ts +41 -3
  549. package/src/tools/search/source-processing.test.ts +373 -0
  550. package/src/tools/search/tool.ts +22 -2
  551. package/src/tools/search/types.ts +4 -0
  552. package/dist/cjs/langchain/google-common.cjs.map +0 -1
  553. package/dist/cjs/langchain/index.cjs.map +0 -1
  554. package/dist/cjs/langchain/language_models/chat_models.cjs.map +0 -1
  555. package/dist/cjs/langchain/messages/tool.cjs.map +0 -1
  556. package/dist/cjs/langchain/messages.cjs.map +0 -1
  557. package/dist/cjs/langchain/openai.cjs.map +0 -1
  558. package/dist/cjs/langchain/prompts.cjs.map +0 -1
  559. package/dist/cjs/langchain/runnables.cjs.map +0 -1
  560. package/dist/cjs/langchain/tools.cjs.map +0 -1
  561. package/dist/cjs/langchain/utils/env.cjs.map +0 -1
  562. package/dist/cjs/main.cjs.map +0 -1
  563. package/dist/esm/langchain/google-common.mjs.map +0 -1
  564. package/dist/esm/langchain/index.mjs.map +0 -1
  565. package/dist/esm/langchain/language_models/chat_models.mjs.map +0 -1
  566. package/dist/esm/langchain/messages/tool.mjs.map +0 -1
  567. package/dist/esm/langchain/messages.mjs.map +0 -1
  568. package/dist/esm/langchain/openai.mjs.map +0 -1
  569. package/dist/esm/langchain/prompts.mjs.map +0 -1
  570. package/dist/esm/langchain/runnables.mjs.map +0 -1
  571. package/dist/esm/langchain/tools.mjs.map +0 -1
  572. package/dist/esm/langchain/utils/env.mjs.map +0 -1
  573. package/dist/esm/main.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"LocalProgrammaticToolCalling.cjs","sources":["../../../../src/tools/local/LocalProgrammaticToolCalling.ts"],"sourcesContent":["import { createServer } from 'http';\nimport { tool } from '@langchain/core/tools';\nimport { randomBytes, randomUUID, timingSafeEqual } from 'crypto';\nimport type { DynamicStructuredTool } from '@langchain/core/tools';\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { AddressInfo } from 'net';\nimport type * as t from '@/types';\nimport {\n executeTools,\n filterToolsByUsage,\n formatCompletedResponse,\n normalizeToPythonIdentifier,\n ProgrammaticToolCallingName,\n ProgrammaticToolCallingSchema,\n ProgrammaticToolCallingDescription,\n} from '@/tools/ProgrammaticToolCalling';\nimport {\n BashProgrammaticToolCallingSchema,\n BashProgrammaticToolCallingDescription,\n filterBashToolsByUsage,\n normalizeToBashIdentifier,\n} from '@/tools/BashProgrammaticToolCalling';\nimport {\n executeLocalBash,\n executeLocalCode,\n getLocalSessionId,\n shellQuote,\n} from './LocalExecutionEngine';\nimport { executeHooks } from '@/hooks';\nimport { Constants } from '@/common';\n\nconst DEFAULT_TIMEOUT = 60000;\nconst LOCAL_MIN_TIMEOUT = 1000;\nconst LOCAL_MAX_TIMEOUT = 300000;\n\ntype LocalTimeoutSchema = {\n type: 'integer';\n minimum: number;\n maximum: number;\n default: number;\n description: string;\n};\n\ntype LocalProgrammaticToolCallingJsonSchema = {\n type: 'object';\n properties: typeof ProgrammaticToolCallingSchema.properties & {\n timeout: LocalTimeoutSchema;\n lang: {\n type: 'string';\n enum: readonly ['py', 'python', 'bash', 'sh'];\n default: 'bash';\n description: string;\n };\n };\n required: readonly ['code'];\n};\n\ntype LocalBashProgrammaticToolCallingJsonSchema = {\n type: 'object';\n properties: typeof BashProgrammaticToolCallingSchema.properties & {\n timeout: LocalTimeoutSchema;\n };\n required: readonly ['code'];\n};\n\nfunction normalizeLocalTimeout(timeoutMs: number | undefined): number {\n if (timeoutMs == null || !Number.isFinite(timeoutMs)) {\n return DEFAULT_TIMEOUT;\n }\n\n return Math.max(LOCAL_MIN_TIMEOUT, Math.floor(timeoutMs));\n}\n\nfunction formatLocalTimeout(timeoutMs: number): string {\n return timeoutMs % 1000 === 0\n ? `${timeoutMs / 1000} seconds`\n : `${timeoutMs} milliseconds`;\n}\n\nfunction createLocalTimeoutSchema(timeoutMs?: number): LocalTimeoutSchema {\n const defaultTimeout = normalizeLocalTimeout(timeoutMs);\n const maxTimeout = Math.max(LOCAL_MAX_TIMEOUT, defaultTimeout);\n const formattedDefault = formatLocalTimeout(defaultTimeout);\n const formattedMax = formatLocalTimeout(maxTimeout);\n\n return {\n type: 'integer',\n minimum: LOCAL_MIN_TIMEOUT,\n maximum: maxTimeout,\n default: defaultTimeout,\n description:\n 'Maximum local execution time in milliseconds. ' +\n `Default: ${formattedDefault}. Max: ${formattedMax}.`,\n };\n}\n\nfunction createLocalProgrammaticToolCallingSchema(\n localConfig: t.LocalExecutionConfig = {}\n): LocalProgrammaticToolCallingJsonSchema {\n return {\n ...ProgrammaticToolCallingSchema,\n properties: {\n ...ProgrammaticToolCallingSchema.properties,\n timeout: createLocalTimeoutSchema(localConfig.timeoutMs),\n lang: {\n type: 'string',\n enum: ['py', 'python', 'bash', 'sh'],\n default: 'bash',\n description:\n 'Local engine runtime for orchestration code. Defaults to bash; use py/python for Python orchestration.',\n },\n },\n } as const;\n}\n\nfunction createLocalBashProgrammaticToolCallingSchema(\n localConfig: t.LocalExecutionConfig = {}\n): LocalBashProgrammaticToolCallingJsonSchema {\n return {\n ...BashProgrammaticToolCallingSchema,\n properties: {\n ...BashProgrammaticToolCallingSchema.properties,\n timeout: createLocalTimeoutSchema(localConfig.timeoutMs),\n },\n } as const;\n}\n\ntype ToolBridge = {\n url: string;\n token: string;\n close: () => Promise<void>;\n};\n\ntype ToolRequest = {\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n};\n\nconst BRIDGE_AUTH_HEADER = 'x-librechat-bridge-token';\n\nfunction constantTimeEquals(a: string, b: string): boolean {\n const aBuf = Buffer.from(a, 'utf8');\n const bBuf = Buffer.from(b, 'utf8');\n if (aBuf.length !== bBuf.length) {\n return false;\n }\n return timingSafeEqual(aBuf, bBuf);\n}\n\ntype LocalProgrammaticRuntime = 'python' | 'bash';\n\ntype LocalProgrammaticParams = {\n code: string;\n timeout?: number;\n lang?: string;\n runtime?: string;\n language?: string;\n};\n\ntype ToolFilter = (toolDefs: t.LCTool[], code: string) => t.LCTool[];\n\nfunction resolveRuntime(\n params: LocalProgrammaticParams\n): LocalProgrammaticRuntime {\n const rawRuntime = params.lang ?? params.runtime ?? params.language ?? 'bash';\n return rawRuntime === 'py' || rawRuntime === 'python' ? 'python' : 'bash';\n}\n\nfunction toSerializable(value: unknown): unknown {\n if (value === undefined) {\n return null;\n }\n return value;\n}\n\nasync function readRequestBody(req: IncomingMessage): Promise<ToolRequest> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const raw = Buffer.concat(chunks).toString('utf8');\n if (raw === '') {\n return {};\n }\n return JSON.parse(raw) as ToolRequest;\n}\n\nfunction writeJson(res: ServerResponse, status: number, value: unknown): void {\n res.writeHead(status, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(value));\n}\n\n/**\n * Run the host's `PreToolUse` hook chain for a single bridge call.\n * Returns the (possibly rewritten) input and a `denyReason` if any\n * matcher returned `decision: 'deny'` or `'ask'`. `'ask'` collapses\n * to deny because the bridge can't raise a LangGraph interrupt from\n * inside an HTTP handler — fail-closed matches the rest of the SDK\n * when HITL is unavailable.\n *\n * @internal Exported for tests so the deny / allow / updatedInput /\n * ask branches can be exercised without standing up the full HTTP\n * bridge.\n */\nexport async function applyPreToolUseHooksForBridge(\n hookContext: t.ProgrammaticHookContext,\n toolName: string,\n toolUseId: string,\n toolInput: Record<string, unknown>\n): Promise<{ input: Record<string, unknown>; denyReason?: string }> {\n if (hookContext.registry == null) {\n return { input: toolInput };\n }\n const result = await executeHooks({\n registry: hookContext.registry,\n input: {\n hook_event_name: 'PreToolUse',\n runId: hookContext.runId,\n threadId: hookContext.threadId,\n agentId: hookContext.agentId,\n executingAgentId: hookContext.executingAgentId,\n toolName,\n toolInput,\n toolUseId,\n stepId: '',\n turn: 0,\n },\n sessionId: hookContext.runId,\n matchQuery: toolName,\n }).catch(() => undefined);\n if (result == null) {\n return { input: toolInput };\n }\n const nextInput =\n result.updatedInput != null\n ? (result.updatedInput as Record<string, unknown>)\n : toolInput;\n if (result.decision === 'deny' || result.decision === 'ask') {\n return {\n input: nextInput,\n denyReason:\n result.reason ??\n (result.decision === 'ask'\n ? `Tool \"${toolName}\" requires human approval; bridge cannot raise an interrupt — denying.`\n : `Tool \"${toolName}\" denied by PreToolUse hook.`),\n };\n }\n return { input: nextInput };\n}\n\nasync function createToolBridge(\n toolMap: t.ToolMap,\n hookContext?: t.ProgrammaticHookContext\n): Promise<ToolBridge> {\n const token = randomBytes(32).toString('hex');\n const server = createServer((req, res) => {\n // `?mode=text` returns the already-serialized result as the body\n // (or the error message at non-2xx). Python/Node callers stay on\n // JSON; bash callers using curl can avoid pulling in a JSON\n // parser dependency (Codex P2 #19 — `python3` was a hard\n // requirement for the bash bridge, breaking minimal containers).\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n const isTextMode = url.searchParams.get('mode') === 'text';\n if (req.method !== 'POST' || url.pathname !== '/tool') {\n if (isTextMode) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n } else {\n writeJson(res, 404, { error: 'Not found' });\n }\n return;\n }\n\n const presented = req.headers[BRIDGE_AUTH_HEADER];\n const presentedToken = Array.isArray(presented) ? presented[0] : presented;\n if (\n typeof presentedToken !== 'string' ||\n !constantTimeEquals(presentedToken, token)\n ) {\n if (isTextMode) {\n res.writeHead(401, { 'Content-Type': 'text/plain' });\n res.end('Unauthorized');\n } else {\n writeJson(res, 401, { error: 'Unauthorized' });\n }\n return;\n }\n\n readRequestBody(req)\n .then(async (body) => {\n if (typeof body.name !== 'string' || body.name === '') {\n const message = 'Tool request is missing a tool name.';\n if (isTextMode) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end(message);\n } else {\n writeJson(res, 400, {\n call_id: body.id ?? 'invalid',\n result: null,\n is_error: true,\n error_message: message,\n });\n }\n return;\n }\n\n const callId = body.id ?? `local_call_${randomUUID()}`;\n let effectiveInput: Record<string, unknown> = body.input ?? {};\n if (hookContext != null) {\n const gate = await applyPreToolUseHooksForBridge(\n hookContext,\n body.name,\n callId,\n effectiveInput\n );\n if (gate.denyReason != null) {\n const denyMsg = gate.denyReason;\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(denyMsg);\n } else {\n writeJson(res, 500, {\n call_id: callId,\n result: null,\n is_error: true,\n error_message: denyMsg,\n });\n }\n return;\n }\n effectiveInput = gate.input;\n }\n\n const [result] = await executeTools(\n [\n {\n id: callId,\n name: body.name,\n input: effectiveInput,\n },\n ],\n toolMap\n );\n\n if (isTextMode) {\n if (result.is_error === true) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(result.error_message ?? `Tool ${body.name} failed`);\n } else {\n const value = toSerializable(result.result);\n const text =\n typeof value === 'string' ? value : JSON.stringify(value);\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end(text);\n }\n return;\n }\n\n writeJson(res, 200, {\n ...result,\n result: toSerializable(result.result),\n });\n })\n .catch((error: Error) => {\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(error.message);\n } else {\n writeJson(res, 500, {\n call_id: 'error',\n result: null,\n is_error: true,\n error_message: error.message,\n });\n }\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', resolve);\n });\n\n const address = server.address() as AddressInfo;\n return {\n url: `http://127.0.0.1:${address.port}/tool`,\n token,\n close: () =>\n new Promise((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n }),\n };\n}\n\nfunction indent(code: string): string {\n return code\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n}\n\nfunction createPythonProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functionDefs = toolDefs\n .map((def) => {\n const pythonName = normalizeToPythonIdentifier(def.name);\n return [\n `async def ${pythonName}(**kwargs):`,\n ` return await __librechat_call_tool(${JSON.stringify(def.name)}, kwargs)`,\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\nimport asyncio\nimport json\nimport urllib.request\n\n__LIBRECHAT_TOOL_BRIDGE = ${JSON.stringify(bridgeUrl)}\n__LIBRECHAT_TOOL_TOKEN = ${JSON.stringify(bridgeToken)}\n\nasync def __librechat_call_tool(name, payload):\n body = json.dumps({\"name\": name, \"input\": payload}).encode(\"utf-8\")\n headers = {\n \"Content-Type\": \"application/json\",\n ${JSON.stringify(BRIDGE_AUTH_HEADER)}: __LIBRECHAT_TOOL_TOKEN,\n }\n\n def request():\n req = urllib.request.Request(__LIBRECHAT_TOOL_BRIDGE, data=body, headers=headers, method=\"POST\")\n with urllib.request.urlopen(req, timeout=300) as response:\n return response.read().decode(\"utf-8\")\n\n raw = await asyncio.to_thread(request)\n result = json.loads(raw)\n if result.get(\"is_error\"):\n raise RuntimeError(result.get(\"error_message\") or f\"Tool {name} failed\")\n return result.get(\"result\")\n\n${functionDefs}\n\nasync def __librechat_main():\n${indent(code)}\n\nasyncio.run(__librechat_main())\n`.trimStart();\n}\n\nexport function _createBashProgramForTests(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n return createBashProgram(code, toolDefs, bridgeUrl, bridgeToken);\n}\n\nfunction createBashProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functions = toolDefs\n .map((def) => {\n const bashName = normalizeToBashIdentifier(def.name);\n return [\n `${bashName}() {`,\n ' local payload=\"${1:-}\"',\n ' if [ -z \"$payload\" ]; then payload=\\'{}\\'; fi',\n ` __librechat_call_tool ${shellQuote(def.name)} \"$payload\"`,\n '}',\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\n__LIBRECHAT_TOOL_BRIDGE=${shellQuote(bridgeUrl)}\n__LIBRECHAT_TOOL_HEADER=${shellQuote(BRIDGE_AUTH_HEADER)}\n__LIBRECHAT_TOOL_TOKEN=${shellQuote(bridgeToken)}\n\n# Bridge call helper. Tries curl first (universally available, no\n# JSON parser needed thanks to the bridge's ?mode=text endpoint),\n# falls back to python3 for environments without curl. Codex P2 #19\n# flagged that the prior python3-only path broke minimal containers\n# (and Windows hosts without a python3 binary on PATH). Tool names\n# come from Constants.* and are always safe identifiers, so we can\n# splice them into JSON without an escape pass.\n__librechat_call_tool() {\n local tool_name=\"$1\"\n local payload=\"$2\"\n if command -v curl >/dev/null 2>&1; then\n local body=\"{\\\\\"name\\\\\":\\\\\"$tool_name\\\\\",\\\\\"input\\\\\":$payload}\"\n local response\n local http_code\n response=$(curl -sS -X POST \\\n -H \"Content-Type: application/json\" \\\n -H \"$__LIBRECHAT_TOOL_HEADER: $__LIBRECHAT_TOOL_TOKEN\" \\\n --data-binary \"$body\" \\\n -w '\\\\n__LIBRECHAT_HTTP_CODE_%{http_code}__' \\\n \"$__LIBRECHAT_TOOL_BRIDGE?mode=text\")\n http_code=$(printf '%s' \"$response\" | sed -n 's/.*__LIBRECHAT_HTTP_CODE_\\\\([0-9][0-9]*\\\\)__$/\\\\1/p')\n local body_only\n body_only=$(printf '%s' \"$response\" | sed 's/__LIBRECHAT_HTTP_CODE_[0-9][0-9]*__$//')\n if [ \"$http_code\" = \"200\" ]; then\n printf '%s' \"$body_only\"\n return 0\n fi\n printf '%s\\\\n' \"$body_only\" >&2\n return 1\n elif command -v python3 >/dev/null 2>&1; then\n python3 - \"$__LIBRECHAT_TOOL_BRIDGE\" \"$tool_name\" \"$payload\" \"$__LIBRECHAT_TOOL_HEADER\" \"$__LIBRECHAT_TOOL_TOKEN\" <<'PY'\nimport json\nimport sys\nimport urllib.request\n\nurl, name, payload, header, token = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]\nbody = json.dumps({\"name\": name, \"input\": json.loads(payload)}).encode(\"utf-8\")\nreq = urllib.request.Request(url, data=body, headers={\"Content-Type\": \"application/json\", header: token}, method=\"POST\")\nwith urllib.request.urlopen(req, timeout=300) as response:\n result = json.loads(response.read().decode(\"utf-8\"))\nif result.get(\"is_error\"):\n print(result.get(\"error_message\") or f\"Tool {name} failed\", file=sys.stderr)\n sys.exit(1)\nvalue = result.get(\"result\")\nif isinstance(value, str):\n print(value)\nelse:\n print(json.dumps(value))\nPY\n else\n printf 'librechat: tool bridge needs either curl or python3 on PATH\\\\n' >&2\n return 1\n fi\n}\n\n${functions}\n\n${code}\n`.trimStart();\n}\n\nfunction getProgrammaticContext(config?: {\n toolCall?: unknown;\n}): Partial<t.ProgrammaticCache> {\n return (config?.toolCall ?? {}) as Partial<t.ProgrammaticCache>;\n}\n\nfunction createEffectiveToolMap(\n toolMap: t.ToolMap,\n toolDefs: t.LCTool[],\n code: string,\n filterTools: ToolFilter\n): { effectiveTools: t.LCTool[]; effectiveMap: t.ToolMap } {\n const effectiveTools = filterTools(toolDefs, code);\n const effectiveMap = new Map<string, t.GenericTool>(\n effectiveTools\n .map((def) => {\n const executable = toolMap.get(def.name);\n return executable == null\n ? undefined\n : ([def.name, executable] as [string, t.GenericTool]);\n })\n .filter((entry): entry is [string, t.GenericTool] => entry != null)\n );\n\n return { effectiveTools, effectiveMap };\n}\n\nasync function runLocalProgrammaticTool(args: {\n params: LocalProgrammaticParams;\n config?: { toolCall?: unknown };\n localConfig: t.LocalExecutionConfig;\n runtime: LocalProgrammaticRuntime;\n}): Promise<[string, t.ProgrammaticExecutionArtifact]> {\n const { toolMap, toolDefs, hookContext } = getProgrammaticContext(\n args.config\n );\n\n if (toolMap == null || toolMap.size === 0) {\n throw new Error('No toolMap provided for local programmatic execution.');\n }\n if (toolDefs == null || toolDefs.length === 0) {\n throw new Error(\n 'No tool definitions provided for local programmatic execution.'\n );\n }\n\n const { effectiveTools, effectiveMap } = createEffectiveToolMap(\n toolMap,\n toolDefs,\n args.params.code,\n args.runtime === 'bash' ? filterBashToolsByUsage : filterToolsByUsage\n );\n const bridge = await createToolBridge(effectiveMap, hookContext);\n\n try {\n const timeoutMs =\n args.params.timeout ?? args.localConfig.timeoutMs ?? DEFAULT_TIMEOUT;\n const result =\n args.runtime === 'bash'\n ? await executeLocalBash(\n createBashProgram(\n args.params.code,\n effectiveTools,\n bridge.url,\n bridge.token\n ),\n { ...args.localConfig, timeoutMs }\n )\n : await executeLocalCode(\n {\n lang: 'py',\n code: createPythonProgram(\n args.params.code,\n effectiveTools,\n bridge.url,\n bridge.token\n ),\n },\n { ...args.localConfig, timeoutMs }\n );\n\n if (result.exitCode !== 0 || result.timedOut) {\n throw new Error(\n result.stderr !== ''\n ? result.stderr\n : `Local ${args.runtime} programmatic execution exited with code ${\n result.exitCode ?? 'unknown'\n }`\n );\n }\n\n return formatCompletedResponse({\n status: 'completed',\n session_id: getLocalSessionId(args.localConfig),\n stdout: result.stdout,\n stderr: result.stderr,\n files: [],\n });\n } finally {\n await bridge.close();\n }\n}\n\nexport function createLocalProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: resolveRuntime(params),\n });\n },\n {\n name: ProgrammaticToolCallingName,\n description: `${ProgrammaticToolCallingDescription}\\n\\nLocal engine: runs bash by default, or Python when \\`lang\\` is \\`py\\` or \\`python\\`, on the host machine and calls tools through an in-process localhost bridge.`,\n schema: createLocalProgrammaticToolCallingSchema(localConfig),\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport function createLocalBashProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: 'bash',\n });\n },\n {\n name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,\n description: `${BashProgrammaticToolCallingDescription}\\n\\nLocal engine: runs this bash orchestration code on the host machine and calls tools through an in-process localhost bridge.`,\n schema: createLocalBashProgrammaticToolCallingSchema(localConfig),\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n"],"names":["ProgrammaticToolCallingSchema","BashProgrammaticToolCallingSchema","timingSafeEqual","executeHooks","randomBytes","createServer","randomUUID","executeTools","normalizeToPythonIdentifier","normalizeToBashIdentifier","shellQuote","filterBashToolsByUsage","filterToolsByUsage","executeLocalBash","executeLocalCode","formatCompletedResponse","getLocalSessionId","tool","ProgrammaticToolCallingName","ProgrammaticToolCallingDescription","Constants","BashProgrammaticToolCallingDescription"],"mappings":"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"}
1
+ {"version":3,"file":"LocalProgrammaticToolCalling.cjs","names":["ProgrammaticToolCallingSchema","BashProgrammaticToolCallingSchema","executeHooks","executeTools","normalizeToPythonIdentifier","normalizeToBashIdentifier","shellQuote","filterBashToolsByUsage","filterToolsByUsage","executeLocalBash","executeLocalCode","formatCompletedResponse","getLocalSessionId","ProgrammaticToolCallingName","ProgrammaticToolCallingDescription","BashProgrammaticToolCallingDescription"],"sources":["../../../../src/tools/local/LocalProgrammaticToolCalling.ts"],"sourcesContent":["import { createServer } from 'http';\nimport { tool } from '@langchain/core/tools';\nimport { randomBytes, randomUUID, timingSafeEqual } from 'crypto';\nimport type { DynamicStructuredTool } from '@langchain/core/tools';\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { AddressInfo } from 'net';\nimport type * as t from '@/types';\nimport {\n executeTools,\n filterToolsByUsage,\n formatCompletedResponse,\n normalizeToPythonIdentifier,\n ProgrammaticToolCallingName,\n ProgrammaticToolCallingSchema,\n ProgrammaticToolCallingDescription,\n} from '@/tools/ProgrammaticToolCalling';\nimport {\n BashProgrammaticToolCallingSchema,\n BashProgrammaticToolCallingDescription,\n filterBashToolsByUsage,\n normalizeToBashIdentifier,\n} from '@/tools/BashProgrammaticToolCalling';\nimport {\n executeLocalBash,\n executeLocalCode,\n getLocalSessionId,\n shellQuote,\n} from './LocalExecutionEngine';\nimport { executeHooks } from '@/hooks';\nimport { Constants } from '@/common';\n\nconst DEFAULT_TIMEOUT = 60000;\nconst LOCAL_MIN_TIMEOUT = 1000;\nconst LOCAL_MAX_TIMEOUT = 300000;\n\ntype LocalTimeoutSchema = {\n type: 'integer';\n minimum: number;\n maximum: number;\n default: number;\n description: string;\n};\n\ntype LocalProgrammaticToolCallingJsonSchema = {\n type: 'object';\n properties: typeof ProgrammaticToolCallingSchema.properties & {\n timeout: LocalTimeoutSchema;\n lang: {\n type: 'string';\n enum: readonly ['py', 'python', 'bash', 'sh'];\n default: 'bash';\n description: string;\n };\n };\n required: readonly ['code'];\n};\n\ntype LocalBashProgrammaticToolCallingJsonSchema = {\n type: 'object';\n properties: typeof BashProgrammaticToolCallingSchema.properties & {\n timeout: LocalTimeoutSchema;\n };\n required: readonly ['code'];\n};\n\nfunction normalizeLocalTimeout(timeoutMs: number | undefined): number {\n if (timeoutMs == null || !Number.isFinite(timeoutMs)) {\n return DEFAULT_TIMEOUT;\n }\n\n return Math.max(LOCAL_MIN_TIMEOUT, Math.floor(timeoutMs));\n}\n\nfunction formatLocalTimeout(timeoutMs: number): string {\n return timeoutMs % 1000 === 0\n ? `${timeoutMs / 1000} seconds`\n : `${timeoutMs} milliseconds`;\n}\n\nfunction createLocalTimeoutSchema(timeoutMs?: number): LocalTimeoutSchema {\n const defaultTimeout = normalizeLocalTimeout(timeoutMs);\n const maxTimeout = Math.max(LOCAL_MAX_TIMEOUT, defaultTimeout);\n const formattedDefault = formatLocalTimeout(defaultTimeout);\n const formattedMax = formatLocalTimeout(maxTimeout);\n\n return {\n type: 'integer',\n minimum: LOCAL_MIN_TIMEOUT,\n maximum: maxTimeout,\n default: defaultTimeout,\n description:\n 'Maximum local execution time in milliseconds. ' +\n `Default: ${formattedDefault}. Max: ${formattedMax}.`,\n };\n}\n\nfunction createLocalProgrammaticToolCallingSchema(\n localConfig: t.LocalExecutionConfig = {}\n): LocalProgrammaticToolCallingJsonSchema {\n return {\n ...ProgrammaticToolCallingSchema,\n properties: {\n ...ProgrammaticToolCallingSchema.properties,\n timeout: createLocalTimeoutSchema(localConfig.timeoutMs),\n lang: {\n type: 'string',\n enum: ['py', 'python', 'bash', 'sh'],\n default: 'bash',\n description:\n 'Local engine runtime for orchestration code. Defaults to bash; use py/python for Python orchestration.',\n },\n },\n } as const;\n}\n\nfunction createLocalBashProgrammaticToolCallingSchema(\n localConfig: t.LocalExecutionConfig = {}\n): LocalBashProgrammaticToolCallingJsonSchema {\n return {\n ...BashProgrammaticToolCallingSchema,\n properties: {\n ...BashProgrammaticToolCallingSchema.properties,\n timeout: createLocalTimeoutSchema(localConfig.timeoutMs),\n },\n } as const;\n}\n\ntype ToolBridge = {\n url: string;\n token: string;\n close: () => Promise<void>;\n};\n\ntype ToolRequest = {\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n};\n\nconst BRIDGE_AUTH_HEADER = 'x-librechat-bridge-token';\n\nfunction constantTimeEquals(a: string, b: string): boolean {\n const aBuf = Buffer.from(a, 'utf8');\n const bBuf = Buffer.from(b, 'utf8');\n if (aBuf.length !== bBuf.length) {\n return false;\n }\n return timingSafeEqual(aBuf, bBuf);\n}\n\ntype LocalProgrammaticRuntime = 'python' | 'bash';\n\ntype LocalProgrammaticParams = {\n code: string;\n timeout?: number;\n lang?: string;\n runtime?: string;\n language?: string;\n};\n\ntype ToolFilter = (toolDefs: t.LCTool[], code: string) => t.LCTool[];\n\nfunction resolveRuntime(\n params: LocalProgrammaticParams\n): LocalProgrammaticRuntime {\n const rawRuntime = params.lang ?? params.runtime ?? params.language ?? 'bash';\n return rawRuntime === 'py' || rawRuntime === 'python' ? 'python' : 'bash';\n}\n\nfunction toSerializable(value: unknown): unknown {\n if (value === undefined) {\n return null;\n }\n return value;\n}\n\nasync function readRequestBody(req: IncomingMessage): Promise<ToolRequest> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const raw = Buffer.concat(chunks).toString('utf8');\n if (raw === '') {\n return {};\n }\n return JSON.parse(raw) as ToolRequest;\n}\n\nfunction writeJson(res: ServerResponse, status: number, value: unknown): void {\n res.writeHead(status, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(value));\n}\n\n/**\n * Run the host's `PreToolUse` hook chain for a single bridge call.\n * Returns the (possibly rewritten) input and a `denyReason` if any\n * matcher returned `decision: 'deny'` or `'ask'`. `'ask'` collapses\n * to deny because the bridge can't raise a LangGraph interrupt from\n * inside an HTTP handler — fail-closed matches the rest of the SDK\n * when HITL is unavailable.\n *\n * @internal Exported for tests so the deny / allow / updatedInput /\n * ask branches can be exercised without standing up the full HTTP\n * bridge.\n */\nexport async function applyPreToolUseHooksForBridge(\n hookContext: t.ProgrammaticHookContext,\n toolName: string,\n toolUseId: string,\n toolInput: Record<string, unknown>\n): Promise<{ input: Record<string, unknown>; denyReason?: string }> {\n if (hookContext.registry == null) {\n return { input: toolInput };\n }\n const result = await executeHooks({\n registry: hookContext.registry,\n input: {\n hook_event_name: 'PreToolUse',\n runId: hookContext.runId,\n threadId: hookContext.threadId,\n agentId: hookContext.agentId,\n executingAgentId: hookContext.executingAgentId,\n toolName,\n toolInput,\n toolUseId,\n stepId: '',\n turn: 0,\n },\n sessionId: hookContext.runId,\n matchQuery: toolName,\n }).catch(() => undefined);\n if (result == null) {\n return { input: toolInput };\n }\n const nextInput =\n result.updatedInput != null\n ? (result.updatedInput as Record<string, unknown>)\n : toolInput;\n if (result.decision === 'deny' || result.decision === 'ask') {\n return {\n input: nextInput,\n denyReason:\n result.reason ??\n (result.decision === 'ask'\n ? `Tool \"${toolName}\" requires human approval; bridge cannot raise an interrupt — denying.`\n : `Tool \"${toolName}\" denied by PreToolUse hook.`),\n };\n }\n return { input: nextInput };\n}\n\nasync function createToolBridge(\n toolMap: t.ToolMap,\n hookContext?: t.ProgrammaticHookContext\n): Promise<ToolBridge> {\n const token = randomBytes(32).toString('hex');\n const server = createServer((req, res) => {\n // `?mode=text` returns the already-serialized result as the body\n // (or the error message at non-2xx). Python/Node callers stay on\n // JSON; bash callers using curl can avoid pulling in a JSON\n // parser dependency (Codex P2 #19 — `python3` was a hard\n // requirement for the bash bridge, breaking minimal containers).\n const url = new URL(req.url ?? '/', 'http://127.0.0.1');\n const isTextMode = url.searchParams.get('mode') === 'text';\n if (req.method !== 'POST' || url.pathname !== '/tool') {\n if (isTextMode) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n } else {\n writeJson(res, 404, { error: 'Not found' });\n }\n return;\n }\n\n const presented = req.headers[BRIDGE_AUTH_HEADER];\n const presentedToken = Array.isArray(presented) ? presented[0] : presented;\n if (\n typeof presentedToken !== 'string' ||\n !constantTimeEquals(presentedToken, token)\n ) {\n if (isTextMode) {\n res.writeHead(401, { 'Content-Type': 'text/plain' });\n res.end('Unauthorized');\n } else {\n writeJson(res, 401, { error: 'Unauthorized' });\n }\n return;\n }\n\n readRequestBody(req)\n .then(async (body) => {\n if (typeof body.name !== 'string' || body.name === '') {\n const message = 'Tool request is missing a tool name.';\n if (isTextMode) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end(message);\n } else {\n writeJson(res, 400, {\n call_id: body.id ?? 'invalid',\n result: null,\n is_error: true,\n error_message: message,\n });\n }\n return;\n }\n\n const callId = body.id ?? `local_call_${randomUUID()}`;\n let effectiveInput: Record<string, unknown> = body.input ?? {};\n if (hookContext != null) {\n const gate = await applyPreToolUseHooksForBridge(\n hookContext,\n body.name,\n callId,\n effectiveInput\n );\n if (gate.denyReason != null) {\n const denyMsg = gate.denyReason;\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(denyMsg);\n } else {\n writeJson(res, 500, {\n call_id: callId,\n result: null,\n is_error: true,\n error_message: denyMsg,\n });\n }\n return;\n }\n effectiveInput = gate.input;\n }\n\n const [result] = await executeTools(\n [\n {\n id: callId,\n name: body.name,\n input: effectiveInput,\n },\n ],\n toolMap\n );\n\n if (isTextMode) {\n if (result.is_error === true) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(result.error_message ?? `Tool ${body.name} failed`);\n } else {\n const value = toSerializable(result.result);\n const text =\n typeof value === 'string' ? value : JSON.stringify(value);\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end(text);\n }\n return;\n }\n\n writeJson(res, 200, {\n ...result,\n result: toSerializable(result.result),\n });\n })\n .catch((error: Error) => {\n if (isTextMode) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(error.message);\n } else {\n writeJson(res, 500, {\n call_id: 'error',\n result: null,\n is_error: true,\n error_message: error.message,\n });\n }\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', resolve);\n });\n\n const address = server.address() as AddressInfo;\n return {\n url: `http://127.0.0.1:${address.port}/tool`,\n token,\n close: () =>\n new Promise((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n }),\n };\n}\n\nfunction indent(code: string): string {\n return code\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n}\n\nfunction createPythonProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functionDefs = toolDefs\n .map((def) => {\n const pythonName = normalizeToPythonIdentifier(def.name);\n return [\n `async def ${pythonName}(**kwargs):`,\n ` return await __librechat_call_tool(${JSON.stringify(def.name)}, kwargs)`,\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\nimport asyncio\nimport json\nimport urllib.request\n\n__LIBRECHAT_TOOL_BRIDGE = ${JSON.stringify(bridgeUrl)}\n__LIBRECHAT_TOOL_TOKEN = ${JSON.stringify(bridgeToken)}\n\nasync def __librechat_call_tool(name, payload):\n body = json.dumps({\"name\": name, \"input\": payload}).encode(\"utf-8\")\n headers = {\n \"Content-Type\": \"application/json\",\n ${JSON.stringify(BRIDGE_AUTH_HEADER)}: __LIBRECHAT_TOOL_TOKEN,\n }\n\n def request():\n req = urllib.request.Request(__LIBRECHAT_TOOL_BRIDGE, data=body, headers=headers, method=\"POST\")\n with urllib.request.urlopen(req, timeout=300) as response:\n return response.read().decode(\"utf-8\")\n\n raw = await asyncio.to_thread(request)\n result = json.loads(raw)\n if result.get(\"is_error\"):\n raise RuntimeError(result.get(\"error_message\") or f\"Tool {name} failed\")\n return result.get(\"result\")\n\n${functionDefs}\n\nasync def __librechat_main():\n${indent(code)}\n\nasyncio.run(__librechat_main())\n`.trimStart();\n}\n\nexport function _createBashProgramForTests(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n return createBashProgram(code, toolDefs, bridgeUrl, bridgeToken);\n}\n\nfunction createBashProgram(\n code: string,\n toolDefs: t.LCTool[],\n bridgeUrl: string,\n bridgeToken: string\n): string {\n const functions = toolDefs\n .map((def) => {\n const bashName = normalizeToBashIdentifier(def.name);\n return [\n `${bashName}() {`,\n ' local payload=\"${1:-}\"',\n ' if [ -z \"$payload\" ]; then payload=\\'{}\\'; fi',\n ` __librechat_call_tool ${shellQuote(def.name)} \"$payload\"`,\n '}',\n ].join('\\n');\n })\n .join('\\n\\n');\n\n return `\n__LIBRECHAT_TOOL_BRIDGE=${shellQuote(bridgeUrl)}\n__LIBRECHAT_TOOL_HEADER=${shellQuote(BRIDGE_AUTH_HEADER)}\n__LIBRECHAT_TOOL_TOKEN=${shellQuote(bridgeToken)}\n\n# Bridge call helper. Tries curl first (universally available, no\n# JSON parser needed thanks to the bridge's ?mode=text endpoint),\n# falls back to python3 for environments without curl. Codex P2 #19\n# flagged that the prior python3-only path broke minimal containers\n# (and Windows hosts without a python3 binary on PATH). Tool names\n# come from Constants.* and are always safe identifiers, so we can\n# splice them into JSON without an escape pass.\n__librechat_call_tool() {\n local tool_name=\"$1\"\n local payload=\"$2\"\n if command -v curl >/dev/null 2>&1; then\n local body=\"{\\\\\"name\\\\\":\\\\\"$tool_name\\\\\",\\\\\"input\\\\\":$payload}\"\n local response\n local http_code\n response=$(curl -sS -X POST \\\n -H \"Content-Type: application/json\" \\\n -H \"$__LIBRECHAT_TOOL_HEADER: $__LIBRECHAT_TOOL_TOKEN\" \\\n --data-binary \"$body\" \\\n -w '\\\\n__LIBRECHAT_HTTP_CODE_%{http_code}__' \\\n \"$__LIBRECHAT_TOOL_BRIDGE?mode=text\")\n http_code=$(printf '%s' \"$response\" | sed -n 's/.*__LIBRECHAT_HTTP_CODE_\\\\([0-9][0-9]*\\\\)__$/\\\\1/p')\n local body_only\n body_only=$(printf '%s' \"$response\" | sed 's/__LIBRECHAT_HTTP_CODE_[0-9][0-9]*__$//')\n if [ \"$http_code\" = \"200\" ]; then\n printf '%s' \"$body_only\"\n return 0\n fi\n printf '%s\\\\n' \"$body_only\" >&2\n return 1\n elif command -v python3 >/dev/null 2>&1; then\n python3 - \"$__LIBRECHAT_TOOL_BRIDGE\" \"$tool_name\" \"$payload\" \"$__LIBRECHAT_TOOL_HEADER\" \"$__LIBRECHAT_TOOL_TOKEN\" <<'PY'\nimport json\nimport sys\nimport urllib.request\n\nurl, name, payload, header, token = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]\nbody = json.dumps({\"name\": name, \"input\": json.loads(payload)}).encode(\"utf-8\")\nreq = urllib.request.Request(url, data=body, headers={\"Content-Type\": \"application/json\", header: token}, method=\"POST\")\nwith urllib.request.urlopen(req, timeout=300) as response:\n result = json.loads(response.read().decode(\"utf-8\"))\nif result.get(\"is_error\"):\n print(result.get(\"error_message\") or f\"Tool {name} failed\", file=sys.stderr)\n sys.exit(1)\nvalue = result.get(\"result\")\nif isinstance(value, str):\n print(value)\nelse:\n print(json.dumps(value))\nPY\n else\n printf 'librechat: tool bridge needs either curl or python3 on PATH\\\\n' >&2\n return 1\n fi\n}\n\n${functions}\n\n${code}\n`.trimStart();\n}\n\nfunction getProgrammaticContext(config?: {\n toolCall?: unknown;\n}): Partial<t.ProgrammaticCache> {\n return (config?.toolCall ?? {}) as Partial<t.ProgrammaticCache>;\n}\n\nfunction createEffectiveToolMap(\n toolMap: t.ToolMap,\n toolDefs: t.LCTool[],\n code: string,\n filterTools: ToolFilter\n): { effectiveTools: t.LCTool[]; effectiveMap: t.ToolMap } {\n const effectiveTools = filterTools(toolDefs, code);\n const effectiveMap = new Map<string, t.GenericTool>(\n effectiveTools\n .map((def) => {\n const executable = toolMap.get(def.name);\n return executable == null\n ? undefined\n : ([def.name, executable] as [string, t.GenericTool]);\n })\n .filter((entry): entry is [string, t.GenericTool] => entry != null)\n );\n\n return { effectiveTools, effectiveMap };\n}\n\nasync function runLocalProgrammaticTool(args: {\n params: LocalProgrammaticParams;\n config?: { toolCall?: unknown };\n localConfig: t.LocalExecutionConfig;\n runtime: LocalProgrammaticRuntime;\n}): Promise<[string, t.ProgrammaticExecutionArtifact]> {\n const { toolMap, toolDefs, hookContext } = getProgrammaticContext(\n args.config\n );\n\n if (toolMap == null || toolMap.size === 0) {\n throw new Error('No toolMap provided for local programmatic execution.');\n }\n if (toolDefs == null || toolDefs.length === 0) {\n throw new Error(\n 'No tool definitions provided for local programmatic execution.'\n );\n }\n\n const { effectiveTools, effectiveMap } = createEffectiveToolMap(\n toolMap,\n toolDefs,\n args.params.code,\n args.runtime === 'bash' ? filterBashToolsByUsage : filterToolsByUsage\n );\n const bridge = await createToolBridge(effectiveMap, hookContext);\n\n try {\n const timeoutMs =\n args.params.timeout ?? args.localConfig.timeoutMs ?? DEFAULT_TIMEOUT;\n const result =\n args.runtime === 'bash'\n ? await executeLocalBash(\n createBashProgram(\n args.params.code,\n effectiveTools,\n bridge.url,\n bridge.token\n ),\n { ...args.localConfig, timeoutMs }\n )\n : await executeLocalCode(\n {\n lang: 'py',\n code: createPythonProgram(\n args.params.code,\n effectiveTools,\n bridge.url,\n bridge.token\n ),\n },\n { ...args.localConfig, timeoutMs }\n );\n\n if (result.exitCode !== 0 || result.timedOut) {\n throw new Error(\n result.stderr !== ''\n ? result.stderr\n : `Local ${args.runtime} programmatic execution exited with code ${\n result.exitCode ?? 'unknown'\n }`\n );\n }\n\n return formatCompletedResponse({\n status: 'completed',\n session_id: getLocalSessionId(args.localConfig),\n stdout: result.stdout,\n stderr: result.stderr,\n files: [],\n });\n } finally {\n await bridge.close();\n }\n}\n\nexport function createLocalProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: resolveRuntime(params),\n });\n },\n {\n name: ProgrammaticToolCallingName,\n description: `${ProgrammaticToolCallingDescription}\\n\\nLocal engine: runs bash by default, or Python when \\`lang\\` is \\`py\\` or \\`python\\`, on the host machine and calls tools through an in-process localhost bridge.`,\n schema: createLocalProgrammaticToolCallingSchema(localConfig),\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport function createLocalBashProgrammaticToolCallingTool(\n localConfig: t.LocalExecutionConfig = {}\n): DynamicStructuredTool {\n return tool(\n async (rawParams, config) => {\n const params = rawParams as LocalProgrammaticParams;\n return runLocalProgrammaticTool({\n params,\n config,\n localConfig,\n runtime: 'bash',\n });\n },\n {\n name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,\n description: `${BashProgrammaticToolCallingDescription}\\n\\nLocal engine: runs this bash orchestration code on the host machine and calls tools through an in-process localhost bridge.`,\n schema: createLocalBashProgrammaticToolCallingSchema(localConfig),\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n"],"mappings":"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"}
@@ -1,178 +1,121 @@
1
- 'use strict';
2
-
3
- var promises = require('fs/promises');
4
-
1
+ let fs_promises = require("fs/promises");
2
+ //#region src/tools/local/attachments.ts
5
3
  /**
6
- * Detects whether a file on disk is an LLM-renderable attachment
7
- * (image / PDF) and produces the LangChain `MessageContentComplex[]`
8
- * payload a `ToolMessage` needs to actually surface those bytes to
9
- * the vision-capable model.
10
- *
11
- * Same approach as LibreChat's `api/server/utils/files.js`: sniff the
12
- * magic bytes (NOT the extension) so a mislabelled `.png` that's
13
- * really a binary blob doesn't get embedded as an image. Inlined for
14
- * the five formats we actually care about (PNG / JPEG / GIF / WebP /
15
- * PDF) instead of pulling the ESM-only `file-type` package — keeps
16
- * the test setup CJS-clean.
17
- *
18
- * Provider compatibility:
19
- * - Anthropic: tool_result content arrays accept `image` / `image_url`
20
- * blocks; LangChain's anthropic adapter at
21
- * `node_modules/@langchain/anthropic/dist/utils/message_inputs.js`
22
- * converts them to native `image` source blocks.
23
- * - OpenAI Chat Completions: image_url blocks in tool messages are
24
- * accepted on vision-capable models.
25
- * - OpenAI Responses API: tool messages are flattened to plain text;
26
- * image_url blocks degrade to a JSON description (still useful as
27
- * a textual hint to the model).
28
- * - Google: image blocks in tool responses are accepted on Gemini
29
- * vision models.
30
- *
31
- * Configuration:
32
- * - `local.attachReadAttachments` (default `'images-only'`) controls
33
- * which file kinds are returned as inline attachments. Other kinds
34
- * fall through to the existing binary-stub path.
35
- * - `local.maxAttachmentBytes` (default 5 MB) caps the pre-encoding
36
- * size; oversize attachments degrade to a stub describing the
37
- * refusal so the model isn't surprised.
38
- */
4
+ * Detects whether a file on disk is an LLM-renderable attachment
5
+ * (image / PDF) and produces the LangChain `MessageContentComplex[]`
6
+ * payload a `ToolMessage` needs to actually surface those bytes to
7
+ * the vision-capable model.
8
+ *
9
+ * Same approach as LibreChat's `api/server/utils/files.js`: sniff the
10
+ * magic bytes (NOT the extension) so a mislabelled `.png` that's
11
+ * really a binary blob doesn't get embedded as an image. Inlined for
12
+ * the five formats we actually care about (PNG / JPEG / GIF / WebP /
13
+ * PDF) instead of pulling the ESM-only `file-type` package — keeps
14
+ * the test setup CJS-clean.
15
+ *
16
+ * Provider compatibility:
17
+ * - Anthropic: tool_result content arrays accept `image` / `image_url`
18
+ * blocks; LangChain's anthropic adapter at
19
+ * `node_modules/@langchain/anthropic/dist/utils/message_inputs.js`
20
+ * converts them to native `image` source blocks.
21
+ * - OpenAI Chat Completions: image_url blocks in tool messages are
22
+ * accepted on vision-capable models.
23
+ * - OpenAI Responses API: tool messages are flattened to plain text;
24
+ * image_url blocks degrade to a JSON description (still useful as
25
+ * a textual hint to the model).
26
+ * - Google: image blocks in tool responses are accepted on Gemini
27
+ * vision models.
28
+ *
29
+ * Configuration:
30
+ * - `local.attachReadAttachments` (default `'images-only'`) controls
31
+ * which file kinds are returned as inline attachments. Other kinds
32
+ * fall through to the existing binary-stub path.
33
+ * - `local.maxAttachmentBytes` (default 5 MB) caps the pre-encoding
34
+ * size; oversize attachments degrade to a stub describing the
35
+ * refusal so the model isn't surprised.
36
+ */
39
37
  /**
40
- * Magic-byte sniff for the small set of image/PDF formats we care
41
- * about. We avoided pulling in `file-type` (ESM-only, awkward under
42
- * ts-jest) since the universe of attachments we want to embed is
43
- * tiny: PNG, JPEG, GIF, WebP, PDF. All have well-known signatures in
44
- * the first 12 bytes.
45
- *
46
- * Returns `undefined` on no match — caller treats as text/unknown.
47
- */
38
+ * Magic-byte sniff for the small set of image/PDF formats we care
39
+ * about. We avoided pulling in `file-type` (ESM-only, awkward under
40
+ * ts-jest) since the universe of attachments we want to embed is
41
+ * tiny: PNG, JPEG, GIF, WebP, PDF. All have well-known signatures in
42
+ * the first 12 bytes.
43
+ *
44
+ * Returns `undefined` on no match — caller treats as text/unknown.
45
+ */
48
46
  function sniffMime(buffer) {
49
- if (buffer.length < 4)
50
- return undefined;
51
- // PNG: 89 50 4E 47 0D 0A 1A 0A
52
- if (buffer.length >= 8 &&
53
- buffer[0] === 0x89 &&
54
- buffer[1] === 0x50 &&
55
- buffer[2] === 0x4e &&
56
- buffer[3] === 0x47 &&
57
- buffer[4] === 0x0d &&
58
- buffer[5] === 0x0a &&
59
- buffer[6] === 0x1a &&
60
- buffer[7] === 0x0a) {
61
- return 'image/png';
62
- }
63
- // JPEG: FF D8 FF
64
- if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
65
- return 'image/jpeg';
66
- }
67
- // GIF: "GIF87a" or "GIF89a"
68
- if (buffer.length >= 6 &&
69
- buffer[0] === 0x47 &&
70
- buffer[1] === 0x49 &&
71
- buffer[2] === 0x46 &&
72
- buffer[3] === 0x38 &&
73
- (buffer[4] === 0x37 || buffer[4] === 0x39) &&
74
- buffer[5] === 0x61) {
75
- return 'image/gif';
76
- }
77
- // WebP: "RIFF" .... "WEBP"
78
- if (buffer.length >= 12 &&
79
- buffer[0] === 0x52 &&
80
- buffer[1] === 0x49 &&
81
- buffer[2] === 0x46 &&
82
- buffer[3] === 0x46 &&
83
- buffer[8] === 0x57 &&
84
- buffer[9] === 0x45 &&
85
- buffer[10] === 0x42 &&
86
- buffer[11] === 0x50) {
87
- return 'image/webp';
88
- }
89
- // PDF: "%PDF-"
90
- if (buffer.length >= 5 &&
91
- buffer[0] === 0x25 &&
92
- buffer[1] === 0x50 &&
93
- buffer[2] === 0x44 &&
94
- buffer[3] === 0x46 &&
95
- buffer[4] === 0x2d) {
96
- return 'application/pdf';
97
- }
98
- return undefined;
47
+ if (buffer.length < 4) return void 0;
48
+ if (buffer.length >= 8 && buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78 && buffer[3] === 71 && buffer[4] === 13 && buffer[5] === 10 && buffer[6] === 26 && buffer[7] === 10) return "image/png";
49
+ if (buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) return "image/jpeg";
50
+ if (buffer.length >= 6 && buffer[0] === 71 && buffer[1] === 73 && buffer[2] === 70 && buffer[3] === 56 && (buffer[4] === 55 || buffer[4] === 57) && buffer[5] === 97) return "image/gif";
51
+ if (buffer.length >= 12 && buffer[0] === 82 && buffer[1] === 73 && buffer[2] === 70 && buffer[3] === 70 && buffer[8] === 87 && buffer[9] === 69 && buffer[10] === 66 && buffer[11] === 80) return "image/webp";
52
+ if (buffer.length >= 5 && buffer[0] === 37 && buffer[1] === 80 && buffer[2] === 68 && buffer[3] === 70 && buffer[4] === 45) return "application/pdf";
99
53
  }
100
54
  const SUPPORTED_IMAGE_MIMES = new Set([
101
- 'image/png',
102
- 'image/jpeg',
103
- 'image/gif',
104
- 'image/webp',
55
+ "image/png",
56
+ "image/jpeg",
57
+ "image/gif",
58
+ "image/webp"
105
59
  ]);
106
60
  async function classifyAttachment(args) {
107
- if (args.bytes === 0) {
108
- return { kind: 'text-or-unknown', bytes: 0 };
109
- }
110
- // MIME sniffing only needs the first 12 bytes — read just the
111
- // header so a 9 MB PNG (under the 10 MB read cap, over the 5 MB
112
- // attachment cap) doesn't pull the whole buffer into memory before
113
- // we discover it's oversize. Full read happens only when we're
114
- // about to base64-embed.
115
- const open = args.fs?.open ?? promises.open;
116
- const handle = await open(args.path, 'r');
117
- const header = Buffer.alloc(12);
118
- let mime;
119
- try {
120
- await handle.read(header, 0, 12, 0);
121
- mime = sniffMime(header);
122
- }
123
- finally {
124
- await handle.close();
125
- }
126
- if (mime == null) {
127
- return { kind: 'text-or-unknown', bytes: args.bytes };
128
- }
129
- const wantsImage = args.mode === 'images-only' || args.mode === 'images-and-pdf';
130
- const wantsPdf = args.mode === 'images-and-pdf';
131
- const isImage = wantsImage && SUPPORTED_IMAGE_MIMES.has(mime);
132
- const isPdf = wantsPdf && mime === 'application/pdf';
133
- if (!isImage && !isPdf) {
134
- // Both branches returned identical values pre-fix (audit-of-audit
135
- // finding #3). The SUPPORTED_ATTACHMENT_MIMES check was dead code —
136
- // collapsing to a single return.
137
- return { kind: 'binary', mime, bytes: args.bytes };
138
- }
139
- if (args.bytes > args.maxBytes) {
140
- return {
141
- kind: 'oversize',
142
- mime,
143
- bytes: args.bytes,
144
- maxBytes: args.maxBytes,
145
- };
146
- }
147
- const readFile = args.fs?.readFile ?? promises.readFile;
148
- const buffer = (await readFile(args.path));
149
- const base64 = buffer.toString('base64');
150
- const dataUrl = `data:${mime};base64,${base64}`;
151
- if (isImage) {
152
- return { kind: 'image', mime, bytes: args.bytes, dataUrl };
153
- }
154
- return {
155
- kind: 'pdf',
156
- mime: 'application/pdf',
157
- bytes: args.bytes,
158
- dataUrl,
159
- };
61
+ if (args.bytes === 0) return {
62
+ kind: "text-or-unknown",
63
+ bytes: 0
64
+ };
65
+ const handle = await (args.fs?.open ?? fs_promises.open)(args.path, "r");
66
+ const header = Buffer.alloc(12);
67
+ let mime;
68
+ try {
69
+ await handle.read(header, 0, 12, 0);
70
+ mime = sniffMime(header);
71
+ } finally {
72
+ await handle.close();
73
+ }
74
+ if (mime == null) return {
75
+ kind: "text-or-unknown",
76
+ bytes: args.bytes
77
+ };
78
+ const wantsImage = args.mode === "images-only" || args.mode === "images-and-pdf";
79
+ const wantsPdf = args.mode === "images-and-pdf";
80
+ const isImage = wantsImage && SUPPORTED_IMAGE_MIMES.has(mime);
81
+ if (!isImage && !(wantsPdf && mime === "application/pdf")) return {
82
+ kind: "binary",
83
+ mime,
84
+ bytes: args.bytes
85
+ };
86
+ if (args.bytes > args.maxBytes) return {
87
+ kind: "oversize",
88
+ mime,
89
+ bytes: args.bytes,
90
+ maxBytes: args.maxBytes
91
+ };
92
+ const base64 = (await (args.fs?.readFile ?? fs_promises.readFile)(args.path)).toString("base64");
93
+ const dataUrl = `data:${mime};base64,${base64}`;
94
+ if (isImage) return {
95
+ kind: "image",
96
+ mime,
97
+ bytes: args.bytes,
98
+ dataUrl
99
+ };
100
+ return {
101
+ kind: "pdf",
102
+ mime: "application/pdf",
103
+ bytes: args.bytes,
104
+ dataUrl
105
+ };
160
106
  }
161
107
  /** Build the LangChain content array for an image attachment. */
162
108
  function imageAttachmentContent(path, attachment) {
163
- return [
164
- {
165
- type: 'text',
166
- text: `Read ${path} (${attachment.mime}, ${attachment.bytes} bytes). ` +
167
- 'The image is attached below for vision-capable models.',
168
- },
169
- {
170
- type: 'image_url',
171
- image_url: { url: attachment.dataUrl },
172
- },
173
- ];
109
+ return [{
110
+ type: "text",
111
+ text: `Read ${path} (${attachment.mime}, ${attachment.bytes} bytes). The image is attached below for vision-capable models.`
112
+ }, {
113
+ type: "image_url",
114
+ image_url: { url: attachment.dataUrl }
115
+ }];
174
116
  }
175
-
117
+ //#endregion
176
118
  exports.classifyAttachment = classifyAttachment;
177
119
  exports.imageAttachmentContent = imageAttachmentContent;
178
- //# sourceMappingURL=attachments.cjs.map
120
+
121
+ //# sourceMappingURL=attachments.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"attachments.cjs","sources":["../../../../src/tools/local/attachments.ts"],"sourcesContent":["/**\n * Detects whether a file on disk is an LLM-renderable attachment\n * (image / PDF) and produces the LangChain `MessageContentComplex[]`\n * payload a `ToolMessage` needs to actually surface those bytes to\n * the vision-capable model.\n *\n * Same approach as LibreChat's `api/server/utils/files.js`: sniff the\n * magic bytes (NOT the extension) so a mislabelled `.png` that's\n * really a binary blob doesn't get embedded as an image. Inlined for\n * the five formats we actually care about (PNG / JPEG / GIF / WebP /\n * PDF) instead of pulling the ESM-only `file-type` package — keeps\n * the test setup CJS-clean.\n *\n * Provider compatibility:\n * - Anthropic: tool_result content arrays accept `image` / `image_url`\n * blocks; LangChain's anthropic adapter at\n * `node_modules/@langchain/anthropic/dist/utils/message_inputs.js`\n * converts them to native `image` source blocks.\n * - OpenAI Chat Completions: image_url blocks in tool messages are\n * accepted on vision-capable models.\n * - OpenAI Responses API: tool messages are flattened to plain text;\n * image_url blocks degrade to a JSON description (still useful as\n * a textual hint to the model).\n * - Google: image blocks in tool responses are accepted on Gemini\n * vision models.\n *\n * Configuration:\n * - `local.attachReadAttachments` (default `'images-only'`) controls\n * which file kinds are returned as inline attachments. Other kinds\n * fall through to the existing binary-stub path.\n * - `local.maxAttachmentBytes` (default 5 MB) caps the pre-encoding\n * size; oversize attachments degrade to a stub describing the\n * refusal so the model isn't surprised.\n */\n\nimport { open as fsOpen, readFile as fsReadFile } from 'fs/promises';\nimport type { WorkspaceFS } from './workspaceFS';\n\n/**\n * Magic-byte sniff for the small set of image/PDF formats we care\n * about. We avoided pulling in `file-type` (ESM-only, awkward under\n * ts-jest) since the universe of attachments we want to embed is\n * tiny: PNG, JPEG, GIF, WebP, PDF. All have well-known signatures in\n * the first 12 bytes.\n *\n * Returns `undefined` on no match — caller treats as text/unknown.\n */\nfunction sniffMime(buffer: Buffer): string | undefined {\n if (buffer.length < 4) return undefined;\n // PNG: 89 50 4E 47 0D 0A 1A 0A\n if (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n ) {\n return 'image/png';\n }\n // JPEG: FF D8 FF\n if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {\n return 'image/jpeg';\n }\n // GIF: \"GIF87a\" or \"GIF89a\"\n if (\n buffer.length >= 6 &&\n buffer[0] === 0x47 &&\n buffer[1] === 0x49 &&\n buffer[2] === 0x46 &&\n buffer[3] === 0x38 &&\n (buffer[4] === 0x37 || buffer[4] === 0x39) &&\n buffer[5] === 0x61\n ) {\n return 'image/gif';\n }\n // WebP: \"RIFF\" .... \"WEBP\"\n if (\n buffer.length >= 12 &&\n buffer[0] === 0x52 &&\n buffer[1] === 0x49 &&\n buffer[2] === 0x46 &&\n buffer[3] === 0x46 &&\n buffer[8] === 0x57 &&\n buffer[9] === 0x45 &&\n buffer[10] === 0x42 &&\n buffer[11] === 0x50\n ) {\n return 'image/webp';\n }\n // PDF: \"%PDF-\"\n if (\n buffer.length >= 5 &&\n buffer[0] === 0x25 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x44 &&\n buffer[3] === 0x46 &&\n buffer[4] === 0x2d\n ) {\n return 'application/pdf';\n }\n return undefined;\n}\n\nconst SUPPORTED_IMAGE_MIMES = new Set<string>([\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n]);\n\nexport type AttachmentMode = 'images-only' | 'images-and-pdf' | 'off';\n\nexport type Attachment =\n | {\n kind: 'image';\n mime: string;\n bytes: number;\n dataUrl: string;\n }\n | {\n kind: 'pdf';\n mime: 'application/pdf';\n bytes: number;\n dataUrl: string;\n }\n | {\n kind: 'binary';\n mime: string;\n bytes: number;\n }\n | {\n kind: 'oversize';\n mime: string;\n bytes: number;\n maxBytes: number;\n }\n | {\n kind: 'text-or-unknown';\n bytes: number;\n };\n\nexport async function classifyAttachment(args: {\n path: string;\n bytes: number;\n mode: AttachmentMode;\n maxBytes: number;\n /**\n * WorkspaceFS to route I/O through — defaults to host fs/promises\n * for backward compat. Manual review (finding F): without this\n * routing, custom/remote FS implementations could either fail to\n * embed valid attachments or accidentally read a host path with\n * the same absolute name (since `read_file` itself does go through\n * the configured WorkspaceFS).\n */\n fs?: WorkspaceFS;\n}): Promise<Attachment> {\n if (args.bytes === 0) {\n return { kind: 'text-or-unknown', bytes: 0 };\n }\n\n // MIME sniffing only needs the first 12 bytes — read just the\n // header so a 9 MB PNG (under the 10 MB read cap, over the 5 MB\n // attachment cap) doesn't pull the whole buffer into memory before\n // we discover it's oversize. Full read happens only when we're\n // about to base64-embed.\n const open = args.fs?.open ?? fsOpen;\n const handle = await open(args.path, 'r');\n const header = Buffer.alloc(12);\n let mime: string | undefined;\n try {\n await handle.read(header, 0, 12, 0);\n mime = sniffMime(header);\n } finally {\n await handle.close();\n }\n\n if (mime == null) {\n return { kind: 'text-or-unknown', bytes: args.bytes };\n }\n\n const wantsImage =\n args.mode === 'images-only' || args.mode === 'images-and-pdf';\n const wantsPdf = args.mode === 'images-and-pdf';\n\n const isImage = wantsImage && SUPPORTED_IMAGE_MIMES.has(mime);\n const isPdf = wantsPdf && mime === 'application/pdf';\n\n if (!isImage && !isPdf) {\n // Both branches returned identical values pre-fix (audit-of-audit\n // finding #3). The SUPPORTED_ATTACHMENT_MIMES check was dead code —\n // collapsing to a single return.\n return { kind: 'binary', mime, bytes: args.bytes };\n }\n\n if (args.bytes > args.maxBytes) {\n return {\n kind: 'oversize',\n mime,\n bytes: args.bytes,\n maxBytes: args.maxBytes,\n };\n }\n\n const readFile = args.fs?.readFile ?? fsReadFile;\n const buffer = (await readFile(args.path)) as Buffer;\n const base64 = buffer.toString('base64');\n const dataUrl = `data:${mime};base64,${base64}`;\n\n if (isImage) {\n return { kind: 'image', mime, bytes: args.bytes, dataUrl };\n }\n return {\n kind: 'pdf',\n mime: 'application/pdf' as const,\n bytes: args.bytes,\n dataUrl,\n };\n}\n\n/** Build the LangChain content array for an image attachment. */\nexport function imageAttachmentContent(\n path: string,\n attachment: Extract<Attachment, { kind: 'image' }>\n): Array<{\n type: 'text' | 'image_url';\n text?: string;\n image_url?: { url: string };\n}> {\n return [\n {\n type: 'text',\n text:\n `Read ${path} (${attachment.mime}, ${attachment.bytes} bytes). ` +\n 'The image is attached below for vision-capable models.',\n },\n {\n type: 'image_url',\n image_url: { url: attachment.dataUrl },\n },\n ];\n}\n"],"names":["fsOpen","fsReadFile"],"mappings":"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"}
1
+ {"version":3,"file":"attachments.cjs","names":["fsOpen","fsReadFile"],"sources":["../../../../src/tools/local/attachments.ts"],"sourcesContent":["/**\n * Detects whether a file on disk is an LLM-renderable attachment\n * (image / PDF) and produces the LangChain `MessageContentComplex[]`\n * payload a `ToolMessage` needs to actually surface those bytes to\n * the vision-capable model.\n *\n * Same approach as LibreChat's `api/server/utils/files.js`: sniff the\n * magic bytes (NOT the extension) so a mislabelled `.png` that's\n * really a binary blob doesn't get embedded as an image. Inlined for\n * the five formats we actually care about (PNG / JPEG / GIF / WebP /\n * PDF) instead of pulling the ESM-only `file-type` package — keeps\n * the test setup CJS-clean.\n *\n * Provider compatibility:\n * - Anthropic: tool_result content arrays accept `image` / `image_url`\n * blocks; LangChain's anthropic adapter at\n * `node_modules/@langchain/anthropic/dist/utils/message_inputs.js`\n * converts them to native `image` source blocks.\n * - OpenAI Chat Completions: image_url blocks in tool messages are\n * accepted on vision-capable models.\n * - OpenAI Responses API: tool messages are flattened to plain text;\n * image_url blocks degrade to a JSON description (still useful as\n * a textual hint to the model).\n * - Google: image blocks in tool responses are accepted on Gemini\n * vision models.\n *\n * Configuration:\n * - `local.attachReadAttachments` (default `'images-only'`) controls\n * which file kinds are returned as inline attachments. Other kinds\n * fall through to the existing binary-stub path.\n * - `local.maxAttachmentBytes` (default 5 MB) caps the pre-encoding\n * size; oversize attachments degrade to a stub describing the\n * refusal so the model isn't surprised.\n */\n\nimport { open as fsOpen, readFile as fsReadFile } from 'fs/promises';\nimport type { WorkspaceFS } from './workspaceFS';\n\n/**\n * Magic-byte sniff for the small set of image/PDF formats we care\n * about. We avoided pulling in `file-type` (ESM-only, awkward under\n * ts-jest) since the universe of attachments we want to embed is\n * tiny: PNG, JPEG, GIF, WebP, PDF. All have well-known signatures in\n * the first 12 bytes.\n *\n * Returns `undefined` on no match — caller treats as text/unknown.\n */\nfunction sniffMime(buffer: Buffer): string | undefined {\n if (buffer.length < 4) return undefined;\n // PNG: 89 50 4E 47 0D 0A 1A 0A\n if (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n ) {\n return 'image/png';\n }\n // JPEG: FF D8 FF\n if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {\n return 'image/jpeg';\n }\n // GIF: \"GIF87a\" or \"GIF89a\"\n if (\n buffer.length >= 6 &&\n buffer[0] === 0x47 &&\n buffer[1] === 0x49 &&\n buffer[2] === 0x46 &&\n buffer[3] === 0x38 &&\n (buffer[4] === 0x37 || buffer[4] === 0x39) &&\n buffer[5] === 0x61\n ) {\n return 'image/gif';\n }\n // WebP: \"RIFF\" .... \"WEBP\"\n if (\n buffer.length >= 12 &&\n buffer[0] === 0x52 &&\n buffer[1] === 0x49 &&\n buffer[2] === 0x46 &&\n buffer[3] === 0x46 &&\n buffer[8] === 0x57 &&\n buffer[9] === 0x45 &&\n buffer[10] === 0x42 &&\n buffer[11] === 0x50\n ) {\n return 'image/webp';\n }\n // PDF: \"%PDF-\"\n if (\n buffer.length >= 5 &&\n buffer[0] === 0x25 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x44 &&\n buffer[3] === 0x46 &&\n buffer[4] === 0x2d\n ) {\n return 'application/pdf';\n }\n return undefined;\n}\n\nconst SUPPORTED_IMAGE_MIMES = new Set<string>([\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n]);\n\nexport type AttachmentMode = 'images-only' | 'images-and-pdf' | 'off';\n\nexport type Attachment =\n | {\n kind: 'image';\n mime: string;\n bytes: number;\n dataUrl: string;\n }\n | {\n kind: 'pdf';\n mime: 'application/pdf';\n bytes: number;\n dataUrl: string;\n }\n | {\n kind: 'binary';\n mime: string;\n bytes: number;\n }\n | {\n kind: 'oversize';\n mime: string;\n bytes: number;\n maxBytes: number;\n }\n | {\n kind: 'text-or-unknown';\n bytes: number;\n };\n\nexport async function classifyAttachment(args: {\n path: string;\n bytes: number;\n mode: AttachmentMode;\n maxBytes: number;\n /**\n * WorkspaceFS to route I/O through — defaults to host fs/promises\n * for backward compat. Manual review (finding F): without this\n * routing, custom/remote FS implementations could either fail to\n * embed valid attachments or accidentally read a host path with\n * the same absolute name (since `read_file` itself does go through\n * the configured WorkspaceFS).\n */\n fs?: WorkspaceFS;\n}): Promise<Attachment> {\n if (args.bytes === 0) {\n return { kind: 'text-or-unknown', bytes: 0 };\n }\n\n // MIME sniffing only needs the first 12 bytes — read just the\n // header so a 9 MB PNG (under the 10 MB read cap, over the 5 MB\n // attachment cap) doesn't pull the whole buffer into memory before\n // we discover it's oversize. Full read happens only when we're\n // about to base64-embed.\n const open = args.fs?.open ?? fsOpen;\n const handle = await open(args.path, 'r');\n const header = Buffer.alloc(12);\n let mime: string | undefined;\n try {\n await handle.read(header, 0, 12, 0);\n mime = sniffMime(header);\n } finally {\n await handle.close();\n }\n\n if (mime == null) {\n return { kind: 'text-or-unknown', bytes: args.bytes };\n }\n\n const wantsImage =\n args.mode === 'images-only' || args.mode === 'images-and-pdf';\n const wantsPdf = args.mode === 'images-and-pdf';\n\n const isImage = wantsImage && SUPPORTED_IMAGE_MIMES.has(mime);\n const isPdf = wantsPdf && mime === 'application/pdf';\n\n if (!isImage && !isPdf) {\n // Both branches returned identical values pre-fix (audit-of-audit\n // finding #3). The SUPPORTED_ATTACHMENT_MIMES check was dead code —\n // collapsing to a single return.\n return { kind: 'binary', mime, bytes: args.bytes };\n }\n\n if (args.bytes > args.maxBytes) {\n return {\n kind: 'oversize',\n mime,\n bytes: args.bytes,\n maxBytes: args.maxBytes,\n };\n }\n\n const readFile = args.fs?.readFile ?? fsReadFile;\n const buffer = (await readFile(args.path)) as Buffer;\n const base64 = buffer.toString('base64');\n const dataUrl = `data:${mime};base64,${base64}`;\n\n if (isImage) {\n return { kind: 'image', mime, bytes: args.bytes, dataUrl };\n }\n return {\n kind: 'pdf',\n mime: 'application/pdf' as const,\n bytes: args.bytes,\n dataUrl,\n };\n}\n\n/** Build the LangChain content array for an image attachment. */\nexport function imageAttachmentContent(\n path: string,\n attachment: Extract<Attachment, { kind: 'image' }>\n): Array<{\n type: 'text' | 'image_url';\n text?: string;\n image_url?: { url: string };\n}> {\n return [\n {\n type: 'text',\n text:\n `Read ${path} (${attachment.mime}, ${attachment.bytes} bytes). ` +\n 'The image is attached below for vision-capable models.',\n },\n {\n type: 'image_url',\n image_url: { url: attachment.dataUrl },\n },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAS,UAAU,QAAoC;CACrD,IAAI,OAAO,SAAS,GAAG,OAAO,KAAA;CAE9B,IACE,OAAO,UAAU,KACjB,OAAO,OAAO,OACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,IAEd,OAAO;CAGT,IAAI,OAAO,OAAO,OAAQ,OAAO,OAAO,OAAQ,OAAO,OAAO,KAC5D,OAAO;CAGT,IACE,OAAO,UAAU,KACjB,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,OACb,OAAO,OAAO,MAAQ,OAAO,OAAO,OACrC,OAAO,OAAO,IAEd,OAAO;CAGT,IACE,OAAO,UAAU,MACjB,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,QAAQ,MACf,OAAO,QAAQ,IAEf,OAAO;CAGT,IACE,OAAO,UAAU,KACjB,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,MACd,OAAO,OAAO,IAEd,OAAO;AAGX;AAEA,MAAM,wBAAwB,IAAI,IAAY;CAC5C;CACA;CACA;CACA;AACF,CAAC;AAiCD,eAAsB,mBAAmB,MAcjB;CACtB,IAAI,KAAK,UAAU,GACjB,OAAO;EAAE,MAAM;EAAmB,OAAO;CAAE;CAS7C,MAAM,SAAS,OADF,KAAK,IAAI,QAAQA,YAAAA,KAAAA,CACJ,KAAK,MAAM,GAAG;CACxC,MAAM,SAAS,OAAO,MAAM,EAAE;CAC9B,IAAI;CACJ,IAAI;EACF,MAAM,OAAO,KAAK,QAAQ,GAAG,IAAI,CAAC;EAClC,OAAO,UAAU,MAAM;CACzB,UAAU;EACR,MAAM,OAAO,MAAM;CACrB;CAEA,IAAI,QAAQ,MACV,OAAO;EAAE,MAAM;EAAmB,OAAO,KAAK;CAAM;CAGtD,MAAM,aACJ,KAAK,SAAS,iBAAiB,KAAK,SAAS;CAC/C,MAAM,WAAW,KAAK,SAAS;CAE/B,MAAM,UAAU,cAAc,sBAAsB,IAAI,IAAI;CAG5D,IAAI,CAAC,WAAW,EAFF,YAAY,SAAS,oBAMjC,OAAO;EAAE,MAAM;EAAU;EAAM,OAAO,KAAK;CAAM;CAGnD,IAAI,KAAK,QAAQ,KAAK,UACpB,OAAO;EACL,MAAM;EACN;EACA,OAAO,KAAK;EACZ,UAAU,KAAK;CACjB;CAKF,MAAM,UAAS,OAFE,KAAK,IAAI,YAAYC,YAAAA,SAAAA,CACP,KAAK,IAAI,EAAA,CAClB,SAAS,QAAQ;CACvC,MAAM,UAAU,QAAQ,KAAK,UAAU;CAEvC,IAAI,SACF,OAAO;EAAE,MAAM;EAAS;EAAM,OAAO,KAAK;EAAO;CAAQ;CAE3D,OAAO;EACL,MAAM;EACN,MAAM;EACN,OAAO,KAAK;EACZ;CACF;AACF;;AAGA,SAAgB,uBACd,MACA,YAKC;CACD,OAAO,CACL;EACE,MAAM;EACN,MACE,QAAQ,KAAK,IAAI,WAAW,KAAK,IAAI,WAAW,MAAM;CAE1D,GACA;EACE,MAAM;EACN,WAAW,EAAE,KAAK,WAAW,QAAQ;CACvC,CACF;AACF"}