@illuma-ai/agents 1.5.0 → 2.1.1

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 (424) hide show
  1. package/README.md +0 -62
  2. package/dist/cjs/agents/AgentContext.cjs +159 -258
  3. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  4. package/dist/cjs/graphs/Graph.cjs +25 -8
  5. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  6. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +1 -5
  7. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  8. package/dist/cjs/llm/bedrock/index.cjs +33 -61
  9. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  10. package/dist/cjs/llm/openai/utils/index.cjs +10 -27
  11. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  12. package/dist/cjs/main.cjs +3 -84
  13. package/dist/cjs/main.cjs.map +1 -1
  14. package/dist/cjs/messages/cache.cjs +0 -89
  15. package/dist/cjs/messages/cache.cjs.map +1 -1
  16. package/dist/cjs/messages/format.cjs +10 -68
  17. package/dist/cjs/messages/format.cjs.map +1 -1
  18. package/dist/cjs/tools/BashExecutor.cjs +11 -21
  19. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  20. package/dist/cjs/tools/CodeExecutor.cjs +10 -37
  21. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  22. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +11 -16
  23. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  24. package/dist/cjs/tools/ToolNode.cjs +73 -8
  25. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  26. package/dist/cjs/tools/search/search.cjs +3 -11
  27. package/dist/cjs/tools/search/search.cjs.map +1 -1
  28. package/dist/cjs/tools/search/tool.cjs +4 -28
  29. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  30. package/dist/cjs/tools/search/utils.cjs +3 -10
  31. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  32. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +48 -0
  33. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  34. package/dist/cjs/types/graph.cjs.map +1 -1
  35. package/dist/esm/agents/AgentContext.mjs +159 -258
  36. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  37. package/dist/esm/graphs/Graph.mjs +25 -8
  38. package/dist/esm/graphs/Graph.mjs.map +1 -1
  39. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +1 -5
  40. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  41. package/dist/esm/llm/bedrock/index.mjs +34 -61
  42. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  43. package/dist/esm/llm/openai/utils/index.mjs +10 -27
  44. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  45. package/dist/esm/main.mjs +1 -5
  46. package/dist/esm/main.mjs.map +1 -1
  47. package/dist/esm/messages/cache.mjs +0 -89
  48. package/dist/esm/messages/cache.mjs.map +1 -1
  49. package/dist/esm/messages/format.mjs +10 -68
  50. package/dist/esm/messages/format.mjs.map +1 -1
  51. package/dist/esm/tools/BashExecutor.mjs +12 -22
  52. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  53. package/dist/esm/tools/CodeExecutor.mjs +11 -37
  54. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  55. package/dist/esm/tools/ProgrammaticToolCalling.mjs +12 -17
  56. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  57. package/dist/esm/tools/ToolNode.mjs +73 -8
  58. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  59. package/dist/esm/tools/search/search.mjs +3 -11
  60. package/dist/esm/tools/search/search.mjs.map +1 -1
  61. package/dist/esm/tools/search/tool.mjs +4 -28
  62. package/dist/esm/tools/search/tool.mjs.map +1 -1
  63. package/dist/esm/tools/search/utils.mjs +3 -10
  64. package/dist/esm/tools/search/utils.mjs.map +1 -1
  65. package/dist/esm/tools/subagent/SubagentExecutor.mjs +48 -0
  66. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  67. package/dist/esm/types/graph.mjs.map +1 -1
  68. package/dist/types/agents/AgentContext.d.ts +25 -95
  69. package/dist/types/index.d.ts +0 -1
  70. package/dist/types/llm/bedrock/index.d.ts +1 -54
  71. package/dist/types/messages/format.d.ts +1 -4
  72. package/dist/types/tools/CodeExecutor.d.ts +0 -6
  73. package/dist/types/tools/search/types.d.ts +5 -99
  74. package/dist/types/tools/search/utils.d.ts +2 -2
  75. package/dist/types/tools/subagent/SubagentExecutor.d.ts +29 -0
  76. package/dist/types/types/graph.d.ts +24 -27
  77. package/dist/types/types/index.d.ts +0 -1
  78. package/dist/types/types/run.d.ts +0 -2
  79. package/dist/types/types/tools.d.ts +0 -9
  80. package/package.json +1 -61
  81. package/src/agents/AgentContext.test.ts +176 -0
  82. package/src/agents/AgentContext.ts +178 -304
  83. package/src/agents/__tests__/AgentContext.test.ts +0 -632
  84. package/src/graphs/Graph.ts +27 -8
  85. package/src/index.ts +0 -6
  86. package/src/llm/anthropic/utils/message_inputs.ts +1 -10
  87. package/src/llm/bedrock/__tests__/bedrock-caching.test.ts +18 -166
  88. package/src/llm/bedrock/index.ts +41 -116
  89. package/src/llm/openai/utils/index.ts +14 -31
  90. package/src/messages/cache.test.ts +24 -62
  91. package/src/messages/cache.ts +0 -112
  92. package/src/messages/format.ts +10 -89
  93. package/src/scripts/subagent-configurable-inheritance.ts +263 -0
  94. package/src/specs/anthropic.simple.test.ts +0 -61
  95. package/src/tools/BashExecutor.ts +13 -37
  96. package/src/tools/CodeExecutor.ts +11 -55
  97. package/src/tools/ProgrammaticToolCalling.ts +14 -29
  98. package/src/tools/ToolNode.ts +69 -8
  99. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +0 -60
  100. package/src/tools/__tests__/SubagentExecutor.test.ts +157 -0
  101. package/src/tools/search/search.ts +2 -12
  102. package/src/tools/search/tool.ts +2 -36
  103. package/src/tools/search/types.ts +8 -133
  104. package/src/tools/search/utils.ts +5 -13
  105. package/src/tools/subagent/SubagentExecutor.ts +78 -0
  106. package/src/types/graph.ts +21 -27
  107. package/src/types/index.ts +0 -1
  108. package/src/types/run.ts +0 -2
  109. package/src/types/tools.ts +0 -9
  110. package/dist/cjs/langchain/google-common.cjs +0 -3
  111. package/dist/cjs/langchain/google-common.cjs.map +0 -1
  112. package/dist/cjs/langchain/index.cjs +0 -86
  113. package/dist/cjs/langchain/index.cjs.map +0 -1
  114. package/dist/cjs/langchain/language_models/chat_models.cjs +0 -3
  115. package/dist/cjs/langchain/language_models/chat_models.cjs.map +0 -1
  116. package/dist/cjs/langchain/messages/tool.cjs +0 -3
  117. package/dist/cjs/langchain/messages/tool.cjs.map +0 -1
  118. package/dist/cjs/langchain/messages.cjs +0 -51
  119. package/dist/cjs/langchain/messages.cjs.map +0 -1
  120. package/dist/cjs/langchain/openai.cjs +0 -3
  121. package/dist/cjs/langchain/openai.cjs.map +0 -1
  122. package/dist/cjs/langchain/prompts.cjs +0 -11
  123. package/dist/cjs/langchain/prompts.cjs.map +0 -1
  124. package/dist/cjs/langchain/runnables.cjs +0 -19
  125. package/dist/cjs/langchain/runnables.cjs.map +0 -1
  126. package/dist/cjs/langchain/tools.cjs +0 -23
  127. package/dist/cjs/langchain/tools.cjs.map +0 -1
  128. package/dist/cjs/langchain/utils/env.cjs +0 -11
  129. package/dist/cjs/langchain/utils/env.cjs.map +0 -1
  130. package/dist/cjs/llm/bedrock/cacheSupport.cjs +0 -55
  131. package/dist/cjs/llm/bedrock/cacheSupport.cjs.map +0 -1
  132. package/dist/cjs/tools/search/tavily-scraper.cjs +0 -189
  133. package/dist/cjs/tools/search/tavily-scraper.cjs.map +0 -1
  134. package/dist/cjs/tools/search/tavily-search.cjs +0 -372
  135. package/dist/cjs/tools/search/tavily-search.cjs.map +0 -1
  136. package/dist/cjs/types/agent-cache.cjs +0 -53
  137. package/dist/cjs/types/agent-cache.cjs.map +0 -1
  138. package/dist/esm/langchain/google-common.mjs +0 -2
  139. package/dist/esm/langchain/google-common.mjs.map +0 -1
  140. package/dist/esm/langchain/index.mjs +0 -5
  141. package/dist/esm/langchain/index.mjs.map +0 -1
  142. package/dist/esm/langchain/language_models/chat_models.mjs +0 -2
  143. package/dist/esm/langchain/language_models/chat_models.mjs.map +0 -1
  144. package/dist/esm/langchain/messages/tool.mjs +0 -2
  145. package/dist/esm/langchain/messages/tool.mjs.map +0 -1
  146. package/dist/esm/langchain/messages.mjs +0 -2
  147. package/dist/esm/langchain/messages.mjs.map +0 -1
  148. package/dist/esm/langchain/openai.mjs +0 -2
  149. package/dist/esm/langchain/openai.mjs.map +0 -1
  150. package/dist/esm/langchain/prompts.mjs +0 -2
  151. package/dist/esm/langchain/prompts.mjs.map +0 -1
  152. package/dist/esm/langchain/runnables.mjs +0 -2
  153. package/dist/esm/langchain/runnables.mjs.map +0 -1
  154. package/dist/esm/langchain/tools.mjs +0 -2
  155. package/dist/esm/langchain/tools.mjs.map +0 -1
  156. package/dist/esm/langchain/utils/env.mjs +0 -2
  157. package/dist/esm/langchain/utils/env.mjs.map +0 -1
  158. package/dist/esm/llm/bedrock/cacheSupport.mjs +0 -52
  159. package/dist/esm/llm/bedrock/cacheSupport.mjs.map +0 -1
  160. package/dist/esm/tools/search/tavily-scraper.mjs +0 -186
  161. package/dist/esm/tools/search/tavily-scraper.mjs.map +0 -1
  162. package/dist/esm/tools/search/tavily-search.mjs +0 -370
  163. package/dist/esm/tools/search/tavily-search.mjs.map +0 -1
  164. package/dist/esm/types/agent-cache.mjs +0 -51
  165. package/dist/esm/types/agent-cache.mjs.map +0 -1
  166. package/dist/types/langchain/google-common.d.ts +0 -1
  167. package/dist/types/langchain/index.d.ts +0 -8
  168. package/dist/types/langchain/language_models/chat_models.d.ts +0 -1
  169. package/dist/types/langchain/messages/tool.d.ts +0 -1
  170. package/dist/types/langchain/messages.d.ts +0 -2
  171. package/dist/types/langchain/openai.d.ts +0 -1
  172. package/dist/types/langchain/prompts.d.ts +0 -1
  173. package/dist/types/langchain/runnables.d.ts +0 -2
  174. package/dist/types/langchain/tools.d.ts +0 -2
  175. package/dist/types/langchain/utils/env.d.ts +0 -1
  176. package/dist/types/llm/bedrock/cacheSupport.d.ts +0 -35
  177. package/dist/types/tools/search/tavily-scraper.d.ts +0 -19
  178. package/dist/types/tools/search/tavily-search.d.ts +0 -4
  179. package/dist/types/tools/subagent/types.d.ts +0 -84
  180. package/dist/types/types/agent-cache.d.ts +0 -70
  181. package/src/agents/AgentContext.js.map +0 -1
  182. package/src/agents/AgentContext.test.js.map +0 -1
  183. package/src/agents/__tests__/AgentContext.cacheTtl.live.test.ts +0 -259
  184. package/src/agents/__tests__/AgentContext.crossAgentTier1.live.test.ts +0 -264
  185. package/src/agents/__tests__/AgentContext.crossUserCache.live.test.ts +0 -342
  186. package/src/agents/__tests__/AgentContext.test.js.map +0 -1
  187. package/src/agents/__tests__/resolveStructuredOutputMode.test.js.map +0 -1
  188. package/src/common/enum.js.map +0 -1
  189. package/src/common/index.js.map +0 -1
  190. package/src/events.js.map +0 -1
  191. package/src/graphs/Graph.js.map +0 -1
  192. package/src/graphs/MultiAgentGraph.js.map +0 -1
  193. package/src/graphs/__tests__/structured-output.integration.test.js.map +0 -1
  194. package/src/graphs/__tests__/structured-output.test.js.map +0 -1
  195. package/src/graphs/contextManagement.e2e.test.js.map +0 -1
  196. package/src/graphs/contextManagement.test.js.map +0 -1
  197. package/src/graphs/handoffValidation.test.js.map +0 -1
  198. package/src/graphs/index.js.map +0 -1
  199. package/src/index.js.map +0 -1
  200. package/src/instrumentation.js.map +0 -1
  201. package/src/langchain/google-common.ts +0 -1
  202. package/src/langchain/index.ts +0 -8
  203. package/src/langchain/language_models/chat_models.ts +0 -1
  204. package/src/langchain/messages/tool.ts +0 -5
  205. package/src/langchain/messages.ts +0 -21
  206. package/src/langchain/openai.ts +0 -1
  207. package/src/langchain/prompts.ts +0 -1
  208. package/src/langchain/runnables.ts +0 -7
  209. package/src/langchain/tools.ts +0 -8
  210. package/src/langchain/utils/env.ts +0 -1
  211. package/src/llm/anthropic/index.js.map +0 -1
  212. package/src/llm/anthropic/types.js.map +0 -1
  213. package/src/llm/anthropic/utils/message_inputs.js.map +0 -1
  214. package/src/llm/anthropic/utils/message_outputs.js.map +0 -1
  215. package/src/llm/anthropic/utils/output_parsers.js.map +0 -1
  216. package/src/llm/anthropic/utils/server-tool-inputs.test.ts +0 -436
  217. package/src/llm/anthropic/utils/tools.js.map +0 -1
  218. package/src/llm/bedrock/__tests__/bedrock-caching.test.js.map +0 -1
  219. package/src/llm/bedrock/cacheSupport.test.ts +0 -99
  220. package/src/llm/bedrock/cacheSupport.ts +0 -53
  221. package/src/llm/bedrock/index.js.map +0 -1
  222. package/src/llm/bedrock/types.js.map +0 -1
  223. package/src/llm/bedrock/utils/index.js.map +0 -1
  224. package/src/llm/bedrock/utils/message_inputs.js.map +0 -1
  225. package/src/llm/bedrock/utils/message_outputs.js.map +0 -1
  226. package/src/llm/fake.js.map +0 -1
  227. package/src/llm/google/index.js.map +0 -1
  228. package/src/llm/google/types.js.map +0 -1
  229. package/src/llm/google/utils/common.js.map +0 -1
  230. package/src/llm/google/utils/tools.js.map +0 -1
  231. package/src/llm/google/utils/zod_to_genai_parameters.js.map +0 -1
  232. package/src/llm/openai/index.js.map +0 -1
  233. package/src/llm/openai/types.js.map +0 -1
  234. package/src/llm/openai/utils/index.js.map +0 -1
  235. package/src/llm/openai/utils/isReasoningModel.test.js.map +0 -1
  236. package/src/llm/openrouter/index.js.map +0 -1
  237. package/src/llm/openrouter/reasoning.test.js.map +0 -1
  238. package/src/llm/providers.js.map +0 -1
  239. package/src/llm/text.js.map +0 -1
  240. package/src/llm/vertexai/index.js.map +0 -1
  241. package/src/messages/__tests__/tools.test.js.map +0 -1
  242. package/src/messages/cache.js.map +0 -1
  243. package/src/messages/cache.test.js.map +0 -1
  244. package/src/messages/content.js.map +0 -1
  245. package/src/messages/content.test.js.map +0 -1
  246. package/src/messages/core.js.map +0 -1
  247. package/src/messages/ensureThinkingBlock.test.js.map +0 -1
  248. package/src/messages/format.js.map +0 -1
  249. package/src/messages/formatAgentMessages.test.js.map +0 -1
  250. package/src/messages/formatAgentMessages.tools.test.js.map +0 -1
  251. package/src/messages/formatMessage.test.js.map +0 -1
  252. package/src/messages/ids.js.map +0 -1
  253. package/src/messages/index.js.map +0 -1
  254. package/src/messages/labelContentByAgent.test.js.map +0 -1
  255. package/src/messages/prune.js.map +0 -1
  256. package/src/messages/reducer.js.map +0 -1
  257. package/src/messages/shiftIndexTokenCountMap.test.js.map +0 -1
  258. package/src/messages/summarize.js.map +0 -1
  259. package/src/messages/summarize.test.js.map +0 -1
  260. package/src/messages/tools.js.map +0 -1
  261. package/src/mockStream.js.map +0 -1
  262. package/src/prompts/collab.js.map +0 -1
  263. package/src/prompts/index.js.map +0 -1
  264. package/src/prompts/taskmanager.js.map +0 -1
  265. package/src/run.js.map +0 -1
  266. package/src/schemas/index.js.map +0 -1
  267. package/src/schemas/schema-preparation.test.js.map +0 -1
  268. package/src/schemas/validate.js.map +0 -1
  269. package/src/schemas/validate.test.js.map +0 -1
  270. package/src/scripts/abort.js.map +0 -1
  271. package/src/scripts/ant_web_search.js.map +0 -1
  272. package/src/scripts/ant_web_search_edge_case.js.map +0 -1
  273. package/src/scripts/ant_web_search_error_edge_case.js.map +0 -1
  274. package/src/scripts/args.js.map +0 -1
  275. package/src/scripts/bedrock-cache-debug.js.map +0 -1
  276. package/src/scripts/bedrock-content-aggregation-test.js.map +0 -1
  277. package/src/scripts/bedrock-merge-test.js.map +0 -1
  278. package/src/scripts/bedrock-parallel-tools-test.js.map +0 -1
  279. package/src/scripts/caching.js.map +0 -1
  280. package/src/scripts/cli.js.map +0 -1
  281. package/src/scripts/cli2.js.map +0 -1
  282. package/src/scripts/cli3.js.map +0 -1
  283. package/src/scripts/cli4.js.map +0 -1
  284. package/src/scripts/cli5.js.map +0 -1
  285. package/src/scripts/code_exec.js.map +0 -1
  286. package/src/scripts/code_exec_files.js.map +0 -1
  287. package/src/scripts/code_exec_multi_session.js.map +0 -1
  288. package/src/scripts/code_exec_ptc.js.map +0 -1
  289. package/src/scripts/code_exec_session.js.map +0 -1
  290. package/src/scripts/code_exec_simple.js.map +0 -1
  291. package/src/scripts/content.js.map +0 -1
  292. package/src/scripts/empty_input.js.map +0 -1
  293. package/src/scripts/handoff-test.js.map +0 -1
  294. package/src/scripts/image.js.map +0 -1
  295. package/src/scripts/memory.js.map +0 -1
  296. package/src/scripts/multi-agent-chain.js.map +0 -1
  297. package/src/scripts/multi-agent-conditional.js.map +0 -1
  298. package/src/scripts/multi-agent-document-review-chain.js.map +0 -1
  299. package/src/scripts/multi-agent-hybrid-flow.js.map +0 -1
  300. package/src/scripts/multi-agent-parallel-start.js.map +0 -1
  301. package/src/scripts/multi-agent-parallel.js.map +0 -1
  302. package/src/scripts/multi-agent-sequence.js.map +0 -1
  303. package/src/scripts/multi-agent-supervisor.js.map +0 -1
  304. package/src/scripts/multi-agent-test.js.map +0 -1
  305. package/src/scripts/parallel-asymmetric-tools-test.js.map +0 -1
  306. package/src/scripts/parallel-full-metadata-test.js.map +0 -1
  307. package/src/scripts/parallel-tools-test.js.map +0 -1
  308. package/src/scripts/programmatic_exec.js.map +0 -1
  309. package/src/scripts/programmatic_exec_agent.js.map +0 -1
  310. package/src/scripts/search.js.map +0 -1
  311. package/src/scripts/sequential-full-metadata-test.js.map +0 -1
  312. package/src/scripts/simple.js.map +0 -1
  313. package/src/scripts/single-agent-metadata-test.js.map +0 -1
  314. package/src/scripts/stream.js.map +0 -1
  315. package/src/scripts/test-custom-prompt-key.js.map +0 -1
  316. package/src/scripts/test-handoff-input.js.map +0 -1
  317. package/src/scripts/test-handoff-preamble.js.map +0 -1
  318. package/src/scripts/test-handoff-steering.js.map +0 -1
  319. package/src/scripts/test-multi-agent-list-handoff.js.map +0 -1
  320. package/src/scripts/test-parallel-agent-labeling.js.map +0 -1
  321. package/src/scripts/test-parallel-handoffs.js.map +0 -1
  322. package/src/scripts/test-thinking-handoff-bedrock.js.map +0 -1
  323. package/src/scripts/test-thinking-handoff.js.map +0 -1
  324. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js.map +0 -1
  325. package/src/scripts/test-tool-before-handoff-role-order.js.map +0 -1
  326. package/src/scripts/test-tools-before-handoff.js.map +0 -1
  327. package/src/scripts/test_code_api.js.map +0 -1
  328. package/src/scripts/thinking-bedrock.js.map +0 -1
  329. package/src/scripts/thinking-vertexai.js.map +0 -1
  330. package/src/scripts/thinking.js.map +0 -1
  331. package/src/scripts/tool_search.js.map +0 -1
  332. package/src/scripts/tools.js.map +0 -1
  333. package/src/specs/agent-handoffs-bedrock.integration.test.js.map +0 -1
  334. package/src/specs/agent-handoffs.test.js.map +0 -1
  335. package/src/specs/anthropic.simple.test.js.map +0 -1
  336. package/src/specs/azure.simple.test.js.map +0 -1
  337. package/src/specs/cache.simple.test.js.map +0 -1
  338. package/src/specs/custom-event-await.test.js.map +0 -1
  339. package/src/specs/deepseek.simple.test.js.map +0 -1
  340. package/src/specs/emergency-prune.test.js.map +0 -1
  341. package/src/specs/moonshot.simple.test.js.map +0 -1
  342. package/src/specs/observability.integration.test.js.map +0 -1
  343. package/src/specs/openai.simple.test.js.map +0 -1
  344. package/src/specs/openrouter.simple.test.js.map +0 -1
  345. package/src/specs/prune.test.js.map +0 -1
  346. package/src/specs/reasoning.test.js.map +0 -1
  347. package/src/specs/spec.utils.js.map +0 -1
  348. package/src/specs/thinking-handoff.test.js.map +0 -1
  349. package/src/specs/thinking-prune.test.js.map +0 -1
  350. package/src/specs/token-distribution-edge-case.test.js.map +0 -1
  351. package/src/specs/token-memoization.test.js.map +0 -1
  352. package/src/specs/tokens.test.js.map +0 -1
  353. package/src/specs/tool-error.test.js.map +0 -1
  354. package/src/splitStream.js.map +0 -1
  355. package/src/splitStream.test.js.map +0 -1
  356. package/src/stream.js.map +0 -1
  357. package/src/stream.test.js.map +0 -1
  358. package/src/test/mockTools.js.map +0 -1
  359. package/src/tools/BrowserTools.js.map +0 -1
  360. package/src/tools/Calculator.js.map +0 -1
  361. package/src/tools/Calculator.test.js.map +0 -1
  362. package/src/tools/CodeExecutor.js.map +0 -1
  363. package/src/tools/ProgrammaticToolCalling.js.map +0 -1
  364. package/src/tools/StreamingToolCallBuffer.js.map +0 -1
  365. package/src/tools/ToolNode.js.map +0 -1
  366. package/src/tools/ToolSearch.js.map +0 -1
  367. package/src/tools/__tests__/BrowserTools.test.js.map +0 -1
  368. package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.js.map +0 -1
  369. package/src/tools/__tests__/ProgrammaticToolCalling.test.js.map +0 -1
  370. package/src/tools/__tests__/StreamingToolCallBuffer.test.js.map +0 -1
  371. package/src/tools/__tests__/ToolApproval.test.js.map +0 -1
  372. package/src/tools/__tests__/ToolNode.recovery.test.js.map +0 -1
  373. package/src/tools/__tests__/ToolNode.session.test.js.map +0 -1
  374. package/src/tools/__tests__/ToolSearch.integration.test.js.map +0 -1
  375. package/src/tools/__tests__/ToolSearch.test.js.map +0 -1
  376. package/src/tools/__tests__/handlers.test.js.map +0 -1
  377. package/src/tools/__tests__/truncation-recovery.integration.test.js.map +0 -1
  378. package/src/tools/handlers.js.map +0 -1
  379. package/src/tools/schema.js.map +0 -1
  380. package/src/tools/search/anthropic.js.map +0 -1
  381. package/src/tools/search/content.js.map +0 -1
  382. package/src/tools/search/content.test.js.map +0 -1
  383. package/src/tools/search/firecrawl.js.map +0 -1
  384. package/src/tools/search/format.js.map +0 -1
  385. package/src/tools/search/highlights.js.map +0 -1
  386. package/src/tools/search/index.js.map +0 -1
  387. package/src/tools/search/jina-reranker.test.js.map +0 -1
  388. package/src/tools/search/rerankers.js.map +0 -1
  389. package/src/tools/search/schema.js.map +0 -1
  390. package/src/tools/search/search.js.map +0 -1
  391. package/src/tools/search/serper-scraper.js.map +0 -1
  392. package/src/tools/search/tavily-scraper.ts +0 -235
  393. package/src/tools/search/tavily-search.ts +0 -424
  394. package/src/tools/search/tavily.test.ts +0 -965
  395. package/src/tools/search/test.js.map +0 -1
  396. package/src/tools/search/tool.js.map +0 -1
  397. package/src/tools/search/types.js.map +0 -1
  398. package/src/tools/search/utils.js.map +0 -1
  399. package/src/tools/subagent/types.test.ts +0 -70
  400. package/src/tools/subagent/types.ts +0 -115
  401. package/src/types/agent-cache.ts +0 -73
  402. package/src/types/graph.js.map +0 -1
  403. package/src/types/graph.test.js.map +0 -1
  404. package/src/types/index.js.map +0 -1
  405. package/src/types/llm.js.map +0 -1
  406. package/src/types/messages.js.map +0 -1
  407. package/src/types/run.js.map +0 -1
  408. package/src/types/stream.js.map +0 -1
  409. package/src/types/tools.js.map +0 -1
  410. package/src/utils/contextAnalytics.js.map +0 -1
  411. package/src/utils/contextAnalytics.test.js.map +0 -1
  412. package/src/utils/events.js.map +0 -1
  413. package/src/utils/graph.js.map +0 -1
  414. package/src/utils/handlers.js.map +0 -1
  415. package/src/utils/index.js.map +0 -1
  416. package/src/utils/llm.js.map +0 -1
  417. package/src/utils/llmConfig.js.map +0 -1
  418. package/src/utils/logging.js.map +0 -1
  419. package/src/utils/misc.js.map +0 -1
  420. package/src/utils/run.js.map +0 -1
  421. package/src/utils/schema.js.map +0 -1
  422. package/src/utils/title.js.map +0 -1
  423. package/src/utils/tokens.js.map +0 -1
  424. package/src/utils/toonFormat.js.map +0 -1
