@librechat/agents 3.2.21 → 3.2.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +3 -2
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/events.cjs.map +1 -1
  4. package/dist/cjs/graphs/Graph.cjs +200 -54
  5. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +13 -7
  8. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -1
  9. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  10. package/dist/cjs/hooks/types.cjs.map +1 -1
  11. package/dist/cjs/instrumentation.cjs +2 -2
  12. package/dist/cjs/instrumentation.cjs.map +1 -1
  13. package/dist/cjs/langfuse.cjs +17 -1
  14. package/dist/cjs/langfuse.cjs.map +1 -1
  15. package/dist/cjs/langfuseToolOutputTracing.cjs +2 -2
  16. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  17. package/dist/cjs/llm/anthropic/index.cjs +1 -1
  18. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  19. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  20. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +1 -1
  21. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  22. package/dist/cjs/llm/bedrock/index.cjs +2 -2
  23. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  24. package/dist/cjs/llm/bedrock/toolCache.cjs +8 -5
  25. package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
  26. package/dist/cjs/llm/fake.cjs +16 -14
  27. package/dist/cjs/llm/fake.cjs.map +1 -1
  28. package/dist/cjs/llm/google/index.cjs +22 -0
  29. package/dist/cjs/llm/google/index.cjs.map +1 -1
  30. package/dist/cjs/llm/google/utils/common.cjs +88 -27
  31. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  32. package/dist/cjs/llm/init.cjs +2 -2
  33. package/dist/cjs/llm/invoke.cjs +108 -11
  34. package/dist/cjs/llm/invoke.cjs.map +1 -1
  35. package/dist/cjs/llm/openai/index.cjs +1 -1
  36. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  37. package/dist/cjs/llm/openai/utils/index.cjs +1 -1
  38. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  39. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  40. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  41. package/dist/cjs/main.cjs +1 -0
  42. package/dist/cjs/main.cjs.map +1 -1
  43. package/dist/cjs/messages/cache.cjs +8 -7
  44. package/dist/cjs/messages/cache.cjs.map +1 -1
  45. package/dist/cjs/messages/content.cjs.map +1 -1
  46. package/dist/cjs/messages/contextPruning.cjs.map +1 -1
  47. package/dist/cjs/messages/format.cjs +124 -17
  48. package/dist/cjs/messages/format.cjs.map +1 -1
  49. package/dist/cjs/messages/prune.cjs.map +1 -1
  50. package/dist/cjs/messages/reducer.cjs +1 -1
  51. package/dist/cjs/messages/reducer.cjs.map +1 -1
  52. package/dist/cjs/messages/tools.cjs +1 -1
  53. package/dist/cjs/messages/tools.cjs.map +1 -1
  54. package/dist/cjs/openai/index.cjs.map +1 -1
  55. package/dist/cjs/responses/index.cjs.map +1 -1
  56. package/dist/cjs/run.cjs +41 -20
  57. package/dist/cjs/run.cjs.map +1 -1
  58. package/dist/cjs/session/AgentSession.cjs +4 -4
  59. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  60. package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
  61. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  62. package/dist/cjs/session/handlers.cjs +2 -2
  63. package/dist/cjs/session/handlers.cjs.map +1 -1
  64. package/dist/cjs/stream.cjs +248 -25
  65. package/dist/cjs/stream.cjs.map +1 -1
  66. package/dist/cjs/summarization/node.cjs.map +1 -1
  67. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +1 -1
  68. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  69. package/dist/cjs/tools/Calculator.cjs +1 -1
  70. package/dist/cjs/tools/Calculator.cjs.map +1 -1
  71. package/dist/cjs/tools/CodeExecutor.cjs +1 -1
  72. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  73. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  74. package/dist/cjs/tools/ToolNode.cjs +37 -18
  75. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  76. package/dist/cjs/tools/ToolSearch.cjs +1 -1
  77. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  78. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +7 -4
  79. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
  80. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +4 -4
  81. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -1
  82. package/dist/cjs/tools/handlers.cjs +2 -1
  83. package/dist/cjs/tools/handlers.cjs.map +1 -1
  84. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
  85. package/dist/cjs/tools/local/FileCheckpointer.cjs +2 -1
  86. package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -1
  87. package/dist/cjs/tools/local/LocalCodingTools.cjs +45 -19
  88. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
  89. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +3 -3
  90. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
  91. package/dist/cjs/tools/local/LocalExecutionTools.cjs +2 -2
  92. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
  93. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +4 -3
  94. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  95. package/dist/cjs/tools/local/attachments.cjs +0 -5
  96. package/dist/cjs/tools/local/attachments.cjs.map +1 -1
  97. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +4 -4
  98. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
  99. package/dist/cjs/tools/search/firecrawl.cjs +1 -1
  100. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  101. package/dist/cjs/tools/search/rerankers.cjs +7 -3
  102. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  103. package/dist/cjs/tools/search/tavily-search.cjs +1 -1
  104. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
  105. package/dist/cjs/tools/search/utils.cjs +76 -8
  106. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  107. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -1
  108. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  109. package/dist/cjs/utils/handlers.cjs +1 -1
  110. package/dist/cjs/utils/handlers.cjs.map +1 -1
  111. package/dist/cjs/utils/run.cjs +1 -1
  112. package/dist/cjs/utils/run.cjs.map +1 -1
  113. package/dist/esm/agents/AgentContext.mjs +3 -2
  114. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  115. package/dist/esm/events.mjs.map +1 -1
  116. package/dist/esm/graphs/Graph.mjs +200 -54
  117. package/dist/esm/graphs/Graph.mjs.map +1 -1
  118. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  119. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +13 -7
  120. package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -1
  121. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  122. package/dist/esm/hooks/types.mjs.map +1 -1
  123. package/dist/esm/instrumentation.mjs +2 -2
  124. package/dist/esm/instrumentation.mjs.map +1 -1
  125. package/dist/esm/langfuse.mjs +17 -2
  126. package/dist/esm/langfuse.mjs.map +1 -1
  127. package/dist/esm/langfuseToolOutputTracing.mjs +2 -2
  128. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  129. package/dist/esm/llm/anthropic/index.mjs +1 -1
  130. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  131. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  132. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +1 -1
  133. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  134. package/dist/esm/llm/bedrock/index.mjs +2 -2
  135. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  136. package/dist/esm/llm/bedrock/toolCache.mjs +8 -5
  137. package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
  138. package/dist/esm/llm/fake.mjs +16 -14
  139. package/dist/esm/llm/fake.mjs.map +1 -1
  140. package/dist/esm/llm/google/index.mjs +23 -1
  141. package/dist/esm/llm/google/index.mjs.map +1 -1
  142. package/dist/esm/llm/google/utils/common.mjs +88 -27
  143. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  144. package/dist/esm/llm/init.mjs +2 -2
  145. package/dist/esm/llm/invoke.mjs +104 -7
  146. package/dist/esm/llm/invoke.mjs.map +1 -1
  147. package/dist/esm/llm/openai/index.mjs +1 -1
  148. package/dist/esm/llm/openai/index.mjs.map +1 -1
  149. package/dist/esm/llm/openai/utils/index.mjs +1 -1
  150. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  151. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  152. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  153. package/dist/esm/main.mjs +1 -1
  154. package/dist/esm/messages/cache.mjs +8 -7
  155. package/dist/esm/messages/cache.mjs.map +1 -1
  156. package/dist/esm/messages/content.mjs.map +1 -1
  157. package/dist/esm/messages/contextPruning.mjs.map +1 -1
  158. package/dist/esm/messages/format.mjs +124 -18
  159. package/dist/esm/messages/format.mjs.map +1 -1
  160. package/dist/esm/messages/prune.mjs.map +1 -1
  161. package/dist/esm/messages/reducer.mjs +1 -1
  162. package/dist/esm/messages/reducer.mjs.map +1 -1
  163. package/dist/esm/messages/tools.mjs +1 -1
  164. package/dist/esm/messages/tools.mjs.map +1 -1
  165. package/dist/esm/openai/index.mjs.map +1 -1
  166. package/dist/esm/responses/index.mjs.map +1 -1
  167. package/dist/esm/run.mjs +41 -20
  168. package/dist/esm/run.mjs.map +1 -1
  169. package/dist/esm/session/AgentSession.mjs +4 -4
  170. package/dist/esm/session/AgentSession.mjs.map +1 -1
  171. package/dist/esm/session/JsonlSessionStore.mjs +2 -2
  172. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  173. package/dist/esm/session/handlers.mjs +2 -2
  174. package/dist/esm/session/handlers.mjs.map +1 -1
  175. package/dist/esm/stream.mjs +248 -25
  176. package/dist/esm/stream.mjs.map +1 -1
  177. package/dist/esm/summarization/node.mjs.map +1 -1
  178. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +1 -1
  179. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  180. package/dist/esm/tools/Calculator.mjs +1 -1
  181. package/dist/esm/tools/Calculator.mjs.map +1 -1
  182. package/dist/esm/tools/CodeExecutor.mjs +1 -1
  183. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  184. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  185. package/dist/esm/tools/ToolNode.mjs +37 -18
  186. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  187. package/dist/esm/tools/ToolSearch.mjs +1 -1
  188. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  189. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +7 -4
  190. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
  191. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +4 -4
  192. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -1
  193. package/dist/esm/tools/handlers.mjs +2 -1
  194. package/dist/esm/tools/handlers.mjs.map +1 -1
  195. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
  196. package/dist/esm/tools/local/FileCheckpointer.mjs +2 -1
  197. package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -1
  198. package/dist/esm/tools/local/LocalCodingTools.mjs +45 -19
  199. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
  200. package/dist/esm/tools/local/LocalExecutionEngine.mjs +3 -3
  201. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
  202. package/dist/esm/tools/local/LocalExecutionTools.mjs +2 -2
  203. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
  204. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +4 -3
  205. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  206. package/dist/esm/tools/local/attachments.mjs +0 -5
  207. package/dist/esm/tools/local/attachments.mjs.map +1 -1
  208. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +4 -4
  209. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
  210. package/dist/esm/tools/search/firecrawl.mjs +1 -1
  211. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  212. package/dist/esm/tools/search/rerankers.mjs +8 -4
  213. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  214. package/dist/esm/tools/search/tavily-search.mjs +1 -1
  215. package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
  216. package/dist/esm/tools/search/utils.mjs +76 -9
  217. package/dist/esm/tools/search/utils.mjs.map +1 -1
  218. package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -1
  219. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  220. package/dist/esm/utils/handlers.mjs +1 -1
  221. package/dist/esm/utils/handlers.mjs.map +1 -1
  222. package/dist/esm/utils/run.mjs +1 -1
  223. package/dist/esm/utils/run.mjs.map +1 -1
  224. package/dist/types/agents/__tests__/promptCacheLiveHelpers.d.ts +1 -1
  225. package/dist/types/events.d.ts +1 -1
  226. package/dist/types/graphs/Graph.d.ts +7 -1
  227. package/dist/types/hooks/executeHooks.d.ts +1 -1
  228. package/dist/types/hooks/types.d.ts +5 -0
  229. package/dist/types/langfuse.d.ts +4 -0
  230. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
  231. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -1
  232. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +2 -2
  233. package/dist/types/llm/bedrock/index.d.ts +2 -2
  234. package/dist/types/llm/fake.d.ts +3 -3
  235. package/dist/types/llm/google/index.d.ts +1 -0
  236. package/dist/types/llm/google/types.d.ts +1 -1
  237. package/dist/types/llm/google/utils/common.d.ts +2 -2
  238. package/dist/types/llm/google/utils/tools.d.ts +1 -1
  239. package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +1 -1
  240. package/dist/types/llm/openai/index.d.ts +2 -2
  241. package/dist/types/llm/openai/utils/index.d.ts +1 -1
  242. package/dist/types/llm/openrouter/index.d.ts +4 -4
  243. package/dist/types/messages/contextPruning.d.ts +1 -1
  244. package/dist/types/messages/format.d.ts +9 -4
  245. package/dist/types/messages/prune.d.ts +1 -1
  246. package/dist/types/session/JsonlSessionStore.d.ts +1 -1
  247. package/dist/types/session/handlers.d.ts +1 -1
  248. package/dist/types/session/types.d.ts +1 -1
  249. package/dist/types/summarization/node.d.ts +1 -1
  250. package/dist/types/tools/SubagentTool.d.ts +2 -2
  251. package/dist/types/tools/ToolNode.d.ts +9 -2
  252. package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +1 -1
  253. package/dist/types/tools/search/types.d.ts +1 -1
  254. package/dist/types/tools/search/utils.d.ts +11 -0
  255. package/dist/types/types/graph.d.ts +4 -4
  256. package/dist/types/types/llm.d.ts +4 -3
  257. package/dist/types/types/messages.d.ts +1 -1
  258. package/dist/types/types/run.d.ts +6 -6
  259. package/dist/types/types/stream.d.ts +2 -2
  260. package/dist/types/types/tools.d.ts +5 -1
  261. package/dist/types/utils/handlers.d.ts +2 -2
  262. package/dist/types/utils/run.d.ts +1 -1
  263. package/package.json +6 -3
  264. package/src/__tests__/stream.eagerEventExecution.test.ts +543 -6
  265. package/src/agents/AgentContext.ts +2 -2
  266. package/src/agents/__tests__/AgentContext.test.ts +3 -3
  267. package/src/agents/__tests__/promptCacheLiveHelpers.ts +1 -1
  268. package/src/events.ts +1 -1
  269. package/src/graphs/Graph.ts +329 -72
  270. package/src/graphs/MultiAgentGraph.ts +1 -1
  271. package/src/graphs/__tests__/Graph.reasoning.test.ts +919 -6
  272. package/src/graphs/__tests__/MultiAgentGraph.test.ts +1 -1
  273. package/src/graphs/__tests__/composition.smoke.test.ts +1 -1
  274. package/src/hooks/__tests__/HookRegistry.test.ts +1 -1
  275. package/src/hooks/__tests__/compactHooks.test.ts +8 -8
  276. package/src/hooks/__tests__/createWorkspacePolicyHook.test.ts +34 -22
  277. package/src/hooks/__tests__/executeHooks.test.ts +3 -3
  278. package/src/hooks/__tests__/integration.test.ts +3 -3
  279. package/src/hooks/__tests__/toolHooks.test.ts +10 -10
  280. package/src/hooks/createWorkspacePolicyHook.ts +17 -14
  281. package/src/hooks/executeHooks.ts +1 -1
  282. package/src/hooks/types.ts +5 -0
  283. package/src/instrumentation.ts +11 -11
  284. package/src/langfuse.ts +35 -1
  285. package/src/langfuseToolOutputTracing.ts +2 -2
  286. package/src/llm/anthropic/index.ts +1 -1
  287. package/src/llm/anthropic/utils/message_inputs.ts +1 -1
  288. package/src/llm/anthropic/utils/message_outputs.ts +3 -5
  289. package/src/llm/anthropic/utils/output_parsers.ts +5 -5
  290. package/src/llm/bedrock/index.ts +4 -4
  291. package/src/llm/bedrock/toolCache.test.ts +48 -9
  292. package/src/llm/bedrock/toolCache.ts +11 -6
  293. package/src/llm/fake.ts +30 -25
  294. package/src/llm/google/index.ts +43 -1
  295. package/src/llm/google/llm.spec.ts +173 -1
  296. package/src/llm/google/types.ts +1 -1
  297. package/src/llm/google/utils/common.ts +154 -45
  298. package/src/llm/google/utils/tools.ts +8 -8
  299. package/src/llm/google/utils/zod_to_genai_parameters.ts +4 -4
  300. package/src/llm/invoke.test.ts +3 -3
  301. package/src/llm/invoke.ts +170 -10
  302. package/src/llm/openai/index.ts +4 -4
  303. package/src/llm/openai/utils/index.ts +14 -14
  304. package/src/llm/openrouter/index.ts +4 -4
  305. package/src/llm/openrouter/reasoning.test.ts +2 -2
  306. package/src/llm/vertexai/fixThoughtSignatures.test.ts +1 -1
  307. package/src/llm/vertexai/index.ts +1 -1
  308. package/src/messages/cache.test.ts +22 -0
  309. package/src/messages/cache.ts +25 -12
  310. package/src/messages/content.ts +1 -1
  311. package/src/messages/contextPruning.ts +1 -1
  312. package/src/messages/format.ts +227 -43
  313. package/src/messages/formatAgentMessages.skills.test.ts +105 -26
  314. package/src/messages/formatAgentMessages.test.ts +841 -10
  315. package/src/messages/labelContentByAgent.test.ts +2 -2
  316. package/src/messages/prune.ts +1 -1
  317. package/src/messages/reducer.ts +1 -1
  318. package/src/messages/tools.ts +1 -1
  319. package/src/openai/__tests__/openai.test.ts +2 -2
  320. package/src/openai/index.ts +1 -1
  321. package/src/responses/__tests__/responses.test.ts +2 -2
  322. package/src/responses/index.ts +1 -1
  323. package/src/run.ts +68 -41
  324. package/src/session/AgentSession.ts +6 -6
  325. package/src/session/JsonlSessionStore.ts +3 -3
  326. package/src/session/__tests__/JsonlSessionStore.test.ts +5 -5
  327. package/src/session/__tests__/handlers.test.ts +2 -2
  328. package/src/session/handlers.ts +5 -5
  329. package/src/session/types.ts +1 -1
  330. package/src/specs/agent-handoffs.test.ts +1 -1
  331. package/src/specs/langfuse-callbacks.test.ts +2 -2
  332. package/src/specs/langfuse-metadata.test.ts +39 -0
  333. package/src/specs/langfuse-tool-output-tracing.test.ts +1 -1
  334. package/src/specs/multi-agent-summarization.test.ts +4 -4
  335. package/src/specs/subagent.test.ts +3 -3
  336. package/src/specs/summarization-unit.test.ts +1 -1
  337. package/src/specs/thinking-handoff.test.ts +1 -1
  338. package/src/splitStream.test.ts +48 -0
  339. package/src/stream.test.ts +53 -3
  340. package/src/stream.ts +450 -39
  341. package/src/summarization/__tests__/aggregator.test.ts +2 -2
  342. package/src/summarization/__tests__/node.test.ts +2 -2
  343. package/src/summarization/node.ts +1 -1
  344. package/src/tools/BashProgrammaticToolCalling.ts +5 -5
  345. package/src/tools/Calculator.ts +1 -1
  346. package/src/tools/CodeExecutor.ts +2 -4
  347. package/src/tools/SubagentTool.ts +2 -2
  348. package/src/tools/ToolNode.ts +37 -16
  349. package/src/tools/ToolSearch.ts +1 -1
  350. package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +4 -4
  351. package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +12 -12
  352. package/src/tools/__tests__/LocalExecutionTools.test.ts +125 -93
  353. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +29 -5
  354. package/src/tools/__tests__/ReadFile.test.ts +1 -1
  355. package/src/tools/__tests__/SkillTool.test.ts +4 -4
  356. package/src/tools/__tests__/SubagentExecutor.test.ts +17 -13
  357. package/src/tools/__tests__/SubagentTool.test.ts +2 -2
  358. package/src/tools/__tests__/ToolNode.eagerEventExecution.test.ts +1 -1
  359. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +2 -5
  360. package/src/tools/__tests__/ToolNode.session.test.ts +1 -1
  361. package/src/tools/__tests__/ToolSearch.test.ts +1 -1
  362. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +1 -1
  363. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +35 -32
  364. package/src/tools/__tests__/directToolHooks.test.ts +41 -0
  365. package/src/tools/__tests__/handlers.test.ts +2 -2
  366. package/src/tools/__tests__/hitl.test.ts +11 -11
  367. package/src/tools/__tests__/localToolNames.test.ts +8 -6
  368. package/src/tools/__tests__/skillCatalog.test.ts +1 -1
  369. package/src/tools/__tests__/subagentHooks.test.ts +20 -10
  370. package/src/tools/__tests__/workspaceSeam.test.ts +20 -7
  371. package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +9 -6
  372. package/src/tools/cloudflare/CloudflareSandboxTools.ts +19 -19
  373. package/src/tools/handlers.ts +5 -5
  374. package/src/tools/local/CompileCheckTool.ts +4 -7
  375. package/src/tools/local/FileCheckpointer.ts +6 -5
  376. package/src/tools/local/LocalCodingTools.ts +100 -45
  377. package/src/tools/local/LocalExecutionEngine.ts +5 -5
  378. package/src/tools/local/LocalExecutionTools.ts +9 -9
  379. package/src/tools/local/LocalProgrammaticToolCalling.ts +5 -4
  380. package/src/tools/local/attachments.ts +0 -6
  381. package/src/tools/local/resolveLocalExecutionTools.ts +15 -15
  382. package/src/tools/search/firecrawl.ts +1 -1
  383. package/src/tools/search/jina-reranker.test.ts +148 -37
  384. package/src/tools/search/rerankers.ts +14 -4
  385. package/src/tools/search/tavily-search.ts +2 -2
  386. package/src/tools/search/types.ts +1 -1
  387. package/src/tools/search/utils.ts +99 -9
  388. package/src/tools/subagent/SubagentExecutor.ts +12 -6
  389. package/src/types/graph.ts +12 -12
  390. package/src/types/llm.ts +7 -6
  391. package/src/types/messages.ts +1 -1
  392. package/src/types/run.ts +7 -7
  393. package/src/types/stream.ts +2 -2
  394. package/src/types/tools.ts +5 -1
  395. package/src/utils/handlers.ts +2 -2
  396. package/src/utils/llmConfig.ts +1 -1
  397. package/src/utils/logging.ts +20 -10
  398. package/src/utils/run.ts +2 -2
