@librechat/agents 3.2.2 → 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 (401) 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 +33 -0
  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 +47 -21
  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 +33 -1
  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 +47 -21
  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/instrumentation.d.ts +1 -0
  230. package/dist/types/langfuse.d.ts +4 -0
  231. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
  232. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -1
  233. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +2 -2
  234. package/dist/types/llm/bedrock/index.d.ts +2 -2
  235. package/dist/types/llm/fake.d.ts +3 -3
  236. package/dist/types/llm/google/index.d.ts +1 -0
  237. package/dist/types/llm/google/types.d.ts +1 -1
  238. package/dist/types/llm/google/utils/common.d.ts +2 -2
  239. package/dist/types/llm/google/utils/tools.d.ts +1 -1
  240. package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +1 -1
  241. package/dist/types/llm/openai/index.d.ts +2 -2
  242. package/dist/types/llm/openai/utils/index.d.ts +1 -1
  243. package/dist/types/llm/openrouter/index.d.ts +4 -4
  244. package/dist/types/messages/contextPruning.d.ts +1 -1
  245. package/dist/types/messages/format.d.ts +9 -4
  246. package/dist/types/messages/prune.d.ts +1 -1
  247. package/dist/types/session/JsonlSessionStore.d.ts +1 -1
  248. package/dist/types/session/handlers.d.ts +1 -1
  249. package/dist/types/session/types.d.ts +1 -1
  250. package/dist/types/summarization/node.d.ts +1 -1
  251. package/dist/types/tools/SubagentTool.d.ts +2 -2
  252. package/dist/types/tools/ToolNode.d.ts +9 -2
  253. package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +1 -1
  254. package/dist/types/tools/search/types.d.ts +1 -1
  255. package/dist/types/tools/search/utils.d.ts +11 -0
  256. package/dist/types/types/graph.d.ts +12 -4
  257. package/dist/types/types/llm.d.ts +4 -3
  258. package/dist/types/types/messages.d.ts +1 -1
  259. package/dist/types/types/run.d.ts +6 -6
  260. package/dist/types/types/stream.d.ts +2 -2
  261. package/dist/types/types/tools.d.ts +5 -1
  262. package/dist/types/utils/handlers.d.ts +2 -2
  263. package/dist/types/utils/run.d.ts +1 -1
  264. package/package.json +6 -3
  265. package/src/__tests__/stream.eagerEventExecution.test.ts +543 -6
  266. package/src/agents/AgentContext.ts +2 -2
  267. package/src/agents/__tests__/AgentContext.test.ts +3 -3
  268. package/src/agents/__tests__/promptCacheLiveHelpers.ts +1 -1
  269. package/src/events.ts +1 -1
  270. package/src/graphs/Graph.ts +329 -72
  271. package/src/graphs/MultiAgentGraph.ts +1 -1
  272. package/src/graphs/__tests__/Graph.reasoning.test.ts +919 -6
  273. package/src/graphs/__tests__/MultiAgentGraph.test.ts +1 -1
  274. package/src/graphs/__tests__/composition.smoke.test.ts +1 -1
  275. package/src/hooks/__tests__/HookRegistry.test.ts +1 -1
  276. package/src/hooks/__tests__/compactHooks.test.ts +8 -8
  277. package/src/hooks/__tests__/createWorkspacePolicyHook.test.ts +34 -22
  278. package/src/hooks/__tests__/executeHooks.test.ts +3 -3
  279. package/src/hooks/__tests__/integration.test.ts +3 -3
  280. package/src/hooks/__tests__/toolHooks.test.ts +10 -10
  281. package/src/hooks/createWorkspacePolicyHook.ts +17 -14
  282. package/src/hooks/executeHooks.ts +1 -1
  283. package/src/hooks/types.ts +5 -0
  284. package/src/instrumentation.ts +49 -8
  285. package/src/langfuse.ts +35 -1
  286. package/src/langfuseToolOutputTracing.ts +2 -2
  287. package/src/llm/anthropic/index.ts +1 -1
  288. package/src/llm/anthropic/utils/message_inputs.ts +1 -1
  289. package/src/llm/anthropic/utils/message_outputs.ts +3 -5
  290. package/src/llm/anthropic/utils/output_parsers.ts +5 -5
  291. package/src/llm/bedrock/index.ts +4 -4
  292. package/src/llm/bedrock/toolCache.test.ts +48 -9
  293. package/src/llm/bedrock/toolCache.ts +11 -6
  294. package/src/llm/custom-chat-models.smoke.test.ts +114 -0
  295. package/src/llm/fake.ts +30 -25
  296. package/src/llm/google/index.ts +43 -1
  297. package/src/llm/google/llm.spec.ts +173 -1
  298. package/src/llm/google/types.ts +1 -1
  299. package/src/llm/google/utils/common.ts +154 -45
  300. package/src/llm/google/utils/tools.ts +8 -8
  301. package/src/llm/google/utils/zod_to_genai_parameters.ts +4 -4
  302. package/src/llm/invoke.test.ts +3 -3
  303. package/src/llm/invoke.ts +170 -10
  304. package/src/llm/openai/index.ts +4 -4
  305. package/src/llm/openai/utils/index.ts +14 -14
  306. package/src/llm/openrouter/index.ts +4 -4
  307. package/src/llm/openrouter/reasoning.test.ts +2 -2
  308. package/src/llm/vertexai/fixThoughtSignatures.test.ts +1 -1
  309. package/src/llm/vertexai/index.ts +1 -1
  310. package/src/messages/cache.test.ts +22 -0
  311. package/src/messages/cache.ts +25 -12
  312. package/src/messages/content.ts +1 -1
  313. package/src/messages/contextPruning.ts +1 -1
  314. package/src/messages/format.ts +227 -43
  315. package/src/messages/formatAgentMessages.skills.test.ts +105 -26
  316. package/src/messages/formatAgentMessages.test.ts +841 -10
  317. package/src/messages/labelContentByAgent.test.ts +2 -2
  318. package/src/messages/prune.ts +1 -1
  319. package/src/messages/reducer.ts +1 -1
  320. package/src/messages/tools.ts +1 -1
  321. package/src/openai/__tests__/openai.test.ts +2 -2
  322. package/src/openai/index.ts +1 -1
  323. package/src/responses/__tests__/responses.test.ts +2 -2
  324. package/src/responses/index.ts +1 -1
  325. package/src/run.ts +82 -47
  326. package/src/session/AgentSession.ts +6 -6
  327. package/src/session/JsonlSessionStore.ts +3 -3
  328. package/src/session/__tests__/JsonlSessionStore.test.ts +5 -5
  329. package/src/session/__tests__/handlers.test.ts +2 -2
  330. package/src/session/handlers.ts +5 -5
  331. package/src/session/types.ts +1 -1
  332. package/src/specs/agent-handoffs.test.ts +1 -1
  333. package/src/specs/deterministic-trace-id.test.ts +50 -0
  334. package/src/specs/langfuse-callbacks.test.ts +2 -2
  335. package/src/specs/langfuse-metadata.test.ts +39 -0
  336. package/src/specs/langfuse-tool-output-tracing.test.ts +1 -1
  337. package/src/specs/multi-agent-summarization.test.ts +4 -4
  338. package/src/specs/subagent.test.ts +3 -3
  339. package/src/specs/summarization-unit.test.ts +1 -1
  340. package/src/specs/thinking-handoff.test.ts +1 -1
  341. package/src/splitStream.test.ts +48 -0
  342. package/src/stream.test.ts +53 -3
  343. package/src/stream.ts +450 -39
  344. package/src/summarization/__tests__/aggregator.test.ts +2 -2
  345. package/src/summarization/__tests__/node.test.ts +2 -2
  346. package/src/summarization/node.ts +1 -1
  347. package/src/tools/BashProgrammaticToolCalling.ts +5 -5
  348. package/src/tools/Calculator.ts +1 -1
  349. package/src/tools/CodeExecutor.ts +2 -4
  350. package/src/tools/SubagentTool.ts +2 -2
  351. package/src/tools/ToolNode.ts +37 -16
  352. package/src/tools/ToolSearch.ts +1 -1
  353. package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +4 -4
  354. package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +12 -12
  355. package/src/tools/__tests__/LocalExecutionTools.test.ts +125 -93
  356. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +29 -5
  357. package/src/tools/__tests__/ReadFile.test.ts +1 -1
  358. package/src/tools/__tests__/SkillTool.test.ts +4 -4
  359. package/src/tools/__tests__/SubagentExecutor.test.ts +17 -13
  360. package/src/tools/__tests__/SubagentTool.test.ts +2 -2
  361. package/src/tools/__tests__/ToolNode.eagerEventExecution.test.ts +1 -1
  362. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +2 -5
  363. package/src/tools/__tests__/ToolNode.session.test.ts +1 -1
  364. package/src/tools/__tests__/ToolSearch.test.ts +1 -1
  365. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +1 -1
  366. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +35 -32
  367. package/src/tools/__tests__/directToolHooks.test.ts +41 -0
  368. package/src/tools/__tests__/handlers.test.ts +2 -2
  369. package/src/tools/__tests__/hitl.test.ts +11 -11
  370. package/src/tools/__tests__/localToolNames.test.ts +8 -6
  371. package/src/tools/__tests__/skillCatalog.test.ts +1 -1
  372. package/src/tools/__tests__/subagentHooks.test.ts +20 -10
  373. package/src/tools/__tests__/workspaceSeam.test.ts +20 -7
  374. package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +9 -6
  375. package/src/tools/cloudflare/CloudflareSandboxTools.ts +19 -19
  376. package/src/tools/handlers.ts +5 -5
  377. package/src/tools/local/CompileCheckTool.ts +4 -7
  378. package/src/tools/local/FileCheckpointer.ts +6 -5
  379. package/src/tools/local/LocalCodingTools.ts +100 -45
  380. package/src/tools/local/LocalExecutionEngine.ts +5 -5
  381. package/src/tools/local/LocalExecutionTools.ts +9 -9
  382. package/src/tools/local/LocalProgrammaticToolCalling.ts +5 -4
  383. package/src/tools/local/attachments.ts +0 -6
  384. package/src/tools/local/resolveLocalExecutionTools.ts +15 -15
  385. package/src/tools/search/firecrawl.ts +1 -1
  386. package/src/tools/search/jina-reranker.test.ts +148 -37
  387. package/src/tools/search/rerankers.ts +14 -4
  388. package/src/tools/search/tavily-search.ts +2 -2
  389. package/src/tools/search/types.ts +1 -1
  390. package/src/tools/search/utils.ts +99 -9
  391. package/src/tools/subagent/SubagentExecutor.ts +12 -6
  392. package/src/types/graph.ts +20 -12
  393. package/src/types/llm.ts +7 -6
  394. package/src/types/messages.ts +1 -1
  395. package/src/types/run.ts +7 -7
  396. package/src/types/stream.ts +2 -2
  397. package/src/types/tools.ts +5 -1
  398. package/src/utils/handlers.ts +2 -2
  399. package/src/utils/llmConfig.ts +1 -1
  400. package/src/utils/logging.ts +20 -10
  401. package/src/utils/run.ts +2 -2