@@ -376,67 +376,6 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
376
376
  );
377
377
  });
378
378
 
379
- test(`${capitalizeFirstLetter(provider)}: follow-up after assistant message with only whitespace text content`, async () => {
380
- /**
381
- * Regression for upstream discussion #12806.
382
- *
383
- * The Anthropic API has two distinct rejection rules (verified against
384
- * the live API):
385
- * 1. Strict empty `text: ''` → rejected anywhere
386
- * "messages: text content blocks must be non-empty"
387
- * 2. Whitespace-only `text: ' '` / '\n' / '\t' → rejected when the
388
- * assistant message has no other accepted blocks (no tool blocks,
389
- * no non-whitespace text)
390
- * "messages: text content blocks must contain non-whitespace text"
391
- *
392
- * Anthropic responses for some prompts include a whitespace-only text
393
- * block as the sole text content. Re-sending that history on a
394
- * follow-up turn triggers rule 2.
395
- *
396
- * The wire-send filter in `_formatContent` must drop any text block
397
- * whose trimmed content is empty. The previous filter used strict
398
- * `text === ''` only, which caught rule 1 but not rule 2.
399
- */
400
- const llmConfig = getLLMConfig(provider);
401
- const customHandlers1 = setupCustomHandlers();
402
-
403
- const followUpRun = await Run.create<t.IState>({
404
- runId: 'repro-12806-followup',
405
- graphConfig: {
406
- type: 'standard',
407
- llmConfig,
408
- instructions: 'You are a friendly AI assistant.',
409
- },
410
- returnContent: true,
411
- skipCleanup: true,
412
- customHandlers: customHandlers1,
413
- });
414
-
415
- // Build history with an assistant message whose entire content array
416
- // is a single whitespace-only text block. This is the precise shape
417
- // the API rejects under rule 2 above.
418
- conversationHistory = [
419
- new HumanMessage('hi'),
420
- new (require('@langchain/core/messages').AIMessage)({
421
- content: [{ type: 'text', text: ' ' }],
422
- }),
423
- new HumanMessage('please respond with a short greeting'),
424
- ];
425
-
426
- // With the fix: `_formatContent` drops the whitespace text block,
427
- // the assistant content becomes an empty array, and the API accepts.
428
- // Without the fix: the whitespace block is forwarded and the API
429
- // rejects with "messages: text content blocks must contain non-whitespace text".
430
- const finalContentParts = await followUpRun.processStream(
431
- { messages: conversationHistory },
432
- config
433
- );
434
- expect(finalContentParts).toBeDefined();
435
- const finalMessages = followUpRun.getRunMessages();
436
- expect(finalMessages).toBeDefined();
437
- expect(finalMessages?.length).toBeGreaterThan(0);
438
- });
439
-
440
379
  test('should handle errors appropriately', async () => {
441
380
  // Test error scenarios
442
381
  await expect(async () => {
@@ -4,23 +4,17 @@ import { HttpsProxyAgent } from 'https-proxy-agent';
4
4
  import { getEnvironmentVariable } from '@langchain/core/utils/env';
5
5
  import { tool, DynamicStructuredTool } from '@langchain/core/tools';
6
6
  import type * as t from '@/types';
7
- import { getCodeBaseURL, renderFileSection } from './CodeExecutor';
7
+ import { imageExtRegex, getCodeBaseURL } from './CodeExecutor';
8
8
  import { Constants, EnvVar } from '@/common';
9
9
 
10
10
  config();
11
11
 
12
+ const imageMessage = 'Image is already displayed to the user';
12
13
  const otherMessage = 'File is already downloaded by the user';
13
- const inheritedFileMessage =
14
- 'Available as an input — already known to the user';
15
14
  const accessMessage =
16
15
  'Note: Files from previous executions are automatically available and can be modified.';
17
16
  const emptyOutputMessage =
18
17
  "stdout: Empty. Ensure you're writing output explicitly.\n";
19
- const inheritedFilesHeader =
20
- 'Available files (inputs, not generated by this execution):';
21
- const generatedFilesHeader = 'Generated files:';
22
- const inheritedNote =
23
- 'Note: Files in "Available files" are inputs the user (or a skill) already provided to the sandbox. They were not produced by this execution and you should not present them as new outputs in your response.';
24
18
 
25
19
  export const BashExecutionToolSchema = {
26
20
  type: 'object',
@@ -221,38 +215,20 @@ function createBashExecutionTool(
221
215
  }
222
216
  if (result.stderr) formattedOutput += `stderr:\n${result.stderr}\n`;
223
217
  if (result.files && result.files.length > 0) {
224
- /* Split inherited (read-only / unchanged-input passthroughs from
225
- * codeapi) from genuine generated outputs. The LLM was previously
226
- * shown skill files under "Generated files:" with the message
227
- * "File is already downloaded by the user", which led it to
228
- * (a) believe it had just produced files it merely referenced
229
- * and (b) sometimes invent paths like /mnt/user-data/uploads/
230
- * trying to find the "originals". Labeling them as inputs makes
231
- * the mental model accurate. */
232
- const inheritedFiles = result.files.filter(
233
- (f) => f.inherited === true
234
- );
235
- const generatedFiles = result.files.filter(
236
- (f) => f.inherited !== true
237
- );
218
+ formattedOutput += 'Generated files:\n';
238
219
 
239
- formattedOutput += renderFileSection(
240
- generatedFilesHeader,
241
- generatedFiles,
242
- otherMessage
243
- );
244
- formattedOutput += renderFileSection(
245
- inheritedFilesHeader,
246
- inheritedFiles,
247
- inheritedFileMessage
248
- );
220
+ const fileCount = result.files.length;
221
+ for (let i = 0; i < fileCount; i++) {
222
+ const file = result.files[i];
223
+ const isImage = imageExtRegex.test(file.name);
224
+ formattedOutput += `- /mnt/data/${file.name} | ${isImage ? imageMessage : otherMessage}`;
249
225
 
250
- if (generatedFiles.length > 0) {
251
- formattedOutput += `\n\n${accessMessage}`;
252
- }
253
- if (inheritedFiles.length > 0) {
254
- formattedOutput += `\n\n${inheritedNote}`;
226
+ if (i < fileCount - 1) {
227
+ formattedOutput += fileCount <= 3 ? ', ' : ',\n';
228
+ }
255
229
  }
230
+
231
+ formattedOutput += `\n\n${accessMessage}`;
256
232
  return [
257
233
  formattedOutput.trim(),
258
234
  {
@@ -15,41 +15,10 @@ export const getCodeBaseURL = (): string =>
15
15
 
16
16
  const imageMessage = 'Image is already displayed to the user';
17
17
  const otherMessage = 'File is already downloaded by the user';
18
- const inheritedFileMessage =
19
- 'Available as an input — already known to the user';
20
18
  const accessMessage =
21
19
  'Note: Files from previous executions are automatically available and can be modified.';
22
20
  const emptyOutputMessage =
23
21
  "stdout: Empty. Ensure you're writing output explicitly.\n";
24
- const inheritedFilesHeader =
25
- 'Available files (inputs, not generated by this execution):';
26
- const generatedFilesHeader = 'Generated files:';
27
- const inheritedNote =
28
- 'Note: Files in "Available files" are inputs the user (or a skill) already provided to the sandbox. They were not produced by this execution and you should not present them as new outputs in your response.';
29
-
30
- /**
31
- * Renders one section of the post-execution file listing. Used by the
32
- * code/bash tool formatters to keep generated outputs and inherited
33
- * inputs visually separated. See BashExecutor for full docs.
34
- */
35
- export function renderFileSection(
36
- header: string,
37
- files: t.FileRefs,
38
- defaultMessage: string
39
- ): string {
40
- if (files.length === 0) return '';
41
- let out = `${header}\n`;
42
- for (let i = 0; i < files.length; i++) {
43
- const file = files[i];
44
- const isImage = imageExtRegex.test(file.name);
45
- out += `- /mnt/data/${file.name} | ${isImage ? imageMessage : defaultMessage}`;
46
- if (i < files.length - 1) {
47
- out += files.length <= 3 ? ', ' : ',\n';
48
- }
49
- }
50
- out += '\n';
51
- return out;
52
- }
53
22
 
54
23
  const SUPPORTED_LANGUAGES = [
55
24
  'py',
@@ -333,33 +302,20 @@ function createCodeExecutionTool(
333
302
  }
334
303
 
335
304
  if (result.files && result.files.length > 0) {
336
- /* Split inherited (read-only passthrough) inputs from real
337
- * generated outputs so the LLM doesn't conflate skill files
338
- * with newly-produced artifacts. */
339
- const inheritedFiles = result.files.filter(
340
- (f) => f.inherited === true
341
- );
342
- const generatedFiles = result.files.filter(
343
- (f) => f.inherited !== true
344
- );
305
+ formattedOutput += 'Generated files:\n';
345
306
 
346
- formattedOutput += renderFileSection(
347
- generatedFilesHeader,
348
- generatedFiles,
349
- otherMessage
350
- );
351
- formattedOutput += renderFileSection(
352
- inheritedFilesHeader,
353
- inheritedFiles,
354
- inheritedFileMessage
355
- );
307
+ const fileCount = result.files.length;
308
+ for (let i = 0; i < fileCount; i++) {
309
+ const file = result.files[i];
310
+ const isImage = imageExtRegex.test(file.name);
311
+ formattedOutput += `- /mnt/data/${file.name} | ${isImage ? imageMessage : otherMessage}`;
356
312
 
357
- if (generatedFiles.length > 0) {
358
- formattedOutput += `\n\n${accessMessage}`;
359
- }
360
- if (inheritedFiles.length > 0) {
361
- formattedOutput += `\n\n${inheritedNote}`;
313
+ if (i < fileCount - 1) {
314
+ formattedOutput += fileCount <= 3 ? ', ' : ',\n';
315
+ }
362
316
  }
317
+
318
+ formattedOutput += `\n\n${accessMessage}`;
363
319
  return [
364
320
  formattedOutput.trim(),
365
321
  {
@@ -6,7 +6,7 @@ import { getEnvironmentVariable } from '@langchain/core/utils/env';
6
6
  import { tool, DynamicStructuredTool } from '@langchain/core/tools';
7
7
  import type { ToolCall } from '@langchain/core/messages/tool';
8
8
  import type * as t from '@/types';
9
- import { getCodeBaseURL, renderFileSection } from './CodeExecutor';
9
+ import { imageExtRegex, getCodeBaseURL } from './CodeExecutor';
10
10
  import { EnvVar, Constants } from '@/common';
11
11
 
12
12
  config();
@@ -15,14 +15,8 @@ config();
15
15
  // Constants
16
16
  // ============================================================================
17
17
 
18
+ const imageMessage = 'Image is already displayed to the user';
18
19
  const otherMessage = 'File is already downloaded by the user';
19
- const inheritedFileMessage =
20
- 'Available as an input — already known to the user';
21
- const inheritedFilesHeader =
22
- 'Available files (inputs, not generated by this execution):';
23
- const generatedFilesHeader = 'Generated files:';
24
- const inheritedNote =
25
- 'Note: Files in "Available files" are inputs the user (or a skill) already provided to the sandbox. They were not produced by this execution and you should not present them as new outputs in your response.';
26
20
  const accessMessage =
27
21
  'Note: Files from previous executions are automatically available and can be modified.';
28
22
  const emptyOutputMessage =
@@ -569,29 +563,20 @@ export function formatCompletedResponse(
569
563
  }
570
564
 
571
565
  if (response.files && response.files.length > 0) {
572
- /* See BashExecutor for the rationale: split inherited (read-only
573
- * passthrough) inputs from real generated outputs so the LLM doesn't
574
- * conflate skill files with newly-produced artifacts. */
575
- const inheritedFiles = response.files.filter((f) => f.inherited === true);
576
- const generatedFiles = response.files.filter((f) => f.inherited !== true);
577
-
578
- formatted += renderFileSection(
579
- generatedFilesHeader,
580
- generatedFiles,
581
- otherMessage
582
- );
583
- formatted += renderFileSection(
584
- inheritedFilesHeader,
585
- inheritedFiles,
586
- inheritedFileMessage
587
- );
566
+ formatted += 'Generated files:\n';
588
567
 
589
- if (generatedFiles.length > 0) {
590
- formatted += `\n\n${accessMessage}`;
591
- }
592
- if (inheritedFiles.length > 0) {
593
- formatted += `\n\n${inheritedNote}`;
568
+ const fileCount = response.files.length;
569
+ for (let i = 0; i < fileCount; i++) {
570
+ const file = response.files[i];
571
+ const isImage = imageExtRegex.test(file.name);
572
+ formatted += `- /mnt/data/${file.name} | ${isImage ? imageMessage : otherMessage}`;
573
+
574
+ if (i < fileCount - 1) {
575
+ formatted += fileCount <= 3 ? ', ' : ',\n';
576
+ }
594
577
  }
578
+
579
+ formatted += `\n\n${accessMessage}`;
595
580
  }
596
581
 
597
582
  return [
@@ -754,19 +754,74 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
754
754
  }
755
755
  }
756
756
 
757
- // Field-level recovery: extract missing fields from the raw buffer
757
+ // Field-level recovery: extract missing fields from the raw buffer.
758
+ //
759
+ // Only attempt this when `parsedArgs` is missing top-level keys that
760
+ // appear at depth 0 in the raw JSON. The previous implementation walked
761
+ // EVERY `"key":` match the regex found — including keys nested inside
762
+ // arrays/objects like `steps[].options[].label` — and tried to "recover"
763
+ // them as top-level fields. That produced confusing log spam (false
764
+ // positives like `recoveredFields=[question,label,value]` for a clean
765
+ // multi-step `ask_user` call) and could inject stray top-level fields
766
+ // into `args` for downstream tool execution.
758
767
  const parsedArgs = typeof args === 'object' ? { ...args } : {};
759
768
  const recoveredFields: string[] = [];
760
769
 
761
- // Extract field names from the raw JSON string
762
- const fieldPattern = /"([^"]+)"\s*:/g;
763
- let match;
764
- const rawFieldNames: string[] = [];
765
- while ((match = fieldPattern.exec(rawArgs)) !== null) {
766
- rawFieldNames.push(match[1]);
770
+ /**
771
+ * Extract only TOP-LEVEL keys from the raw JSON. Walks the buffer
772
+ * tracking brace/bracket depth so nested keys are skipped.
773
+ */
774
+ const topLevelKeys: string[] = [];
775
+ let depth = 0;
776
+ let inString = false;
777
+ let escaped = false;
778
+ let i = 0;
779
+ while (i < rawArgs.length) {
780
+ const ch = rawArgs[i];
781
+ if (escaped) {
782
+ escaped = false;
783
+ i++;
784
+ continue;
785
+ }
786
+ if (inString) {
787
+ if (ch === '\\') escaped = true;
788
+ else if (ch === '"') inString = false;
789
+ i++;
790
+ continue;
791
+ }
792
+ if (ch === '"') {
793
+ // Possible key — only count if at depth 1 (inside the outer object)
794
+ const start = i + 1;
795
+ let j = start;
796
+ while (j < rawArgs.length) {
797
+ const c = rawArgs[j];
798
+ if (c === '\\') {
799
+ j += 2;
800
+ continue;
801
+ }
802
+ if (c === '"') break;
803
+ j++;
804
+ }
805
+ if (j < rawArgs.length) {
806
+ // Skip whitespace after closing quote and check for ':'
807
+ let k = j + 1;
808
+ while (k < rawArgs.length && /\s/.test(rawArgs[k])) k++;
809
+ if (depth === 1 && rawArgs[k] === ':') {
810
+ topLevelKeys.push(rawArgs.slice(start, j));
811
+ }
812
+ i = j + 1;
813
+ continue;
814
+ }
815
+ inString = true;
816
+ i++;
817
+ continue;
818
+ }
819
+ if (ch === '{' || ch === '[') depth++;
820
+ else if (ch === '}' || ch === ']') depth--;
821
+ i++;
767
822
  }
768
823
 
769
- for (const fieldName of rawFieldNames) {
824
+ for (const fieldName of topLevelKeys) {
770
825
  if (
771
826
  parsedArgs[fieldName] == null ||
772
827
  parsedArgs[fieldName] === '' ||
@@ -991,6 +1046,12 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
991
1046
  // Dispatch ON_RUN_STEP_COMPLETED via custom event (same path as dispatchToolEvents)
992
1047
  const stepId = this.toolCallStepIds?.get(toolCallId) ?? '';
993
1048
  if (!stepId) {
1049
+ // eslint-disable-next-line no-console
1050
+ console.warn(
1051
+ `[ToolNode.handleRunToolCompletions] missing stepId for toolCallId=${toolCallId} ` +
1052
+ `name=${call.name} — ON_RUN_STEP_COMPLETED skipped, output will not be persisted. ` +
1053
+ `If this is a resumed HITL tool call, verify Graph.resetValues preserves toolCallStepIds when keepContent=true.`
1054
+ );
994
1055
  continue;
995
1056
  }
996
1057
 
@@ -664,66 +664,6 @@ for member in team:
664
664
  expect(output).toContain('chart.png');
665
665
  expect(output).toContain('Image is already displayed to the user');
666
666
  });
667
-
668
- it('splits inherited inputs from generated outputs into distinct sections', () => {
669
- const response: t.ProgrammaticExecutionResponse = {
670
- status: 'completed',
671
- stdout: 'analysis done\n',
672
- stderr: '',
673
- files: [
674
- { id: 'g1', name: 'report.pdf' },
675
- { id: 'i1', name: 'pptx/SKILL.md', inherited: true },
676
- { id: 'i2', name: 'pptx/scripts/clean.py', inherited: true },
677
- { id: 'g2', name: 'chart.png' },
678
- ],
679
- session_id: 'sess_abc123',
680
- };
681
-
682
- const [output, artifact] = formatCompletedResponse(response);
683
-
684
- /* Generated section lists only outputs the run produced. */
685
- const generatedIdx = output.indexOf('Generated files:');
686
- const inheritedIdx = output.indexOf('Available files (inputs');
687
- expect(generatedIdx).toBeGreaterThan(-1);
688
- expect(inheritedIdx).toBeGreaterThan(generatedIdx);
689
-
690
- /* Slice each section so we can assert membership without
691
- * cross-talk between the two listings. */
692
- const generatedSection = output.slice(generatedIdx, inheritedIdx);
693
- const inheritedSection = output.slice(inheritedIdx);
694
-
695
- expect(generatedSection).toContain('report.pdf');
696
- expect(generatedSection).toContain('chart.png');
697
- expect(generatedSection).not.toContain('SKILL.md');
698
-
699
- expect(inheritedSection).toContain('pptx/SKILL.md');
700
- expect(inheritedSection).toContain('pptx/scripts/clean.py');
701
- expect(inheritedSection).toContain('Available as an input');
702
-
703
- /* The artifact still carries every file so the host can still
704
- * thread per-file ids through to subsequent calls. */
705
- expect(artifact.files).toHaveLength(4);
706
- });
707
-
708
- it('omits the Generated files header when every entry is inherited', () => {
709
- const response: t.ProgrammaticExecutionResponse = {
710
- status: 'completed',
711
- stdout: 'cat: ok\n',
712
- stderr: '',
713
- files: [
714
- { id: 'i1', name: 'pptx/SKILL.md', inherited: true },
715
- { id: 'i2', name: 'pptx/editing.md', inherited: true },
716
- ],
717
- session_id: 'sess_abc123',
718
- };
719
-
720
- const [output] = formatCompletedResponse(response);
721
-
722
- expect(output).not.toContain('Generated files:');
723
- expect(output).toContain('Available files (inputs');
724
- expect(output).toContain('pptx/SKILL.md');
725
- expect(output).toContain('pptx/editing.md');
726
- });
727
667
  });
728
668
 
729
669
  describe('createProgrammaticToolCallingTool - Manual Invocation', () => {
@@ -546,6 +546,163 @@ describe('SubagentExecutor', () => {
546
546
  expect(observedChildInputs!.maxSubagentDepth).toBeUndefined();
547
547
  });
548
548
 
549
+ describe('parentConfigurable inheritance', () => {
550
+ /**
551
+ * Build a stub factory that captures the second argument to
552
+ * `workflow.invoke()` (the runnable config) so tests can assert on
553
+ * the `configurable` we forwarded to the child graph.
554
+ */
555
+ function makeCapturingGraphFactory(): {
556
+ factory: () => StandardGraph;
557
+ getInvokeConfig: () => Record<string, unknown> | undefined;
558
+ } {
559
+ let capturedConfig: Record<string, unknown> | undefined;
560
+ const factory = (): StandardGraph =>
561
+ ({
562
+ createWorkflow: (): { invoke: jest.Mock } => ({
563
+ invoke: jest
564
+ .fn()
565
+ .mockImplementation(
566
+ async (
567
+ _input: unknown,
568
+ config: Record<string, unknown>
569
+ ): Promise<{ messages: BaseMessage[] }> => {
570
+ capturedConfig = config;
571
+ return { messages: [new AIMessage('done')] };
572
+ }
573
+ ),
574
+ }),
575
+ clearHeavyState: jest.fn(),
576
+ }) as unknown as StandardGraph;
577
+ return { factory, getInvokeConfig: () => capturedConfig };
578
+ }
579
+
580
+ it('forwards parentConfigurable into the child workflow.invoke configurable', async () => {
581
+ const { factory, getInvokeConfig } = makeCapturingGraphFactory();
582
+ const executor = createExecutor({ createChildGraph: factory });
583
+
584
+ await executor.execute({
585
+ description: 'task',
586
+ subagentType: 'researcher',
587
+ parentConfigurable: {
588
+ requestBody: { messageId: 'msg-123', conversationId: 'conv-456' },
589
+ user: { id: 'user_abc' },
590
+ user_id: 'user_abc',
591
+ userMCPAuthMap: { 'mcp-github': { token: 'abc' } },
592
+ },
593
+ });
594
+
595
+ const invokeConfig = getInvokeConfig();
596
+ expect(invokeConfig).toBeDefined();
597
+ const configurable = invokeConfig!.configurable as Record<
598
+ string,
599
+ unknown
600
+ >;
601
+ expect(configurable.requestBody).toEqual({
602
+ messageId: 'msg-123',
603
+ conversationId: 'conv-456',
604
+ });
605
+ expect(configurable.user).toEqual({ id: 'user_abc' });
606
+ expect(configurable.user_id).toBe('user_abc');
607
+ expect(configurable.userMCPAuthMap).toEqual({
608
+ 'mcp-github': { token: 'abc' },
609
+ });
610
+ });
611
+
612
+ it('inherits parent thread_id when supplied (subagent is part of same conversation)', async () => {
613
+ const { factory, getInvokeConfig } = makeCapturingGraphFactory();
614
+ const executor = createExecutor({
615
+ createChildGraph: factory,
616
+ parentRunId: 'parent-run-xyz',
617
+ });
618
+
619
+ await executor.execute({
620
+ description: 'task',
621
+ subagentType: 'researcher',
622
+ parentConfigurable: { thread_id: 'parent-thread-conv-abc' },
623
+ });
624
+
625
+ const configurable = getInvokeConfig()!.configurable as Record<
626
+ string,
627
+ unknown
628
+ >;
629
+ expect(configurable.thread_id).toBe('parent-thread-conv-abc');
630
+ });
631
+
632
+ it('falls back to childRunId for thread_id when parent did not supply one', async () => {
633
+ const { factory, getInvokeConfig } = makeCapturingGraphFactory();
634
+ const executor = createExecutor({
635
+ createChildGraph: factory,
636
+ parentRunId: 'parent-run-xyz',
637
+ });
638
+
639
+ await executor.execute({
640
+ description: 'task',
641
+ subagentType: 'researcher',
642
+ parentConfigurable: { user_id: 'user_abc' },
643
+ });
644
+
645
+ const configurable = getInvokeConfig()!.configurable as Record<
646
+ string,
647
+ unknown
648
+ >;
649
+ expect(configurable.thread_id as string).toMatch(/^parent-run-xyz_sub_/);
650
+ expect(configurable.user_id).toBe('user_abc');
651
+ });
652
+
653
+ it('forwards run-identity fields verbatim into the child invoke configurable', async () => {
654
+ const { factory, getInvokeConfig } = makeCapturingGraphFactory();
655
+ const executor = createExecutor({ createChildGraph: factory });
656
+
657
+ await executor.execute({
658
+ description: 'task',
659
+ subagentType: 'researcher',
660
+ parentConfigurable: {
661
+ run_id: 'parent-run-id',
662
+ parent_run_id: 'grandparent-run-id',
663
+ requestBody: { messageId: 'msg-1' },
664
+ },
665
+ });
666
+
667
+ const configurable = getInvokeConfig()!.configurable as Record<
668
+ string,
669
+ unknown
670
+ >;
671
+ // The SDK forwards these fields as part of its inheritance contract.
672
+ // NOTE: the LangGraph runtime overwrites `configurable.run_id` at
673
+ // actual child-invoke time (verified empirically); this unit test
674
+ // only asserts what the SDK forwards into `workflow.invoke` — not
675
+ // what tools downstream observe. `parent_run_id` and other
676
+ // host-set keys do survive the runtime pass-through.
677
+ expect(configurable.run_id).toBe('parent-run-id');
678
+ expect(configurable.parent_run_id).toBe('grandparent-run-id');
679
+ expect(configurable.requestBody).toEqual({ messageId: 'msg-1' });
680
+ });
681
+
682
+ it('does not require parentConfigurable (back-compat with hosts that omit it)', async () => {
683
+ const { factory, getInvokeConfig } = makeCapturingGraphFactory();
684
+ const executor = createExecutor({ createChildGraph: factory });
685
+
686
+ await executor.execute({
687
+ description: 'task',
688
+ subagentType: 'researcher',
689
+ });
690
+
691
+ const configurable = getInvokeConfig()!.configurable as Record<
692
+ string,
693
+ unknown
694
+ >;
695
+ // Only thread_id (childRunId fallback) and the host-attached
696
+ // parentToolCallId (used by ranger for attachment routing) are set
697
+ // when no parent context is supplied. parentToolCallId is undefined
698
+ // here because no tool_call_id was passed in the metadata.
699
+ expect(Object.keys(configurable).sort()).toEqual(
700
+ ['parentToolCallId', 'thread_id'].sort()
701
+ );
702
+ expect(configurable.parentToolCallId).toBeUndefined();
703
+ });
704
+ });
705
+
549
706
  describe('hooks', () => {
550
707
  let capturedStart: unknown;
551
708
  let capturedStop: unknown;
@@ -2,7 +2,6 @@ import axios from 'axios';
2
2
  import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
3
3
  import type * as t from './types';
4
4
  import { getAttribution, createDefaultLogger } from './utils';
5
- import { createTavilyAPI } from './tavily-search';
6
5
  import { BaseReranker } from './rerankers';
7
6
 
8
7
  const chunker = {
@@ -439,9 +438,6 @@ export const createSearchAPI = (
439
438
  serperApiKey,
440
439
  searxngInstanceUrl,
441
440
  searxngApiKey,
442
- tavilyApiKey,
443
- tavilySearchUrl,
444
- tavilySearchOptions,
445
441
  domainBlocklist,
446
442
  countryBlocklist,
447
443
  } = config;
@@ -450,11 +446,9 @@ export const createSearchAPI = (
450
446
  return createSerperAPI(serperApiKey, domainBlocklist, countryBlocklist);
451
447
  } else if (searchProvider.toLowerCase() === 'searxng') {
452
448
  return createSearXNGAPI(searxngInstanceUrl, searxngApiKey);
453
- } else if (searchProvider.toLowerCase() === 'tavily') {
454
- return createTavilyAPI(tavilyApiKey, tavilySearchUrl, tavilySearchOptions);
455
449
  } else {
456
450
  throw new Error(
457
- `Invalid search provider: ${searchProvider}. Must be 'serper', 'searxng', or 'tavily'`
451
+ `Invalid search provider: ${searchProvider}. Must be 'serper' or 'searxng'`
458
452
  );
459
453
  }
460
454
  };
@@ -500,13 +494,9 @@ export const createSourceProcessor = (
500
494
  const promise: Promise<t.ScrapeResult> = scraper
501
495
  .scrapeUrl(currentLink, {})
502
496
  .then(([url, response]) => {
503
- /* metadata exists on Firecrawl/Serper responses but not on
504
- * Tavily's. Read it via the scraper's extractMetadata abstraction
505
- * to stay polymorphic across all scraper providers. */
506
- const rawMeta = scraper.extractMetadata(response);
507
497
  const attribution = getAttribution(
508
498
  url,
509
- Object.keys(rawMeta).length > 0 ? rawMeta : undefined,
499
+ response.data?.metadata,
510
500
  logger_
511
501
  );
512
502
  if (response.success && response.data) {