@@ -2,6 +2,16 @@ import { z } from 'zod';
2
2
  import { tmpdir } from 'os';
3
3
  import { join } from 'path';
4
4
  import { spawnSync } from 'child_process';
5
+ import { tool } from '@langchain/core/tools';
6
+ import { AIMessage, ToolMessage } from '@langchain/core/messages';
7
+ import {
8
+ describe,
9
+ it,
10
+ expect,
11
+ afterEach,
12
+ beforeEach,
13
+ jest,
14
+ } from '@jest/globals';
5
15
  import {
6
16
  mkdtemp,
7
17
  rm,
@@ -9,21 +19,15 @@ import {
9
19
  writeFile as fsWriteFile,
10
20
  readFile as fsReadFile,
11
21
  } from 'fs/promises';
12
- import { tool } from '@langchain/core/tools';
13
- import { AIMessage, ToolMessage } from '@langchain/core/messages';
14
- import type { BaseMessage } from '@langchain/core/messages';
15
- import { describe, it, expect, afterEach, beforeEach, jest } from '@jest/globals';
16
22
  import type { StructuredToolInterface } from '@langchain/core/tools';
23
+ import type { BaseMessage } from '@langchain/core/messages';
17
24
  import type * as t from '@/types';
18
- import { Constants, Providers } from '@/common';
19
- import { ToolNode } from '../ToolNode';
20
25
  import {
21
26
  executeLocalBash,
22
27
  executeLocalCode,
23
28
  validateBashCommand,
24
29
  _resetLocalEngineWarningsForTests,
25
30
  } from '../local/LocalExecutionEngine';
26
- import { resolveLocalToolsForBinding } from '../local/resolveLocalExecutionTools';
27
31
  import {
28
32
  createLocalCodingToolBundle,
29
33
  _resetRipgrepCacheForTests,
@@ -32,9 +36,12 @@ import {
32
36
  runPostEditSyntaxCheck,
33
37
  _resetSyntaxCheckProbeCacheForTests,
34
38
  } from '../local/syntaxCheck';
39
+ import { resolveLocalToolsForBinding } from '../local/resolveLocalExecutionTools';
40
+ import { LocalFileCheckpointerImpl } from '../local/FileCheckpointer';
35
41
  import { createCompileCheckTool } from '../local/CompileCheckTool';
36
42
  import { runBashAstChecks } from '../local/bashAst';
37
- import { LocalFileCheckpointerImpl } from '../local/FileCheckpointer';
43
+ import { Constants, Providers } from '@/common';
44
+ import { ToolNode } from '../ToolNode';
38
45
 
39
46
  const hasPython3 = spawnSync('python3', ['--version']).status === 0;
40
47
 
@@ -47,14 +54,11 @@ async function createTempDir(): Promise<string> {
47
54
  }
48
55
 
49
56
  function createRemoteBashStub(): StructuredToolInterface {
50
- return tool(
51
- async () => 'remote bash should not run',
52
- {
53
- name: Constants.BASH_TOOL,
54
- description: 'Remote bash stub',
55
- schema: z.object({ command: z.string() }),
56
- }
57
- ) as unknown as StructuredToolInterface;
57
+ return tool(async () => 'remote bash should not run', {
58
+ name: Constants.BASH_TOOL,
59
+ description: 'Remote bash stub',
60
+ schema: z.object({ command: z.string() }),
61
+ }) as unknown as StructuredToolInterface;
58
62
  }
59
63
 
60
64
  function messagesFromResult(
@@ -216,7 +220,9 @@ describe('local execution tools', () => {
216
220
  describe('local engine bashAst', () => {
217
221
  it('flags command substitution in auto mode', () => {
218
222
  const findings = runBashAstChecks('echo $(whoami)', 'auto');
219
- expect(findings.some((f) => f.code === 'cmd-subst-dollar-paren')).toBe(true);
223
+ expect(findings.some((f) => f.code === 'cmd-subst-dollar-paren')).toBe(
224
+ true
225
+ );
220
226
  });
221
227
 
222
228
  it('escalates command substitution to deny in strict mode', () => {
@@ -227,7 +233,11 @@ describe('local engine bashAst', () => {
227
233
 
228
234
  it('always denies /proc/<pid>/environ access', () => {
229
235
  const findings = runBashAstChecks('cat /proc/1/environ', 'auto');
230
- expect(findings.some((f) => f.code === 'proc-environ-read' && f.severity === 'deny')).toBe(true);
236
+ expect(
237
+ findings.some(
238
+ (f) => f.code === 'proc-environ-read' && f.severity === 'deny'
239
+ )
240
+ ).toBe(true);
231
241
  });
232
242
 
233
243
  it('never produces findings when off', () => {
@@ -432,8 +442,7 @@ describe('local edit fuzzy matching', () => {
432
442
  // LLM emits a trailing-whitespace-stripped version.
433
443
  old_text:
434
444
  'function greet(name: string) {\n return `Hello, ${name}!`;\n}',
435
- new_text:
436
- 'function greet(name: string) {\n return `Hi, ${name}!`;\n}',
445
+ new_text: 'function greet(name: string) {\n return `Hi, ${name}!`;\n}',
437
446
  });
438
447
  expect(String(result)).toContain('strategies: line-trimmed');
439
448
  const after = await fsReadFile(file, 'utf8');
@@ -701,7 +710,10 @@ describe('compile_check', () => {
701
710
  name: 'compile_check',
702
711
  args: { command: 'echo hello && false' },
703
712
  type: 'tool_call',
704
- })) as { content: string; artifact: { passed: boolean; exit_code: number | null } };
713
+ })) as {
714
+ content: string;
715
+ artifact: { passed: boolean; exit_code: number | null };
716
+ };
705
717
  expect(message.content).toContain('FAILED');
706
718
  expect(message.content).toContain('hello');
707
719
  expect(message.artifact.passed).toBe(false);
@@ -764,18 +776,20 @@ describe('codex review fixes', () => {
764
776
  // Backend A: pretends rg works (returns a fake spawn whose
765
777
  // process exits 0 on every call). The cache should record true
766
778
  // for THIS backend.
767
- const okBackend = jest.fn((cmd: string, _args: string[], _opts: unknown) => {
768
- const ok = require('child_process').spawn('echo', [cmd]);
769
- return ok;
770
- }) as unknown as t.LocalSpawn;
779
+ const okBackend = jest.fn(
780
+ (cmd: string, _args: string[], _opts: unknown) => {
781
+ const ok = require('child_process').spawn('echo', [cmd]);
782
+ return ok;
783
+ }
784
+ ) as unknown as t.LocalSpawn;
771
785
  // Backend B: pretends rg does not exist (returns a child that
772
786
  // exits 127, the "command not found" code).
773
787
  const missingBackend = jest.fn(
774
788
  (_cmd: string, _args: string[], _opts: unknown) => {
775
- const child = require('child_process').spawn(
776
- 'sh',
777
- ['-c', 'exit 127']
778
- );
789
+ const child = require('child_process').spawn('sh', [
790
+ '-c',
791
+ 'exit 127',
792
+ ]);
779
793
  return child;
780
794
  }
781
795
  ) as unknown as t.LocalSpawn;
@@ -798,9 +812,11 @@ describe('codex review fixes', () => {
798
812
  });
799
813
 
800
814
  // Run grep against A first — populates cache for A's backend.
801
- await bundleA.tools.find((t_) => t_.name === 'grep_search')!.invoke({
802
- pattern: 'needle',
803
- });
815
+ await bundleA.tools
816
+ .find((t_) => t_.name === 'grep_search')!
817
+ .invoke({
818
+ pattern: 'needle',
819
+ });
804
820
  // Run grep against B — must NOT see cached "true" from A's
805
821
  // backend. With the bug, B would try to spawn rg, fail, and
806
822
  // throw instead of falling back to the Node walker.
@@ -825,7 +841,9 @@ describe('codex review fixes', () => {
825
841
  additionalRoots: ['../shared'],
826
842
  },
827
843
  });
828
- const readTool = bundle.tools.find((t_) => t_.name === Constants.READ_FILE);
844
+ const readTool = bundle.tools.find(
845
+ (t_) => t_.name === Constants.READ_FILE
846
+ );
829
847
  // Without the fix, '../shared/lib.ts' would resolve relative to
830
848
  // process.cwd (this test runner), miss the boundary check, and
831
849
  // throw "Path is outside the local workspace".
@@ -842,7 +860,10 @@ describe('codex review fixes', () => {
842
860
 
843
861
  describe('codex review fixes (round 2)', () => {
844
862
  describe('streaming output cap (Codex P1)', () => {
845
- const { spawnLocalProcess, _resetLocalEngineWarningsForTests: _ } = require('../local/LocalExecutionEngine');
863
+ const {
864
+ spawnLocalProcess,
865
+ _resetLocalEngineWarningsForTests: _,
866
+ } = require('../local/LocalExecutionEngine');
846
867
 
847
868
  it('hard-kills the child when total streamed bytes exceed maxSpawnedBytes', async () => {
848
869
  // Cap at 64 KiB. `yes` would otherwise run unbounded.
@@ -877,7 +898,10 @@ describe('codex review fixes (round 2)', () => {
877
898
  expect(result.exitCode).toBe(0);
878
899
  expect(result.fullOutputPath).toBeTruthy();
879
900
  const fs = await import('fs/promises');
880
- const spilled = await fs.readFile(result.fullOutputPath as string, 'utf8');
901
+ const spilled = await fs.readFile(
902
+ result.fullOutputPath as string,
903
+ 'utf8'
904
+ );
881
905
  // The spill file holds more bytes than the in-memory truncation.
882
906
  expect(spilled.length).toBeGreaterThan(result.stdout.length);
883
907
  });
@@ -902,7 +926,10 @@ describe('codex review fixes (round 2)', () => {
902
926
  const result = await bashTool!.invoke({
903
927
  id: 'b1',
904
928
  name: Constants.BASH_TOOL,
905
- args: { command: 'echo "first=$1 second=$2"', args: ['hello', 'world'] },
929
+ args: {
930
+ command: 'echo "first=$1 second=$2"',
931
+ args: ['hello', 'world'],
932
+ },
906
933
  type: 'tool_call',
907
934
  });
908
935
  const text = JSON.stringify(result);
@@ -939,7 +966,8 @@ describe('codex review fixes (round 3)', () => {
939
966
  ) => {
940
967
  calls.push(command);
941
968
  // Fall through to a real spawn so the call resolves cleanly.
942
- const { spawn: realSpawn } = require('child_process') as typeof import('child_process');
969
+ const { spawn: realSpawn } =
970
+ require('child_process') as typeof import('child_process');
943
971
  return realSpawn(command, args, opts);
944
972
  }) as unknown as t.LocalSpawn;
945
973
 
@@ -959,7 +987,9 @@ describe('codex review fixes (round 3)', () => {
959
987
  _resetSyntaxCheckProbeCacheForTests();
960
988
 
961
989
  // Backend A: probes succeed (real spawn).
962
- const realSpawn = (require('child_process') as typeof import('child_process')).spawn;
990
+ const realSpawn = (
991
+ require('child_process') as typeof import('child_process')
992
+ ).spawn;
963
993
  const okBackend: t.LocalSpawn = ((
964
994
  cmd: string,
965
995
  args: string[],
@@ -970,7 +1000,8 @@ describe('codex review fixes (round 3)', () => {
970
1000
  _cmd: string,
971
1001
  _args: string[],
972
1002
  opts: import('child_process').SpawnOptions
973
- ) => realSpawn('sh', ['-c', 'exit 127'], opts)) as unknown as t.LocalSpawn;
1003
+ ) =>
1004
+ realSpawn('sh', ['-c', 'exit 127'], opts)) as unknown as t.LocalSpawn;
974
1005
 
975
1006
  const cwdA = await createTempDir();
976
1007
  const cwdB = await createTempDir();
@@ -1039,7 +1070,7 @@ describe('codex review fixes (round 4)', () => {
1039
1070
  });
1040
1071
 
1041
1072
  it('blocks rm -rf \'/\' (target inside single quotes)', async () => {
1042
- const result = await validateBashCommand("rm -rf '/'");
1073
+ const result = await validateBashCommand('rm -rf \'/\'');
1043
1074
  expect(result.valid).toBe(false);
1044
1075
  expect(result.errors.join('\n')).toContain('destructive command pattern');
1045
1076
  });
@@ -1067,7 +1098,6 @@ describe('codex review fixes (round 4)', () => {
1067
1098
 
1068
1099
  describe('codex review fixes (round 5)', () => {
1069
1100
  describe('maxSpawnedBytes=0 disables the cap (Codex P2 #11)', () => {
1070
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1071
1101
  const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
1072
1102
 
1073
1103
  it('does not kill on first byte when maxSpawnedBytes is 0', async () => {
@@ -1109,7 +1139,7 @@ describe('codex review fixes (round 5)', () => {
1109
1139
  // happy path here; the static `createWriteStream` import means a
1110
1140
  // ReferenceError would surface as a test failure regardless of
1111
1141
  // which build runs the test.
1112
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1142
+
1113
1143
  const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
1114
1144
 
1115
1145
  it('writes a spill file without a runtime require', async () => {
@@ -1136,8 +1166,9 @@ describe('codex review fixes (round 5)', () => {
1136
1166
  });
1137
1167
 
1138
1168
  describe('sandbox config: loopback bridge access (Codex P1 #14)', () => {
1139
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1140
- const { buildSandboxRuntimeConfig } = require('../local/LocalExecutionEngine');
1169
+ const {
1170
+ buildSandboxRuntimeConfig,
1171
+ } = require('../local/LocalExecutionEngine');
1141
1172
 
1142
1173
  it('seeds allowedDomains with loopback hosts so the bridge works under sandbox', () => {
1143
1174
  const cfg = buildSandboxRuntimeConfig({}, '/tmp/ws', () => []);
@@ -1148,7 +1179,11 @@ describe('codex review fixes (round 5)', () => {
1148
1179
 
1149
1180
  it('keeps user-supplied allowedDomains and does not duplicate loopback', () => {
1150
1181
  const cfg = buildSandboxRuntimeConfig(
1151
- { sandbox: { network: { allowedDomains: ['api.example.com', '127.0.0.1'] } } },
1182
+ {
1183
+ sandbox: {
1184
+ network: { allowedDomains: ['api.example.com', '127.0.0.1'] },
1185
+ },
1186
+ },
1152
1187
  '/tmp/ws',
1153
1188
  () => []
1154
1189
  );
@@ -1175,8 +1210,9 @@ describe('codex review fixes (round 5)', () => {
1175
1210
  });
1176
1211
 
1177
1212
  describe('sandbox allowWrite includes additionalRoots (Codex P2 #15)', () => {
1178
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1179
- const { buildSandboxRuntimeConfig } = require('../local/LocalExecutionEngine');
1213
+ const {
1214
+ buildSandboxRuntimeConfig,
1215
+ } = require('../local/LocalExecutionEngine');
1180
1216
 
1181
1217
  it('adds workspace.additionalRoots to allowWrite alongside cwd', () => {
1182
1218
  const cfg = buildSandboxRuntimeConfig(
@@ -1188,7 +1224,7 @@ describe('codex review fixes (round 5)', () => {
1188
1224
  },
1189
1225
  },
1190
1226
  '/tmp/repo/app',
1191
- () => ['/tmp/runtime-default'],
1227
+ () => ['/tmp/runtime-default']
1192
1228
  );
1193
1229
  expect(cfg.filesystem.allowWrite).toEqual(
1194
1230
  expect.arrayContaining([
@@ -1209,7 +1245,7 @@ describe('codex review fixes (round 5)', () => {
1209
1245
  },
1210
1246
  },
1211
1247
  '/tmp/repo/app',
1212
- () => [],
1248
+ () => []
1213
1249
  );
1214
1250
  // ../shared anchored to root: /tmp/repo/app -> /tmp/repo/shared.
1215
1251
  expect(cfg.filesystem.allowWrite).toContain('/tmp/repo/shared');
@@ -1253,7 +1289,6 @@ describe('codex review fixes (round 5)', () => {
1253
1289
  // flagged. Pre-fix, glob_search dropped exitCode/stderr on
1254
1290
  // the floor and returned "No files found." regardless.
1255
1291
  const realSpawn = (
1256
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1257
1292
  require('child_process') as typeof import('child_process')
1258
1293
  ).spawn;
1259
1294
  const fakeRgBackend: t.LocalSpawn = ((
@@ -1304,7 +1339,6 @@ describe('codex review fixes (round 5)', () => {
1304
1339
  // glob_search had this fix but grep_search hadn't been
1305
1340
  // updated to match).
1306
1341
  const realSpawn = (
1307
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1308
1342
  require('child_process') as typeof import('child_process')
1309
1343
  ).spawn;
1310
1344
  const fakeRgBackend: t.LocalSpawn = ((
@@ -1435,13 +1469,13 @@ describe('comprehensive review (round 7) — manual finding C', () => {
1435
1469
  });
1436
1470
 
1437
1471
  it('blocks sh -c "chmod -R 777 /"', async () => {
1438
- const result = await validateBashCommand("sh -c 'chmod -R 777 /'");
1472
+ const result = await validateBashCommand('sh -c \'chmod -R 777 /\'');
1439
1473
  expect(result.valid).toBe(false);
1440
1474
  expect(result.errors.join('\n')).toMatch(/destructive command pattern/);
1441
1475
  });
1442
1476
 
1443
1477
  it('blocks eval "rm -rf /"', async () => {
1444
- const result = await validateBashCommand("eval 'rm -rf /'");
1478
+ const result = await validateBashCommand('eval \'rm -rf /\'');
1445
1479
  expect(result.valid).toBe(false);
1446
1480
  expect(result.errors.join('\n')).toMatch(/destructive command pattern/);
1447
1481
  });
@@ -1631,7 +1665,6 @@ describe('comprehensive review (round 7) — manual finding E', () => {
1631
1665
  describe('comprehensive review (round 8) — Codex P1 #24 / P1 #25', () => {
1632
1666
  describe('JSON post-edit syntax check uses WorkspaceFS (Codex P1 #24)', () => {
1633
1667
  it('routes the JSON read through `local.exec.fs` instead of host fs', async () => {
1634
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1635
1668
  const { runPostEditSyntaxCheck } = require('../local/syntaxCheck');
1636
1669
 
1637
1670
  const reads: string[] = [];
@@ -1669,7 +1702,6 @@ describe('comprehensive review (round 8) — Codex P1 #24 / P1 #25', () => {
1669
1702
  });
1670
1703
 
1671
1704
  it('flags invalid JSON returned by the WorkspaceFS', async () => {
1672
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1673
1705
  const { runPostEditSyntaxCheck } = require('../local/syntaxCheck');
1674
1706
  const fakeFs = {
1675
1707
  readFile: async () => '{ invalid: json',
@@ -1764,7 +1796,6 @@ describe('comprehensive review (round 8) — Codex P1 #24 / P1 #25', () => {
1764
1796
 
1765
1797
  describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit findings', () => {
1766
1798
  describe('overflow-killed processes report as failures (Codex P1)', () => {
1767
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1768
1799
  const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
1769
1800
 
1770
1801
  it('reports overflowKilled=true and a non-null exit code when maxSpawnedBytes is exceeded', async () => {
@@ -1811,7 +1842,6 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
1811
1842
  });
1812
1843
 
1813
1844
  describe('signal-killed processes report as failures (Codex P2 — generalizes the overflow fix)', () => {
1814
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1815
1845
  const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
1816
1846
 
1817
1847
  it('synthesizes a non-zero exit code and surfaces the signal name on `kill -9 $$`', async () => {
@@ -1861,7 +1891,6 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
1861
1891
  // is unavailable (the rg --version probe always fails). This
1862
1892
  // way the fallback compileFallbackRegex actually runs.
1863
1893
  const realSpawn = (
1864
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1865
1894
  require('child_process') as typeof import('child_process')
1866
1895
  ).spawn;
1867
1896
  const noRgBackend: t.LocalSpawn = ((
@@ -1907,7 +1936,7 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
1907
1936
  toolExecution: { engine: 'local' },
1908
1937
  });
1909
1938
  // Capture the bash_tool instance
1910
- // eslint-disable-next-line @typescript-eslint/dot-notation
1939
+
1911
1940
  const m1 = (node1 as unknown as { toolMap: Map<string, unknown> })
1912
1941
  .toolMap;
1913
1942
  expect(m1.has(Constants.BASH_TOOL)).toBe(true);
@@ -1930,7 +1959,6 @@ describe('comprehensive review (round 9) — Codex P1 (overflow-killed) + audit
1930
1959
 
1931
1960
  describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
1932
1961
  describe('SIGKILL escalation defeats SIGTERM-trapping processes (Codex P1 #28)', () => {
1933
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1934
1962
  const { spawnLocalProcess } = require('../local/LocalExecutionEngine');
1935
1963
 
1936
1964
  it('escalates to SIGKILL when timeoutMs elapses and the child traps SIGTERM', async () => {
@@ -1942,7 +1970,7 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
1942
1970
  const start = Date.now();
1943
1971
  const result = await spawnLocalProcess(
1944
1972
  'bash',
1945
- ['-c', "trap '' TERM; while true; do sleep 0.1; done"],
1973
+ ['-c', 'trap \'\' TERM; while true; do sleep 0.1; done'],
1946
1974
  { timeoutMs: 1500, sandbox: { enabled: false } }
1947
1975
  );
1948
1976
  const elapsed = Date.now() - start;
@@ -1968,7 +1996,6 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
1968
1996
  // verdict and tried to use rg under an env without it,
1969
1997
  // failing with ENOENT.
1970
1998
  const realSpawn = (
1971
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1972
1999
  require('child_process') as typeof import('child_process')
1973
2000
  ).spawn;
1974
2001
 
@@ -1993,14 +2020,12 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
1993
2020
 
1994
2021
  const cwdA = await createTempDir();
1995
2022
  const cwdB = await createTempDir();
1996
- await (await import('fs/promises')).writeFile(
1997
- join(cwdA, 'a.ts'),
1998
- 'needle\n'
1999
- );
2000
- await (await import('fs/promises')).writeFile(
2001
- join(cwdB, 'b.ts'),
2002
- 'needle\n'
2003
- );
2023
+ await (
2024
+ await import('fs/promises')
2025
+ ).writeFile(join(cwdA, 'a.ts'), 'needle\n');
2026
+ await (
2027
+ await import('fs/promises')
2028
+ ).writeFile(join(cwdB, 'b.ts'), 'needle\n');
2004
2029
 
2005
2030
  // Run A: env says rg is available → cache records `true` for
2006
2031
  // (backend, env-A).
@@ -2009,12 +2034,14 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
2009
2034
  exec: { spawn: envSensitive },
2010
2035
  env: { PATH: '/with/rg' },
2011
2036
  });
2012
- await bundleA.tools.find((t_) => t_.name === 'grep_search')!.invoke({
2013
- id: 'gA',
2014
- name: 'grep_search',
2015
- args: { pattern: 'needle' },
2016
- type: 'tool_call',
2017
- });
2037
+ await bundleA.tools
2038
+ .find((t_) => t_.name === 'grep_search')!
2039
+ .invoke({
2040
+ id: 'gA',
2041
+ name: 'grep_search',
2042
+ args: { pattern: 'needle' },
2043
+ type: 'tool_call',
2044
+ });
2018
2045
 
2019
2046
  // Run B: same backend, DIFFERENT env (PATH excludes rg). Must
2020
2047
  // run a fresh probe and fall back to the Node walker, NOT
@@ -2042,14 +2069,12 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
2042
2069
  });
2043
2070
 
2044
2071
  describe('compile-style runtimes honor local.shell (Codex P2 #29)', () => {
2045
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2046
2072
  const { executeLocalCode } = require('../local/LocalExecutionEngine');
2047
2073
 
2048
2074
  it('routes the rust runtime through `local.shell` instead of bare `bash`', async () => {
2049
2075
  // Intercept spawn — assert the configured shell is used for
2050
2076
  // the rs runtime, not hardcoded `bash`.
2051
2077
  const realSpawn = (
2052
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2053
2078
  require('child_process') as typeof import('child_process')
2054
2079
  ).spawn;
2055
2080
  const calls: string[] = [];
@@ -2065,7 +2090,11 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
2065
2090
 
2066
2091
  await executeLocalCode(
2067
2092
  { lang: 'rs', code: 'fn main() {}', args: [] },
2068
- { shell: '/bin/sh', exec: { spawn: intercept }, sandbox: { enabled: false } }
2093
+ {
2094
+ shell: '/bin/sh',
2095
+ exec: { spawn: intercept },
2096
+ sandbox: { enabled: false },
2097
+ }
2069
2098
  );
2070
2099
 
2071
2100
  // The rust path's compile-and-run command should have been
@@ -2077,8 +2106,10 @@ describe('comprehensive review (round 10) — Codex P1 #28 / P2 #29', () => {
2077
2106
 
2078
2107
  describe('comprehensive review (round 12) — Codex P1 #36', () => {
2079
2108
  describe('granular workspace flags override the legacy allowOutsideWorkspace', () => {
2080
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2081
- const { getWriteRoots, getReadRoots } = require('../local/LocalExecutionEngine');
2109
+ const {
2110
+ getWriteRoots,
2111
+ getReadRoots,
2112
+ } = require('../local/LocalExecutionEngine');
2082
2113
 
2083
2114
  it('workspace.allowWriteOutside=false beats allowOutsideWorkspace=true (Codex P1 #36)', () => {
2084
2115
  // Pre-fix the OR short-circuited on the legacy flag, returning
@@ -2190,8 +2221,9 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2190
2221
  });
2191
2222
 
2192
2223
  it('blocks the positional-arg dot-glob form too', async () => {
2193
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2194
- const { executeLocalBashWithArgs } = require('../local/LocalExecutionEngine');
2224
+ const {
2225
+ executeLocalBashWithArgs,
2226
+ } = require('../local/LocalExecutionEngine');
2195
2227
  await expect(
2196
2228
  executeLocalBashWithArgs('rm -rf "$1"', ['/.*'], {
2197
2229
  sandbox: { enabled: false },
@@ -2291,7 +2323,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2291
2323
  it('reports `matches: 0` when only oversize files are present', async () => {
2292
2324
  _resetRipgrepCacheForTests();
2293
2325
  const realSpawn = (
2294
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2295
2326
  require('child_process') as typeof import('child_process')
2296
2327
  ).spawn;
2297
2328
  const noRgBackend: t.LocalSpawn = ((
@@ -2386,8 +2417,9 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2386
2417
  });
2387
2418
 
2388
2419
  describe('bash args validated against destructive-target patterns (Codex P1 [45])', () => {
2389
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2390
- const { executeLocalBashWithArgs } = require('../local/LocalExecutionEngine');
2420
+ const {
2421
+ executeLocalBashWithArgs,
2422
+ } = require('../local/LocalExecutionEngine');
2391
2423
 
2392
2424
  it('blocks `rm -rf "$1"` + args=["/"]', async () => {
2393
2425
  await expect(
@@ -2495,8 +2527,9 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2495
2527
 
2496
2528
  describe('resolveWorkspacePathSafe routes through WorkspaceFS.realpath (Codex P2 #38)', () => {
2497
2529
  it('honors a custom workspace fs realpath impl', async () => {
2498
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2499
- const { resolveWorkspacePathSafe } = require('../local/LocalExecutionEngine');
2530
+ const {
2531
+ resolveWorkspacePathSafe,
2532
+ } = require('../local/LocalExecutionEngine');
2500
2533
  const calls: string[] = [];
2501
2534
  const fakeFs = {
2502
2535
  readFile: async () => '',
@@ -2539,7 +2572,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2539
2572
  it('does not bleed `hasNode` verdict from one env to another on the same backend', async () => {
2540
2573
  _resetSyntaxCheckProbeCacheForTests();
2541
2574
  const realSpawn = (
2542
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2543
2575
  require('child_process') as typeof import('child_process')
2544
2576
  ).spawn;
2545
2577
  const calls: Array<{ cmd: string; env?: NodeJS.ProcessEnv }> = [];
@@ -2563,7 +2595,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2563
2595
  return realSpawn('sh', ['-c', 'exit 0'], opts);
2564
2596
  }) as unknown as t.LocalSpawn;
2565
2597
 
2566
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2567
2598
  const { runPostEditSyntaxCheck } = require('../local/syntaxCheck');
2568
2599
  const cwd = await createTempDir();
2569
2600
  const file = join(cwd, 'a.js');
@@ -2581,14 +2612,16 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2581
2612
  // syntax-check via the missing node. Now: separate cache slot
2582
2613
  // for envB → its own probe → records `false` → skips check.
2583
2614
  const probeCallsBefore = calls.filter(
2584
- (c) => c.cmd === 'node' && c.env?.PATH?.includes('without-node') === true
2615
+ (c) =>
2616
+ c.cmd === 'node' && c.env?.PATH?.includes('without-node') === true
2585
2617
  ).length;
2586
2618
  await runPostEditSyntaxCheck(file, {
2587
2619
  exec: { spawn: envSensitive },
2588
2620
  env: { PATH: '/without-node' },
2589
2621
  });
2590
2622
  const probeCallsAfter = calls.filter(
2591
- (c) => c.cmd === 'node' && c.env?.PATH?.includes('without-node') === true
2623
+ (c) =>
2624
+ c.cmd === 'node' && c.env?.PATH?.includes('without-node') === true
2592
2625
  ).length;
2593
2626
  // A fresh probe must have run for envB (count went up).
2594
2627
  expect(probeCallsAfter).toBeGreaterThan(probeCallsBefore);
@@ -2599,7 +2632,6 @@ describe('comprehensive review (round 14) — Codex P1 #37 + P2 #38/#40/#41', ()
2599
2632
  it('emits a sentinel and continues instead of reading multi-MB files into memory', async () => {
2600
2633
  _resetRipgrepCacheForTests();
2601
2634
  const realSpawn = (
2602
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2603
2635
  require('child_process') as typeof import('child_process')
2604
2636
  ).spawn;
2605
2637
  // Force the Node fallback by making rg unavailable.
@@ -5,7 +5,6 @@
5
5
  */
6
6
  import { describe, it, expect, jest, beforeEach } from '@jest/globals';
7
7
  import type * as t from '@/types';
8
- import { Constants } from '@/common';
9
8
  import {
10
9
  createProgrammaticToolCallingTool,
11
10
  createProgrammaticToolCallingSchema,
@@ -16,10 +15,6 @@ import {
16
15
  normalizeToPythonIdentifier,
17
16
  unwrapToolResponse,
18
17
  } from '../ProgrammaticToolCalling';
19
- import {
20
- createBashProgrammaticToolCallingSchema,
21
- normalizeBashToolResultsForReplay,
22
- } from '../BashProgrammaticToolCalling';
23
18
  import {
24
19
  createProgrammaticToolRegistry,
25
20
  createGetTeamMembersTool,
@@ -27,6 +22,11 @@ import {
27
22
  createGetWeatherTool,
28
23
  createCalculatorTool,
29
24
  } from '@/test/mockTools';
25
+ import {
26
+ createBashProgrammaticToolCallingSchema,
27
+ normalizeBashToolResultsForReplay,
28
+ } from '../BashProgrammaticToolCalling';
29
+ import { Constants } from '@/common';
30
30
 
31
31
  describe('ProgrammaticToolCalling', () => {
32
32
  describe('tool descriptions', () => {
@@ -1464,6 +1464,30 @@ for member in team:
1464
1464
  expect(gate.denyReason).toContain('no writes from bridge');
1465
1465
  });
1466
1466
 
1467
+ it('threads executingAgentId from the hook context to bridge PreToolUse hooks', async () => {
1468
+ const { HookRegistry } = await import('@/hooks');
1469
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
1470
+ const ptcMod = require('../local/LocalProgrammaticToolCalling');
1471
+ const registry = new HookRegistry();
1472
+ let seen: string | undefined = 'UNSET';
1473
+ registry.register('PreToolUse', {
1474
+ hooks: [
1475
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
1476
+ async (input) => {
1477
+ seen = input.executingAgentId;
1478
+ return { decision: 'allow' };
1479
+ },
1480
+ ],
1481
+ });
1482
+ await ptcMod.applyPreToolUseHooksForBridge(
1483
+ { registry, runId: 'r1', executingAgentId: 'repo_investigator' },
1484
+ 'write_file',
1485
+ 'call_1',
1486
+ { path: '/tmp/x' }
1487
+ );
1488
+ expect(seen).toBe('repo_investigator');
1489
+ });
1490
+
1467
1491
  it('passes through when no hook denies (allow path)', async () => {
1468
1492
  const { HookRegistry } = await import('@/hooks');
1469
1493
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -1,11 +1,11 @@
1
1
  import { describe, it, expect } from '@jest/globals';
2
- import { Constants } from '@/common';
3
2
  import {
4
3
  ReadFileToolName,
5
4
  ReadFileToolSchema,
6
5
  ReadFileToolDescription,
7
6
  ReadFileToolDefinition,
8
7
  } from '../ReadFile';
8
+ import { Constants } from '@/common';
9
9
 
10
10
  describe('ReadFile', () => {
11
11
  describe('schema structure', () => {