@@ -1,7 +1,7 @@
1
1
  // src/graphs/__tests__/MultiAgentGraph.test.ts
2
+ import type * as t from '@/types';
2
3
  import { MultiAgentGraph } from '../MultiAgentGraph';
3
4
  import { Providers } from '@/common';
4
- import type * as t from '@/types';
5
5
 
6
6
  describe('MultiAgentGraph.validateEdgeAgents', () => {
7
7
  const makeAgent = (agentId: string): t.AgentInputs => ({
@@ -1,7 +1,7 @@
1
1
  import { HumanMessage, getBufferString } from '@langchain/core/messages';
2
2
  import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
3
- import type { RunnableConfig } from '@langchain/core/runnables';
4
3
  import type { ChatGenerationChunk } from '@langchain/core/outputs';
4
+ import type { RunnableConfig } from '@langchain/core/runnables';
5
5
  import type { ToolCall } from '@langchain/core/messages/tool';
6
6
  import type { BaseMessage } from '@langchain/core/messages';
7
7
  import type * as t from '@/types';
@@ -1,11 +1,11 @@
1
1
  // src/hooks/__tests__/HookRegistry.test.ts
2
- import { HookRegistry } from '../HookRegistry';
3
2
  import type {
4
3
  HookMatcher,
5
4
  HookCallback,
6
5
  PreToolUseHookOutput,
7
6
  PostToolUseHookOutput,
8
7
  } from '../types';
8
+ import { HookRegistry } from '../HookRegistry';
9
9
 
10
10
  const noop: HookCallback<
11
11
  'PreToolUse'
@@ -1,13 +1,6 @@
1
1
  // src/hooks/__tests__/compactHooks.test.ts
2
- import { HumanMessage, AIMessage } from '@langchain/core/messages';
3
2
  import { FakeListChatModel } from '@langchain/core/utils/testing';
4
- import { HookRegistry } from '../HookRegistry';
5
- import { Run } from '@/run';
6
- import * as providers from '@/llm/providers';
7
- import { ToolEndHandler, ModelEndHandler } from '@/events';
8
- import { createTokenCounter } from '@/utils/tokens';
9
- import { Providers, GraphEvents } from '@/common';
10
- import type * as t from '@/types';
3
+ import { HumanMessage, AIMessage } from '@langchain/core/messages';
11
4
  import type {
12
5
  HookCallback,
13
6
  PreCompactHookInput,
@@ -15,6 +8,13 @@ import type {
15
8
  PostCompactHookInput,
16
9
  PostCompactHookOutput,
17
10
  } from '../types';
11
+ import type * as t from '@/types';
12
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
13
+ import { createTokenCounter } from '@/utils/tokens';
14
+ import { Providers, GraphEvents } from '@/common';
15
+ import { HookRegistry } from '../HookRegistry';
16
+ import * as providers from '@/llm/providers';
17
+ import { Run } from '@/run';
18
18
 
19
19
  const SUMMARY_RESPONSE = '## Summary\nUser asked a question and got an answer.';
20
20
 
@@ -2,12 +2,12 @@ import { tmpdir } from 'os';
2
2
  import { join, resolve } from 'path';
3
3
  import { mkdtemp, rm } from 'fs/promises';
4
4
  import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
5
- import { createWorkspacePolicyHook } from '../createWorkspacePolicyHook';
6
5
  import type {
7
6
  HookCallback,
8
7
  PreToolUseHookInput,
9
8
  PreToolUseHookOutput,
10
9
  } from '../types';
10
+ import { createWorkspacePolicyHook } from '../createWorkspacePolicyHook';
11
11
 
12
12
  function call(
13
13
  hook: HookCallback<'PreToolUse'>,
@@ -49,13 +49,17 @@ describe('createWorkspacePolicyHook', () => {
49
49
 
50
50
  it('allows in-workspace relative paths', async () => {
51
51
  const hook = createWorkspacePolicyHook({ root: workspace });
52
- const out = await call(hook,makeInput('read_file', { file_path: 'src/x.ts' }));
52
+ const out = await call(
53
+ hook,
54
+ makeInput('read_file', { file_path: 'src/x.ts' })
55
+ );
53
56
  expect(out.decision).toBe('allow');
54
57
  });
55
58
 
56
59
  it('allows in-workspace absolute paths', async () => {
57
60
  const hook = createWorkspacePolicyHook({ root: workspace });
58
- const out = await call(hook,
61
+ const out = await call(
62
+ hook,
59
63
  makeInput('read_file', { file_path: join(workspace, 'src/x.ts') })
60
64
  );
61
65
  expect(out.decision).toBe('allow');
@@ -66,7 +70,8 @@ describe('createWorkspacePolicyHook', () => {
66
70
  root: workspace,
67
71
  additionalRoots: [extra],
68
72
  });
69
- const out = await call(hook,
73
+ const out = await call(
74
+ hook,
70
75
  makeInput('read_file', { file_path: join(extra, 'lib/y.ts') })
71
76
  );
72
77
  expect(out.decision).toBe('allow');
@@ -74,7 +79,8 @@ describe('createWorkspacePolicyHook', () => {
74
79
 
75
80
  it('asks by default when path is outside the workspace (read tool)', async () => {
76
81
  const hook = createWorkspacePolicyHook({ root: workspace });
77
- const out = await call(hook,
82
+ const out = await call(
83
+ hook,
78
84
  makeInput('read_file', { file_path: '/etc/passwd' })
79
85
  );
80
86
  expect(out.decision).toBe('ask');
@@ -84,7 +90,8 @@ describe('createWorkspacePolicyHook', () => {
84
90
 
85
91
  it('asks by default when path is outside the workspace (write tool)', async () => {
86
92
  const hook = createWorkspacePolicyHook({ root: workspace });
87
- const out = await call(hook,
93
+ const out = await call(
94
+ hook,
88
95
  makeInput('write_file', {
89
96
  file_path: '/etc/foo',
90
97
  content: 'malicious',
@@ -98,7 +105,8 @@ describe('createWorkspacePolicyHook', () => {
98
105
  root: workspace,
99
106
  outsideRead: 'deny',
100
107
  });
101
- const out = await call(hook,
108
+ const out = await call(
109
+ hook,
102
110
  makeInput('read_file', { file_path: '/etc/passwd' })
103
111
  );
104
112
  expect(out.decision).toBe('deny');
@@ -110,7 +118,8 @@ describe('createWorkspacePolicyHook', () => {
110
118
  root: workspace,
111
119
  outsideWrite: 'deny',
112
120
  });
113
- const out = await call(hook,
121
+ const out = await call(
122
+ hook,
114
123
  makeInput('edit_file', {
115
124
  file_path: '/etc/foo',
116
125
  old_text: 'a',
@@ -125,7 +134,8 @@ describe('createWorkspacePolicyHook', () => {
125
134
  root: workspace,
126
135
  outsideRead: 'allow',
127
136
  });
128
- const out = await call(hook,
137
+ const out = await call(
138
+ hook,
129
139
  makeInput('read_file', { file_path: '/etc/passwd' })
130
140
  );
131
141
  expect(out.decision).toBe('allow');
@@ -133,7 +143,8 @@ describe('createWorkspacePolicyHook', () => {
133
143
 
134
144
  it('passes through when the tool has no extractor (e.g. bash)', async () => {
135
145
  const hook = createWorkspacePolicyHook({ root: workspace });
136
- const out = await call(hook,
146
+ const out = await call(
147
+ hook,
137
148
  makeInput('bash', { command: 'cat /etc/passwd' })
138
149
  );
139
150
  expect(out.decision).toBe('allow');
@@ -141,7 +152,7 @@ describe('createWorkspacePolicyHook', () => {
141
152
 
142
153
  it('passes through when the path arg is missing/empty', async () => {
143
154
  const hook = createWorkspacePolicyHook({ root: workspace });
144
- const out = await call(hook,makeInput('grep_search', { pattern: 'x' }));
155
+ const out = await call(hook, makeInput('grep_search', { pattern: 'x' }));
145
156
  expect(out.decision).toBe('allow');
146
157
  });
147
158
 
@@ -149,16 +160,17 @@ describe('createWorkspacePolicyHook', () => {
149
160
  const hook = createWorkspacePolicyHook({
150
161
  root: workspace,
151
162
  pathExtractors: {
152
- my_custom_tool: (i) =>
153
- typeof i.target === 'string' ? [i.target] : [],
163
+ my_custom_tool: (i) => (typeof i.target === 'string' ? [i.target] : []),
154
164
  },
155
165
  });
156
- const inside = await call(hook,
166
+ const inside = await call(
167
+ hook,
157
168
  makeInput('my_custom_tool', { target: 'in/workspace.ts' })
158
169
  );
159
170
  expect(inside.decision).toBe('allow');
160
171
 
161
- const outside = await call(hook,
172
+ const outside = await call(
173
+ hook,
162
174
  makeInput('my_custom_tool', { target: '/elsewhere/x.ts' })
163
175
  );
164
176
  // Unknown tools default to write-policy (stricter): 'ask'.
@@ -170,7 +182,8 @@ describe('createWorkspacePolicyHook', () => {
170
182
  root: workspace,
171
183
  reason: '{tool} blocked from {paths}',
172
184
  });
173
- const out = await call(hook,
185
+ const out = await call(
186
+ hook,
174
187
  makeInput('read_file', { file_path: '/somewhere/else.ts' })
175
188
  );
176
189
  expect(out.reason).toBe('read_file blocked from /somewhere/else.ts');
@@ -184,7 +197,8 @@ describe('createWorkspacePolicyHook', () => {
184
197
  Array.isArray(i.paths) ? (i.paths as string[]) : [],
185
198
  },
186
199
  });
187
- const out = await call(hook,
200
+ const out = await call(
201
+ hook,
188
202
  makeInput('multi_file_tool', {
189
203
  paths: [join(workspace, 'a.ts'), '/etc/passwd'],
190
204
  })
@@ -196,7 +210,8 @@ describe('createWorkspacePolicyHook', () => {
196
210
 
197
211
  it('respects resolved root paths (relative root config)', async () => {
198
212
  const hook = createWorkspacePolicyHook({ root: '.' });
199
- const out = await call(hook,
213
+ const out = await call(
214
+ hook,
200
215
  makeInput('read_file', { file_path: resolve('.', 'src/x.ts') })
201
216
  );
202
217
  expect(out.decision).toBe('allow');
@@ -206,10 +221,7 @@ describe('createWorkspacePolicyHook', () => {
206
221
  it('rejects a symlink inside the workspace that points outside', async () => {
207
222
  const fs = await import('fs/promises');
208
223
  await fs.writeFile(join(extra, 'secret.txt'), 'top-secret\n');
209
- await fs.symlink(
210
- join(extra, 'secret.txt'),
211
- join(workspace, 'escape')
212
- );
224
+ await fs.symlink(join(extra, 'secret.txt'), join(workspace, 'escape'));
213
225
  const hook = createWorkspacePolicyHook({
214
226
  root: workspace,
215
227
  outsideRead: 'deny',
@@ -1,7 +1,4 @@
1
1
  // src/hooks/__tests__/executeHooks.test.ts
2
- import { HookRegistry } from '../HookRegistry';
3
- import { executeHooks } from '../executeHooks';
4
- import { clearMatcherCache } from '../matchers';
5
2
  import type {
6
3
  HookCallback,
7
4
  HookMatcher,
@@ -14,6 +11,9 @@ import type {
14
11
  PostToolUseHookInput,
15
12
  PostToolUseHookOutput,
16
13
  } from '../types';
14
+ import { clearMatcherCache } from '../matchers';
15
+ import { HookRegistry } from '../HookRegistry';
16
+ import { executeHooks } from '../executeHooks';
17
17
 
18
18
  function preToolUseInput(
19
19
  toolName: string,
@@ -1,8 +1,5 @@
1
1
  // src/hooks/__tests__/integration.test.ts
2
2
  import { HumanMessage } from '@langchain/core/messages';
3
- import { HookRegistry } from '../HookRegistry';
4
- import { Run } from '@/run';
5
- import type * as t from '@/types';
6
3
  import type {
7
4
  HookCallback,
8
5
  RunStartHookInput,
@@ -12,7 +9,10 @@ import type {
12
9
  StopHookOutput,
13
10
  StopFailureHookOutput,
14
11
  } from '../types';
12
+ import type * as t from '@/types';
13
+ import { HookRegistry } from '../HookRegistry';
15
14
  import { Providers } from '@/common';
15
+ import { Run } from '@/run';
16
16
 
17
17
  const llmConfig: t.LLMConfig = {
18
18
  provider: Providers.OPENAI,
@@ -1,15 +1,6 @@
1
1
  // src/hooks/__tests__/toolHooks.test.ts
2
- import { ToolCall } from '@langchain/core/messages/tool';
3
2
  import { HumanMessage } from '@langchain/core/messages';
4
- import { HookRegistry } from '../HookRegistry';
5
- import { Run } from '@/run';
6
- import {
7
- GraphEvents,
8
- Providers,
9
- ToolEndHandler,
10
- ModelEndHandler,
11
- } from '@/index';
12
- import type * as t from '@/types';
3
+ import { ToolCall } from '@langchain/core/messages/tool';
13
4
  import type {
14
5
  HookCallback,
15
6
  PreToolUseHookOutput,
@@ -21,6 +12,15 @@ import type {
21
12
  PostToolUseHookInput,
22
13
  PostToolUseFailureHookInput,
23
14
  } from '../types';
15
+ import type * as t from '@/types';
16
+ import {
17
+ GraphEvents,
18
+ Providers,
19
+ ToolEndHandler,
20
+ ModelEndHandler,
21
+ } from '@/index';
22
+ import { HookRegistry } from '../HookRegistry';
23
+ import { Run } from '@/run';
24
24
 
25
25
  const llmConfig: t.LLMConfig = {
26
26
  provider: Providers.OPENAI,
@@ -48,15 +48,15 @@
48
48
  */
49
49
 
50
50
  import { homedir } from 'os';
51
- import { isAbsolute, relative, resolve } from 'path';
52
51
  import { realpath } from 'fs/promises';
53
- import { Constants } from '@/common';
52
+ import { isAbsolute, relative, resolve } from 'path';
54
53
  import type {
55
54
  HookCallback,
56
55
  PreToolUseHookInput,
57
56
  PreToolUseHookOutput,
58
57
  ToolDecision,
59
58
  } from './types';
59
+ import { Constants } from '@/common';
60
60
 
61
61
  /**
62
62
  * What to do when a tool call references a path outside the workspace.
@@ -213,9 +213,7 @@ async function realpathOrSelf(absolutePath: string): Promise<string> {
213
213
  }
214
214
  }
215
215
 
216
- async function realpathOfPathOrAncestor(
217
- absolutePath: string
218
- ): Promise<string> {
216
+ async function realpathOfPathOrAncestor(absolutePath: string): Promise<string> {
219
217
  let current = absolutePath;
220
218
  let suffix = '';
221
219
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -296,18 +294,27 @@ export function createWorkspacePolicyHook(
296
294
  const readPolicy: OutsideAccessPolicy = config.outsideRead ?? 'ask';
297
295
  const writePolicy: OutsideAccessPolicy = config.outsideWrite ?? 'ask';
298
296
 
299
- const extractors: Record<string, PathExtractor> = {
297
+ const extractors: Record<string, PathExtractor | undefined> = {
300
298
  ...DEFAULT_EXTRACTORS,
301
299
  ...(config.pathExtractors ?? {}),
302
300
  };
303
301
 
302
+ /** Unknown tools are treated as writes (the stricter policy). */
303
+ const resolvePolicy = (toolName: string): OutsideAccessPolicy => {
304
+ if (WRITE_TOOLS.has(toolName)) {
305
+ return writePolicy;
306
+ }
307
+ if (READ_TOOLS.has(toolName)) {
308
+ return readPolicy;
309
+ }
310
+ return writePolicy;
311
+ };
312
+
304
313
  return async (input: PreToolUseHookInput): Promise<PreToolUseHookOutput> => {
305
314
  const extractor = extractors[input.toolName];
306
315
  if (extractor == null) return { decision: 'allow' };
307
316
 
308
- const paths = extractor(
309
- (input.toolInput ?? {}) as Record<string, unknown>
310
- );
317
+ const paths = extractor(input.toolInput);
311
318
  if (paths.length === 0) return { decision: 'allow' };
312
319
 
313
320
  // Two-stage check:
@@ -336,11 +343,7 @@ export function createWorkspacePolicyHook(
336
343
  }
337
344
  if (outside.length === 0) return { decision: 'allow' };
338
345
 
339
- const policy = WRITE_TOOLS.has(input.toolName)
340
- ? writePolicy
341
- : READ_TOOLS.has(input.toolName)
342
- ? readPolicy
343
- : writePolicy; // unknown tools — treat as write (stricter)
346
+ const policy = resolvePolicy(input.toolName);
344
347
  if (policy === 'allow') return { decision: 'allow' };
345
348
 
346
349
  const decision: ToolDecision = policy === 'deny' ? 'deny' : 'ask';
@@ -1,6 +1,5 @@
1
1
  // src/hooks/executeHooks.ts
2
2
  import type { Logger } from 'winston';
3
- import type { HookRegistry } from './HookRegistry';
4
3
  import type {
5
4
  HookInput,
6
5
  HookEvent,
@@ -11,6 +10,7 @@ import type {
11
10
  HookCallback,
12
11
  AggregatedHookResult,
13
12
  } from './types';
13
+ import type { HookRegistry } from './HookRegistry';
14
14
  import { matchesQuery } from './matchers';
15
15
 
16
16
  /** Default per-hook timeout when a matcher doesn't set its own. */
@@ -39,11 +39,16 @@ export type StopDecision = 'continue' | 'block';
39
39
  * - `runId` identifies the current agent run and is always present.
40
40
  * - `threadId` identifies the conversation thread when the host has one.
41
41
  * - `agentId` is only set when the hook fires inside a subagent scope.
42
+ * - `executingAgentId` identifies the agent that owns the node emitting the hook,
43
+ * whenever the graph knows it — including top-level agents in a multi-agent
44
+ * graph (where `agentId` is intentionally undefined). Use this to attribute a
45
+ * hook to a specific agent regardless of subagent scope.
42
46
  */
43
47
  export interface BaseHookInput {
44
48
  runId: string;
45
49
  threadId?: string;
46
50
  agentId?: string;
51
+ executingAgentId?: string;
47
52
  }
48
53
 
49
54
  export interface RunStartHookInput extends BaseHookInput {
@@ -1,7 +1,18 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { createHash, randomBytes } from 'node:crypto';
1
3
  import { setLangfuseTracerProvider } from '@langfuse/tracing';
2
4
  import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
3
5
  import { context, ROOT_CONTEXT, createContextKey } from '@opentelemetry/api';
4
6
  import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
7
+ import type {
8
+ IdGenerator,
9
+ ReadableSpan,
10
+ Span,
11
+ SpanProcessor,
12
+ } from '@opentelemetry/sdk-trace-base';
13
+ import type { LangfuseSpanProcessorParams } from '@langfuse/otel';
14
+ import type { Context } from '@opentelemetry/api';
15
+ import type * as t from '@/types';
5
16
  import {
6
17
  hasLangfuseConfigCredentials,
7
18
  hasLangfuseEnvCredentials,
@@ -12,14 +23,43 @@ import {
12
23
  getContextLangfuseConfig,
13
24
  } from '@/langfuseToolOutputTracing';
14
25
  import { isPresent } from '@/utils/misc';
15
- import type {
16
- ReadableSpan,
17
- Span,
18
- SpanProcessor,
19
- } from '@opentelemetry/sdk-trace-base';
20
- import type { LangfuseSpanProcessorParams } from '@langfuse/otel';
21
- import type { Context } from '@opentelemetry/api';
22
- import type * as t from '@/types';
26
+
27
+ /**
28
+ * Per-run seed for deterministic Langfuse trace ids. When a run opts in
29
+ * (`LangfuseConfig.deterministicTraceId`), it executes its stream inside
30
+ * `runWithTraceIdSeed(runId, …)` and the IdGenerator below derives the root
31
+ * trace id from that seed instead of a random one. This lets external systems
32
+ * (e.g. a host app recording user feedback after the fact) attach scores or
33
+ * observations to the trace by regenerating the same id from the run/message
34
+ * id — no trace lookup required. With no active seed it falls back to random
35
+ * ids, so default behavior is unchanged.
36
+ */
37
+ const traceIdSeedStore = new AsyncLocalStorage<string>();
38
+
39
+ export function runWithTraceIdSeed<T>(
40
+ seed: string | undefined,
41
+ fn: () => T
42
+ ): T {
43
+ return isPresent(seed) ? traceIdSeedStore.run(seed, fn) : fn();
44
+ }
45
+
46
+ /** sha256(seed) → first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */
47
+ function traceIdFromSeed(seed: string): string {
48
+ return createHash('sha256').update(seed, 'utf8').digest('hex').slice(0, 32);
49
+ }
50
+
51
+ class SeededTraceIdGenerator implements IdGenerator {
52
+ generateTraceId(): string {
53
+ const seed = traceIdSeedStore.getStore();
54
+ return isPresent(seed)
55
+ ? traceIdFromSeed(seed)
56
+ : randomBytes(16).toString('hex');
57
+ }
58
+
59
+ generateSpanId(): string {
60
+ return randomBytes(8).toString('hex');
61
+ }
62
+ }
23
63
 
24
64
  let langfuseTracerProvider: BasicTracerProvider | undefined;
25
65
  let langfuseRoutingSpanProcessor: RoutingLangfuseSpanProcessor | undefined;
@@ -163,6 +203,7 @@ export function initializeLangfuseTracing(
163
203
  langfuseRoutingSpanProcessor.ensureProcessor(langfuse);
164
204
  langfuseTracerProvider = new BasicTracerProvider({
165
205
  spanProcessors: [langfuseRoutingSpanProcessor],
206
+ idGenerator: new SeededTraceIdGenerator(),
166
207
  });
167
208
 
168
209
  setLangfuseTracerProvider(langfuseTracerProvider);
package/src/langfuse.ts CHANGED
@@ -1,5 +1,9 @@
1
- import { getLangfuseTracerProvider } from '@langfuse/tracing';
2
1
  import { CallbackHandler } from '@langfuse/langchain';
2
+ import {
3
+ getLangfuseTracerProvider,
4
+ propagateAttributes,
5
+ } from '@langfuse/tracing';
6
+ import type { PropagateAttributesParams } from '@langfuse/tracing';
3
7
  import type * as t from '@/types';
4
8
  import { isPresent } from '@/utils/misc';
5
9
 
@@ -19,6 +23,10 @@ type AgentLangfuseHandlerParams = LangfuseHandlerParams & {
19
23
  langfuse?: t.LangfuseConfig;
20
24
  };
21
25
 
26
+ type LangfuseAttributeParams = AgentLangfuseHandlerParams & {
27
+ traceName?: string;
28
+ };
29
+
22
30
  type FlushableTracerProvider = {
23
31
  forceFlush?: () => Promise<void> | void;
24
32
  };
@@ -158,6 +166,32 @@ export function createLangfuseHandler({
158
166
  });
159
167
  }
160
168
 
169
+ function createPropagateAttributeParams({
170
+ userId,
171
+ sessionId,
172
+ traceMetadata,
173
+ traceName,
174
+ tags,
175
+ }: LangfuseAttributeParams): PropagateAttributesParams {
176
+ return {
177
+ userId,
178
+ sessionId,
179
+ traceName,
180
+ tags,
181
+ metadata: traceMetadata,
182
+ };
183
+ }
184
+
185
+ export function withLangfuseAttributes<T>(
186
+ params: LangfuseAttributeParams,
187
+ action: () => T
188
+ ): T {
189
+ if (!shouldCreateLangfuseHandler(params.langfuse)) {
190
+ return action();
191
+ }
192
+ return propagateAttributes(createPropagateAttributeParams(params), action);
193
+ }
194
+
161
195
  export function hasExplicitLangfuseConfig(
162
196
  contexts: Iterable<{ langfuse?: t.LangfuseConfig }>
163
197
  ): boolean {
@@ -1,7 +1,7 @@
1
- import { context, createContextKey } from '@opentelemetry/api';
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
2
  import { LangfuseSpanProcessor } from '@langfuse/otel';
3
+ import { context, createContextKey } from '@opentelemetry/api';
3
4
  import { LangfuseOtelSpanAttributes } from '@langfuse/tracing';
4
- import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  import type {
6
6
  ReadableSpan,
7
7
  Span,
@@ -19,11 +19,11 @@ import type {
19
19
  AnthropicContextManagementConfigParam,
20
20
  AnthropicRequestOptions,
21
21
  } from '@/llm/anthropic/types';
22
- import { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';
23
22
  import {
24
23
  _convertMessagesToAnthropicPayload,
25
24
  stripUnsupportedAssistantPrefill,
26
25
  } from './utils/message_inputs';
26
+ import { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';
27
27
  import { handleToolChoice } from './utils/tools';
28
28
 
29
29
  const DEFAULT_STREAM_DELAY = 25;
@@ -4,6 +4,7 @@
4
4
  * This util file contains functions for converting LangChain messages to Anthropic messages.
5
5
  */
6
6
  import { createHash } from 'node:crypto';
7
+ import { ToolCall } from '@langchain/core/messages/tool';
7
8
  import {
8
9
  type BaseMessage,
9
10
  type SystemMessage,
@@ -18,7 +19,6 @@ import {
18
19
  convertToProviderContentBlock,
19
20
  parseBase64DataUrl,
20
21
  } from '@langchain/core/messages';
21
- import { ToolCall } from '@langchain/core/messages/tool';
22
22
  import {
23
23
  AnthropicImageBlockParam,
24
24
  AnthropicMessageCreateParams,
@@ -1,13 +1,11 @@
1
1
  /** This util file contains functions for converting Anthropic messages to LangChain messages. */
2
2
  import { AIMessage, AIMessageChunk } from '@langchain/core/messages';
3
-
4
- import type Anthropic from '@anthropic-ai/sdk';
5
- import type { UsageMetadata } from '@langchain/core/messages';
6
3
  import type { ToolCallChunk } from '@langchain/core/messages/tool';
4
+ import type { UsageMetadata } from '@langchain/core/messages';
7
5
  import type { ChatGeneration } from '@langchain/core/outputs';
8
- import type { MessageContentComplex } from '@/types';
6
+ import type Anthropic from '@anthropic-ai/sdk';
9
7
  import type { AnthropicMessageResponse } from '../types';
10
-
8
+ import type { MessageContentComplex } from '@/types';
11
9
  import { toLangChainContent } from '@/messages/langchain';
12
10
  import { extractToolCalls } from './output_parsers';
13
11
 
@@ -1,16 +1,16 @@
1
1
  /* eslint-disable @typescript-eslint/explicit-function-return-type */
2
2
  /* eslint-disable @typescript-eslint/no-empty-object-type */
3
- import {
4
- BaseLLMOutputParser,
5
- OutputParserException,
6
- } from '@langchain/core/output_parsers';
7
- import { JsonOutputKeyToolsParserParamsInterop } from '@langchain/core/output_parsers/openai_tools';
8
3
  import { ChatGeneration } from '@langchain/core/outputs';
9
4
  import { ToolCall } from '@langchain/core/messages/tool';
10
5
  import {
11
6
  interopSafeParseAsync,
12
7
  InteropZodType,
13
8
  } from '@langchain/core/utils/types';
9
+ import {
10
+ BaseLLMOutputParser,
11
+ OutputParserException,
12
+ } from '@langchain/core/output_parsers';
13
+ import { JsonOutputKeyToolsParserParamsInterop } from '@langchain/core/output_parsers/openai_tools';
14
14
 
15
15
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
16
  interface AnthropicToolsOutputParserParams<T extends Record<string, any>>
@@ -22,23 +22,23 @@
22
22
  */
23
23
 
24
24
  import { ChatBedrockConverse } from '@langchain/aws';
25
+ import { AIMessageChunk } from '@langchain/core/messages';
26
+ import { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';
25
27
  import {
26
28
  ConverseStreamCommand,
27
29
  type GuardrailConfiguration,
28
30
  type GuardrailStreamConfiguration,
29
31
  } from '@aws-sdk/client-bedrock-runtime';
30
- import { AIMessageChunk } from '@langchain/core/messages';
31
- import { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';
32
32
  import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
33
- import type { ChatBedrockConverseInput } from '@langchain/aws';
34
33
  import type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';
35
- import { insertBedrockToolCachePoint } from './toolCache';
34
+ import type { ChatBedrockConverseInput } from '@langchain/aws';
36
35
  import {
37
36
  convertToConverseMessages,
38
37
  handleConverseStreamContentBlockStart,
39
38
  handleConverseStreamContentBlockDelta,
40
39
  handleConverseStreamMetadata,
41
40
  } from './utils';
41
+ import { insertBedrockToolCachePoint } from './toolCache';
42
42
 
43
43
  /**
44
44
  * Service tier type for Bedrock invocations.