@illuma-ai/agents 1.4.0-alpha.6 → 1.5.0

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 (800) hide show
  1. package/README.md +62 -0
  2. package/dist/cjs/agents/AgentContext.cjs +274 -67
  3. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  4. package/dist/cjs/common/enum.cjs +44 -13
  5. package/dist/cjs/common/enum.cjs.map +1 -1
  6. package/dist/cjs/graphs/Graph.cjs +182 -5
  7. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  8. package/dist/cjs/graphs/MultiAgentGraph.cjs +152 -1167
  9. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  10. package/dist/cjs/hooks/HookRegistry.cjs +162 -0
  11. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -0
  12. package/dist/cjs/hooks/executeHooks.cjs +276 -0
  13. package/dist/cjs/hooks/executeHooks.cjs.map +1 -0
  14. package/dist/cjs/hooks/matchers.cjs +256 -0
  15. package/dist/cjs/hooks/matchers.cjs.map +1 -0
  16. package/dist/cjs/hooks/types.cjs +27 -0
  17. package/dist/cjs/hooks/types.cjs.map +1 -0
  18. package/dist/cjs/langchain/google-common.cjs +3 -0
  19. package/dist/cjs/langchain/google-common.cjs.map +1 -0
  20. package/dist/cjs/langchain/index.cjs +86 -0
  21. package/dist/cjs/langchain/index.cjs.map +1 -0
  22. package/dist/cjs/langchain/language_models/chat_models.cjs +3 -0
  23. package/dist/cjs/langchain/language_models/chat_models.cjs.map +1 -0
  24. package/dist/cjs/langchain/messages/tool.cjs +3 -0
  25. package/dist/cjs/langchain/messages/tool.cjs.map +1 -0
  26. package/dist/cjs/langchain/messages.cjs +51 -0
  27. package/dist/cjs/langchain/messages.cjs.map +1 -0
  28. package/dist/cjs/langchain/openai.cjs +3 -0
  29. package/dist/cjs/langchain/openai.cjs.map +1 -0
  30. package/dist/cjs/langchain/prompts.cjs +11 -0
  31. package/dist/cjs/langchain/prompts.cjs.map +1 -0
  32. package/dist/cjs/langchain/runnables.cjs +19 -0
  33. package/dist/cjs/langchain/runnables.cjs.map +1 -0
  34. package/dist/cjs/langchain/tools.cjs +23 -0
  35. package/dist/cjs/langchain/tools.cjs.map +1 -0
  36. package/dist/cjs/langchain/utils/env.cjs +11 -0
  37. package/dist/cjs/langchain/utils/env.cjs.map +1 -0
  38. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +5 -1
  39. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  40. package/dist/cjs/llm/bedrock/cacheSupport.cjs +55 -0
  41. package/dist/cjs/llm/bedrock/cacheSupport.cjs.map +1 -0
  42. package/dist/cjs/llm/bedrock/index.cjs +61 -33
  43. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  44. package/dist/cjs/llm/openai/index.cjs +0 -3
  45. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  46. package/dist/cjs/llm/openai/utils/index.cjs +27 -10
  47. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  48. package/dist/cjs/main.cjs +178 -127
  49. package/dist/cjs/main.cjs.map +1 -1
  50. package/dist/cjs/messages/cache.cjs +89 -0
  51. package/dist/cjs/messages/cache.cjs.map +1 -1
  52. package/dist/cjs/messages/contextPruning.cjs +156 -0
  53. package/dist/cjs/messages/contextPruning.cjs.map +1 -0
  54. package/dist/cjs/messages/contextPruningSettings.cjs +53 -0
  55. package/dist/cjs/messages/contextPruningSettings.cjs.map +1 -0
  56. package/dist/cjs/messages/format.cjs +144 -20
  57. package/dist/cjs/messages/format.cjs.map +1 -1
  58. package/dist/cjs/messages/prune.cjs +505 -4
  59. package/dist/cjs/messages/prune.cjs.map +1 -1
  60. package/dist/cjs/run.cjs +141 -1
  61. package/dist/cjs/run.cjs.map +1 -1
  62. package/dist/cjs/tools/BashExecutor.cjs +235 -0
  63. package/dist/cjs/tools/BashExecutor.cjs.map +1 -0
  64. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +297 -0
  65. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -0
  66. package/dist/cjs/tools/CodeExecutor.cjs +44 -47
  67. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  68. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +16 -11
  69. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  70. package/dist/cjs/tools/ReadFile.cjs +44 -0
  71. package/dist/cjs/tools/ReadFile.cjs.map +1 -0
  72. package/dist/cjs/tools/SkillTool.cjs +51 -0
  73. package/dist/cjs/tools/SkillTool.cjs.map +1 -0
  74. package/dist/cjs/tools/SubagentTool.cjs +93 -0
  75. package/dist/cjs/tools/SubagentTool.cjs.map +1 -0
  76. package/dist/cjs/tools/ToolNode.cjs +450 -24
  77. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  78. package/dist/cjs/tools/search/search.cjs +11 -3
  79. package/dist/cjs/tools/search/search.cjs.map +1 -1
  80. package/dist/cjs/tools/search/tavily-scraper.cjs +189 -0
  81. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -0
  82. package/dist/cjs/tools/search/tavily-search.cjs +372 -0
  83. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -0
  84. package/dist/cjs/tools/search/tool.cjs +28 -4
  85. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  86. package/dist/cjs/tools/search/utils.cjs +10 -3
  87. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  88. package/dist/cjs/tools/skillCatalog.cjs +84 -0
  89. package/dist/cjs/tools/skillCatalog.cjs.map +1 -0
  90. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +512 -0
  91. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -0
  92. package/dist/cjs/tools/toolOutputReferences.cjs +670 -0
  93. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -0
  94. package/dist/cjs/types/agent-cache.cjs +53 -0
  95. package/dist/cjs/types/agent-cache.cjs.map +1 -0
  96. package/dist/cjs/types/graph.cjs.map +1 -1
  97. package/dist/cjs/utils/truncation.cjs +135 -0
  98. package/dist/cjs/utils/truncation.cjs.map +1 -0
  99. package/dist/esm/agents/AgentContext.mjs +274 -67
  100. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  101. package/dist/esm/common/enum.mjs +44 -12
  102. package/dist/esm/common/enum.mjs.map +1 -1
  103. package/dist/esm/graphs/Graph.mjs +182 -5
  104. package/dist/esm/graphs/Graph.mjs.map +1 -1
  105. package/dist/esm/graphs/MultiAgentGraph.mjs +155 -1170
  106. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  107. package/dist/esm/hooks/HookRegistry.mjs +160 -0
  108. package/dist/esm/hooks/HookRegistry.mjs.map +1 -0
  109. package/dist/esm/hooks/executeHooks.mjs +273 -0
  110. package/dist/esm/hooks/executeHooks.mjs.map +1 -0
  111. package/dist/esm/hooks/matchers.mjs +251 -0
  112. package/dist/esm/hooks/matchers.mjs.map +1 -0
  113. package/dist/esm/hooks/types.mjs +25 -0
  114. package/dist/esm/hooks/types.mjs.map +1 -0
  115. package/dist/esm/langchain/google-common.mjs +2 -0
  116. package/dist/esm/langchain/google-common.mjs.map +1 -0
  117. package/dist/esm/langchain/index.mjs +5 -0
  118. package/dist/esm/langchain/language_models/chat_models.mjs +2 -0
  119. package/dist/esm/langchain/language_models/chat_models.mjs.map +1 -0
  120. package/dist/esm/langchain/messages/tool.mjs +2 -0
  121. package/dist/esm/langchain/messages/tool.mjs.map +1 -0
  122. package/dist/esm/langchain/messages.mjs +2 -0
  123. package/dist/esm/langchain/messages.mjs.map +1 -0
  124. package/dist/esm/langchain/openai.mjs +2 -0
  125. package/dist/esm/langchain/openai.mjs.map +1 -0
  126. package/dist/esm/langchain/prompts.mjs +2 -0
  127. package/dist/esm/langchain/prompts.mjs.map +1 -0
  128. package/dist/esm/langchain/runnables.mjs +2 -0
  129. package/dist/esm/langchain/runnables.mjs.map +1 -0
  130. package/dist/esm/langchain/tools.mjs +2 -0
  131. package/dist/esm/langchain/tools.mjs.map +1 -0
  132. package/dist/esm/langchain/utils/env.mjs +2 -0
  133. package/dist/esm/langchain/utils/env.mjs.map +1 -0
  134. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +5 -1
  135. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  136. package/dist/esm/llm/bedrock/cacheSupport.mjs +52 -0
  137. package/dist/esm/llm/bedrock/cacheSupport.mjs.map +1 -0
  138. package/dist/esm/llm/bedrock/index.mjs +61 -34
  139. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  140. package/dist/esm/llm/openai/index.mjs +0 -3
  141. package/dist/esm/llm/openai/index.mjs.map +1 -1
  142. package/dist/esm/llm/openai/utils/index.mjs +27 -10
  143. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  144. package/dist/esm/main.mjs +21 -27
  145. package/dist/esm/main.mjs.map +1 -1
  146. package/dist/esm/messages/cache.mjs +89 -0
  147. package/dist/esm/messages/cache.mjs.map +1 -1
  148. package/dist/esm/messages/contextPruning.mjs +154 -0
  149. package/dist/esm/messages/contextPruning.mjs.map +1 -0
  150. package/dist/esm/messages/contextPruningSettings.mjs +50 -0
  151. package/dist/esm/messages/contextPruningSettings.mjs.map +1 -0
  152. package/dist/esm/messages/format.mjs +136 -12
  153. package/dist/esm/messages/format.mjs.map +1 -1
  154. package/dist/esm/messages/prune.mjs +504 -7
  155. package/dist/esm/messages/prune.mjs.map +1 -1
  156. package/dist/esm/run.mjs +141 -1
  157. package/dist/esm/run.mjs.map +1 -1
  158. package/dist/esm/tools/BashExecutor.mjs +227 -0
  159. package/dist/esm/tools/BashExecutor.mjs.map +1 -0
  160. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +288 -0
  161. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -0
  162. package/dist/esm/tools/CodeExecutor.mjs +44 -48
  163. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  164. package/dist/esm/tools/ProgrammaticToolCalling.mjs +17 -12
  165. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  166. package/dist/esm/tools/ReadFile.mjs +39 -0
  167. package/dist/esm/tools/ReadFile.mjs.map +1 -0
  168. package/dist/esm/tools/SkillTool.mjs +46 -0
  169. package/dist/esm/tools/SkillTool.mjs.map +1 -0
  170. package/dist/esm/tools/SubagentTool.mjs +86 -0
  171. package/dist/esm/tools/SubagentTool.mjs.map +1 -0
  172. package/dist/esm/tools/ToolNode.mjs +452 -26
  173. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  174. package/dist/esm/tools/search/search.mjs +11 -3
  175. package/dist/esm/tools/search/search.mjs.map +1 -1
  176. package/dist/esm/tools/search/tavily-scraper.mjs +186 -0
  177. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -0
  178. package/dist/esm/tools/search/tavily-search.mjs +370 -0
  179. package/dist/esm/tools/search/tavily-search.mjs.map +1 -0
  180. package/dist/esm/tools/search/tool.mjs +28 -4
  181. package/dist/esm/tools/search/tool.mjs.map +1 -1
  182. package/dist/esm/tools/search/utils.mjs +10 -3
  183. package/dist/esm/tools/search/utils.mjs.map +1 -1
  184. package/dist/esm/tools/skillCatalog.mjs +82 -0
  185. package/dist/esm/tools/skillCatalog.mjs.map +1 -0
  186. package/dist/esm/tools/subagent/SubagentExecutor.mjs +506 -0
  187. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -0
  188. package/dist/esm/tools/toolOutputReferences.mjs +662 -0
  189. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -0
  190. package/dist/esm/types/agent-cache.mjs +51 -0
  191. package/dist/esm/types/agent-cache.mjs.map +1 -0
  192. package/dist/esm/types/graph.mjs.map +1 -1
  193. package/dist/esm/utils/truncation.mjs +128 -0
  194. package/dist/esm/utils/truncation.mjs.map +1 -0
  195. package/dist/types/agents/AgentContext.d.ts +101 -8
  196. package/dist/types/common/enum.d.ts +39 -12
  197. package/dist/types/common/index.d.ts +0 -1
  198. package/dist/types/graphs/Graph.d.ts +43 -0
  199. package/dist/types/graphs/MultiAgentGraph.d.ts +26 -150
  200. package/dist/types/graphs/index.d.ts +0 -1
  201. package/dist/types/hooks/HookRegistry.d.ts +56 -0
  202. package/dist/types/hooks/executeHooks.d.ts +79 -0
  203. package/dist/types/hooks/index.d.ts +6 -0
  204. package/dist/types/hooks/matchers.d.ts +95 -0
  205. package/dist/types/hooks/types.d.ts +320 -0
  206. package/dist/types/index.d.ts +9 -9
  207. package/dist/types/langchain/google-common.d.ts +1 -0
  208. package/dist/types/langchain/index.d.ts +8 -0
  209. package/dist/types/langchain/language_models/chat_models.d.ts +1 -0
  210. package/dist/types/langchain/messages/tool.d.ts +1 -0
  211. package/dist/types/langchain/messages.d.ts +2 -0
  212. package/dist/types/langchain/openai.d.ts +1 -0
  213. package/dist/types/langchain/prompts.d.ts +1 -0
  214. package/dist/types/langchain/runnables.d.ts +2 -0
  215. package/dist/types/langchain/tools.d.ts +2 -0
  216. package/dist/types/langchain/utils/env.d.ts +1 -0
  217. package/dist/types/llm/bedrock/cacheSupport.d.ts +35 -0
  218. package/dist/types/llm/bedrock/index.d.ts +54 -1
  219. package/dist/types/messages/contextPruning.d.ts +42 -0
  220. package/dist/types/messages/contextPruningSettings.d.ts +44 -0
  221. package/dist/types/messages/format.d.ts +9 -1
  222. package/dist/types/messages/index.d.ts +2 -0
  223. package/dist/types/messages/prune.d.ts +91 -1
  224. package/dist/types/run.d.ts +2 -0
  225. package/dist/types/tools/BashExecutor.d.ts +76 -0
  226. package/dist/types/tools/BashProgrammaticToolCalling.d.ts +72 -0
  227. package/dist/types/tools/CodeExecutor.d.ts +8 -26
  228. package/dist/types/tools/ReadFile.d.ts +28 -0
  229. package/dist/types/tools/SkillTool.d.ts +40 -0
  230. package/dist/types/tools/SubagentTool.d.ts +36 -0
  231. package/dist/types/tools/ToolNode.d.ts +77 -5
  232. package/dist/types/tools/search/tavily-scraper.d.ts +19 -0
  233. package/dist/types/tools/search/tavily-search.d.ts +4 -0
  234. package/dist/types/tools/search/types.d.ts +99 -5
  235. package/dist/types/tools/search/utils.d.ts +2 -2
  236. package/dist/types/tools/skillCatalog.d.ts +19 -0
  237. package/dist/types/tools/subagent/SubagentExecutor.d.ts +137 -0
  238. package/dist/types/tools/subagent/index.d.ts +2 -0
  239. package/dist/types/tools/subagent/types.d.ts +84 -0
  240. package/dist/types/tools/toolOutputReferences.d.ts +236 -0
  241. package/dist/types/types/agent-cache.d.ts +70 -0
  242. package/dist/types/types/graph.d.ts +162 -22
  243. package/dist/types/types/index.d.ts +3 -0
  244. package/dist/types/types/messages.d.ts +26 -0
  245. package/dist/types/types/run.d.ts +22 -0
  246. package/dist/types/types/skill.d.ts +9 -0
  247. package/dist/types/types/tools.d.ts +111 -0
  248. package/dist/types/utils/index.d.ts +1 -3
  249. package/dist/types/utils/truncation.d.ts +70 -0
  250. package/package.json +57 -17
  251. package/src/agents/AgentContext.js.map +1 -0
  252. package/src/agents/AgentContext.test.js.map +1 -0
  253. package/src/agents/AgentContext.ts +321 -78
  254. package/src/agents/__tests__/AgentContext.cacheTtl.live.test.ts +259 -0
  255. package/src/agents/__tests__/AgentContext.crossAgentTier1.live.test.ts +264 -0
  256. package/src/agents/__tests__/AgentContext.crossUserCache.live.test.ts +342 -0
  257. package/src/agents/__tests__/AgentContext.test.js.map +1 -0
  258. package/src/agents/__tests__/AgentContext.test.ts +632 -0
  259. package/src/agents/__tests__/resolveStructuredOutputMode.test.js.map +1 -0
  260. package/src/common/__tests__/enum.test.ts +7 -17
  261. package/src/common/enum.js.map +1 -0
  262. package/src/common/enum.ts +43 -12
  263. package/src/common/index.js.map +1 -0
  264. package/src/common/index.ts +0 -1
  265. package/src/events.js.map +1 -0
  266. package/src/graphs/Graph.js.map +1 -0
  267. package/src/graphs/Graph.ts +222 -2
  268. package/src/graphs/MultiAgentGraph.js.map +1 -0
  269. package/src/graphs/MultiAgentGraph.ts +154 -1466
  270. package/src/graphs/__tests__/MultiAgentGraph.test.ts +91 -0
  271. package/src/graphs/__tests__/structured-output.integration.test.js.map +1 -0
  272. package/src/graphs/__tests__/structured-output.test.js.map +1 -0
  273. package/src/graphs/contextManagement.e2e.test.js.map +1 -0
  274. package/src/graphs/contextManagement.test.js.map +1 -0
  275. package/src/graphs/handoffValidation.test.js.map +1 -0
  276. package/src/graphs/index.js.map +1 -0
  277. package/src/graphs/index.ts +0 -1
  278. package/src/hooks/HookRegistry.ts +208 -0
  279. package/src/hooks/__tests__/HookRegistry.test.ts +190 -0
  280. package/src/hooks/__tests__/compactHooks.test.ts +214 -0
  281. package/src/hooks/__tests__/executeHooks.test.ts +1013 -0
  282. package/src/hooks/__tests__/integration.test.ts +337 -0
  283. package/src/hooks/__tests__/matchers.test.ts +238 -0
  284. package/src/hooks/__tests__/toolHooks.test.ts +665 -0
  285. package/src/hooks/executeHooks.ts +375 -0
  286. package/src/hooks/index.ts +57 -0
  287. package/src/hooks/matchers.ts +280 -0
  288. package/src/hooks/types.ts +404 -0
  289. package/src/index.js.map +1 -0
  290. package/src/index.ts +15 -24
  291. package/src/instrumentation.js.map +1 -0
  292. package/src/langchain/google-common.ts +1 -0
  293. package/src/langchain/index.ts +8 -0
  294. package/src/langchain/language_models/chat_models.ts +1 -0
  295. package/src/langchain/messages/tool.ts +5 -0
  296. package/src/langchain/messages.ts +21 -0
  297. package/src/langchain/openai.ts +1 -0
  298. package/src/langchain/prompts.ts +1 -0
  299. package/src/langchain/runnables.ts +7 -0
  300. package/src/langchain/tools.ts +8 -0
  301. package/src/langchain/utils/env.ts +1 -0
  302. package/src/llm/anthropic/index.js.map +1 -0
  303. package/src/llm/anthropic/types.js.map +1 -0
  304. package/src/llm/anthropic/utils/message_inputs.js.map +1 -0
  305. package/src/llm/anthropic/utils/message_inputs.ts +10 -1
  306. package/src/llm/anthropic/utils/message_outputs.js.map +1 -0
  307. package/src/llm/anthropic/utils/output_parsers.js.map +1 -0
  308. package/src/llm/anthropic/utils/server-tool-inputs.test.ts +436 -0
  309. package/src/llm/anthropic/utils/tools.js.map +1 -0
  310. package/src/llm/bedrock/__tests__/bedrock-caching.test.js.map +1 -0
  311. package/src/llm/bedrock/__tests__/bedrock-caching.test.ts +166 -18
  312. package/src/llm/bedrock/cacheSupport.test.ts +99 -0
  313. package/src/llm/bedrock/cacheSupport.ts +53 -0
  314. package/src/llm/bedrock/index.js.map +1 -0
  315. package/src/llm/bedrock/index.ts +116 -41
  316. package/src/llm/bedrock/types.js.map +1 -0
  317. package/src/llm/bedrock/utils/index.js.map +1 -0
  318. package/src/llm/bedrock/utils/message_inputs.js.map +1 -0
  319. package/src/llm/bedrock/utils/message_outputs.js.map +1 -0
  320. package/src/llm/fake.js.map +1 -0
  321. package/src/llm/google/index.js.map +1 -0
  322. package/src/llm/google/types.js.map +1 -0
  323. package/src/llm/google/utils/common.js.map +1 -0
  324. package/src/llm/google/utils/tools.js.map +1 -0
  325. package/src/llm/google/utils/zod_to_genai_parameters.js.map +1 -0
  326. package/src/llm/openai/index.js.map +1 -0
  327. package/src/llm/openai/types.js.map +1 -0
  328. package/src/llm/openai/utils/index.js.map +1 -0
  329. package/src/llm/openai/utils/index.ts +31 -14
  330. package/src/llm/openai/utils/isReasoningModel.test.js.map +1 -0
  331. package/src/llm/openrouter/index.js.map +1 -0
  332. package/src/llm/openrouter/reasoning.test.js.map +1 -0
  333. package/src/llm/providers.js.map +1 -0
  334. package/src/llm/text.js.map +1 -0
  335. package/src/llm/vertexai/index.js.map +1 -0
  336. package/src/messages/__tests__/contextPruning.test.ts +228 -0
  337. package/src/messages/__tests__/tools.test.js.map +1 -0
  338. package/src/messages/cache.js.map +1 -0
  339. package/src/messages/cache.test.js.map +1 -0
  340. package/src/messages/cache.test.ts +62 -24
  341. package/src/messages/cache.ts +112 -0
  342. package/src/messages/content.js.map +1 -0
  343. package/src/messages/content.test.js.map +1 -0
  344. package/src/messages/contextPruning.ts +191 -0
  345. package/src/messages/contextPruningSettings.ts +90 -0
  346. package/src/messages/core.js.map +1 -0
  347. package/src/messages/ensureThinkingBlock.test.js.map +1 -0
  348. package/src/messages/format.js.map +1 -0
  349. package/src/messages/format.ts +164 -12
  350. package/src/messages/formatAgentMessages.skills.test.ts +413 -0
  351. package/src/messages/formatAgentMessages.test.js.map +1 -0
  352. package/src/messages/formatAgentMessages.tools.test.js.map +1 -0
  353. package/src/messages/formatMessage.test.js.map +1 -0
  354. package/src/messages/ids.js.map +1 -0
  355. package/src/messages/index.js.map +1 -0
  356. package/src/messages/index.ts +2 -0
  357. package/src/messages/labelContentByAgent.test.js.map +1 -0
  358. package/src/messages/prune.js.map +1 -0
  359. package/src/messages/prune.ts +661 -4
  360. package/src/messages/reducer.js.map +1 -0
  361. package/src/messages/shiftIndexTokenCountMap.test.js.map +1 -0
  362. package/src/messages/summarize.js.map +1 -0
  363. package/src/messages/summarize.test.js.map +1 -0
  364. package/src/messages/tools.js.map +1 -0
  365. package/src/mockStream.js.map +1 -0
  366. package/src/prompts/collab.js.map +1 -0
  367. package/src/prompts/index.js.map +1 -0
  368. package/src/prompts/taskmanager.js.map +1 -0
  369. package/src/run.js.map +1 -0
  370. package/src/run.ts +155 -1
  371. package/src/schemas/index.js.map +1 -0
  372. package/src/schemas/schema-preparation.test.js.map +1 -0
  373. package/src/schemas/validate.js.map +1 -0
  374. package/src/schemas/validate.test.js.map +1 -0
  375. package/src/scripts/abort.js.map +1 -0
  376. package/src/scripts/ant_web_search.js.map +1 -0
  377. package/src/scripts/ant_web_search_edge_case.js.map +1 -0
  378. package/src/scripts/ant_web_search_error_edge_case.js.map +1 -0
  379. package/src/scripts/args.js.map +1 -0
  380. package/src/scripts/bedrock-cache-debug.js.map +1 -0
  381. package/src/scripts/bedrock-content-aggregation-test.js.map +1 -0
  382. package/src/scripts/bedrock-merge-test.js.map +1 -0
  383. package/src/scripts/bedrock-parallel-tools-test.js.map +1 -0
  384. package/src/scripts/caching.js.map +1 -0
  385. package/src/scripts/cli.js.map +1 -0
  386. package/src/scripts/cli2.js.map +1 -0
  387. package/src/scripts/cli3.js.map +1 -0
  388. package/src/scripts/cli4.js.map +1 -0
  389. package/src/scripts/cli5.js.map +1 -0
  390. package/src/scripts/code_exec.js.map +1 -0
  391. package/src/scripts/code_exec_files.js.map +1 -0
  392. package/src/scripts/code_exec_multi_session.js.map +1 -0
  393. package/src/scripts/code_exec_ptc.js.map +1 -0
  394. package/src/scripts/code_exec_session.js.map +1 -0
  395. package/src/scripts/code_exec_simple.js.map +1 -0
  396. package/src/scripts/content.js.map +1 -0
  397. package/src/scripts/empty_input.js.map +1 -0
  398. package/src/scripts/handoff-test.js.map +1 -0
  399. package/src/scripts/image.js.map +1 -0
  400. package/src/scripts/memory.js.map +1 -0
  401. package/src/scripts/multi-agent-chain.js.map +1 -0
  402. package/src/scripts/multi-agent-chain.ts +2 -2
  403. package/src/scripts/multi-agent-conditional.js.map +1 -0
  404. package/src/scripts/multi-agent-document-review-chain.js.map +1 -0
  405. package/src/scripts/multi-agent-document-review-chain.ts +2 -2
  406. package/src/scripts/multi-agent-hybrid-flow.js.map +1 -0
  407. package/src/scripts/multi-agent-hybrid-flow.ts +4 -4
  408. package/src/scripts/multi-agent-parallel-start.js.map +1 -0
  409. package/src/scripts/multi-agent-parallel.js.map +1 -0
  410. package/src/scripts/multi-agent-parallel.ts +3 -3
  411. package/src/scripts/multi-agent-sequence.js.map +1 -0
  412. package/src/scripts/multi-agent-sequence.ts +3 -3
  413. package/src/scripts/multi-agent-subagent.ts +246 -0
  414. package/src/scripts/multi-agent-supervisor.js.map +1 -0
  415. package/src/scripts/multi-agent-supervisor.ts +5 -5
  416. package/src/scripts/multi-agent-test.js.map +1 -0
  417. package/src/scripts/parallel-asymmetric-tools-test.js.map +1 -0
  418. package/src/scripts/parallel-full-metadata-test.js.map +1 -0
  419. package/src/scripts/parallel-tools-test.js.map +1 -0
  420. package/src/scripts/poc-multi-agent-comprehensive.ts +8 -8
  421. package/src/scripts/programmatic_exec.js.map +1 -0
  422. package/src/scripts/programmatic_exec_agent.js.map +1 -0
  423. package/src/scripts/search.js.map +1 -0
  424. package/src/scripts/sequential-full-metadata-test.js.map +1 -0
  425. package/src/scripts/sequential-full-metadata-test.ts +2 -2
  426. package/src/scripts/simple.js.map +1 -0
  427. package/src/scripts/single-agent-metadata-test.js.map +1 -0
  428. package/src/scripts/stream.js.map +1 -0
  429. package/src/scripts/subagent-event-driven-debug.ts +190 -0
  430. package/src/scripts/subagent-tools-debug.ts +160 -0
  431. package/src/scripts/test-custom-prompt-key.js.map +1 -0
  432. package/src/scripts/test-custom-prompt-key.ts +3 -3
  433. package/src/scripts/test-handoff-input.js.map +1 -0
  434. package/src/scripts/test-handoff-input.ts +1 -1
  435. package/src/scripts/test-handoff-preamble.js.map +1 -0
  436. package/src/scripts/test-handoff-steering.js.map +1 -0
  437. package/src/scripts/test-handoff-steering.ts +3 -3
  438. package/src/scripts/test-multi-agent-list-handoff.js.map +1 -0
  439. package/src/scripts/test-multi-agent-list-handoff.ts +1 -1
  440. package/src/scripts/test-parallel-agent-labeling.js.map +1 -0
  441. package/src/scripts/test-parallel-agent-labeling.ts +3 -3
  442. package/src/scripts/test-parallel-handoffs.js.map +1 -0
  443. package/src/scripts/test-parallel-handoffs.ts +2 -2
  444. package/src/scripts/test-thinking-handoff-bedrock.js.map +1 -0
  445. package/src/scripts/test-thinking-handoff-bedrock.ts +1 -1
  446. package/src/scripts/test-thinking-handoff.js.map +1 -0
  447. package/src/scripts/test-thinking-handoff.ts +1 -1
  448. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js.map +1 -0
  449. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +1 -1
  450. package/src/scripts/test-tool-before-handoff-role-order.js.map +1 -0
  451. package/src/scripts/test-tool-before-handoff-role-order.ts +1 -1
  452. package/src/scripts/test-tools-before-handoff.js.map +1 -0
  453. package/src/scripts/test-tools-before-handoff.ts +1 -1
  454. package/src/scripts/test_code_api.js.map +1 -0
  455. package/src/scripts/thinking-bedrock.js.map +1 -0
  456. package/src/scripts/thinking-vertexai.js.map +1 -0
  457. package/src/scripts/thinking.js.map +1 -0
  458. package/src/scripts/tool_search.js.map +1 -0
  459. package/src/scripts/tools.js.map +1 -0
  460. package/src/specs/agent-handoffs-bedrock.integration.test.js.map +1 -0
  461. package/src/specs/agent-handoffs.test.js.map +1 -0
  462. package/src/specs/agent-handoffs.test.ts +26 -483
  463. package/src/specs/anthropic.simple.test.js.map +1 -0
  464. package/src/specs/anthropic.simple.test.ts +61 -0
  465. package/src/specs/azure.simple.test.js.map +1 -0
  466. package/src/specs/cache.simple.test.js.map +1 -0
  467. package/src/specs/custom-event-await.test.js.map +1 -0
  468. package/src/specs/deepseek.simple.test.js.map +1 -0
  469. package/src/specs/emergency-prune.test.js.map +1 -0
  470. package/src/specs/moonshot.simple.test.js.map +1 -0
  471. package/src/specs/multi-agent-summarization.test.ts +396 -0
  472. package/src/specs/observability.integration.test.js.map +1 -0
  473. package/src/specs/openai.simple.test.js.map +1 -0
  474. package/src/specs/openrouter.simple.test.js.map +1 -0
  475. package/src/specs/prune.orphans.test.ts +248 -0
  476. package/src/specs/prune.test.js.map +1 -0
  477. package/src/specs/prune.test.ts +104 -16
  478. package/src/specs/reasoning.test.js.map +1 -0
  479. package/src/specs/spec.utils.js.map +1 -0
  480. package/src/specs/thinking-handoff.test.js.map +1 -0
  481. package/src/specs/thinking-handoff.test.ts +19 -19
  482. package/src/specs/thinking-prune.test.js.map +1 -0
  483. package/src/specs/token-distribution-edge-case.test.js.map +1 -0
  484. package/src/specs/token-memoization.test.js.map +1 -0
  485. package/src/specs/tokens.test.js.map +1 -0
  486. package/src/specs/tool-error.test.js.map +1 -0
  487. package/src/splitStream.js.map +1 -0
  488. package/src/splitStream.test.js.map +1 -0
  489. package/src/stream.js.map +1 -0
  490. package/src/stream.test.js.map +1 -0
  491. package/src/test/mockTools.js.map +1 -0
  492. package/src/tools/BashExecutor.ts +281 -0
  493. package/src/tools/BashProgrammaticToolCalling.ts +397 -0
  494. package/src/tools/BrowserTools.js.map +1 -0
  495. package/src/tools/Calculator.js.map +1 -0
  496. package/src/tools/Calculator.test.js.map +1 -0
  497. package/src/tools/CodeExecutor.js.map +1 -0
  498. package/src/tools/CodeExecutor.ts +62 -54
  499. package/src/tools/ProgrammaticToolCalling.js.map +1 -0
  500. package/src/tools/ProgrammaticToolCalling.ts +29 -14
  501. package/src/tools/ReadFile.ts +39 -0
  502. package/src/tools/SkillTool.ts +46 -0
  503. package/src/tools/StreamingToolCallBuffer.js.map +1 -0
  504. package/src/tools/SubagentTool.ts +100 -0
  505. package/src/tools/ToolNode.js.map +1 -0
  506. package/src/tools/ToolNode.ts +548 -26
  507. package/src/tools/ToolSearch.js.map +1 -0
  508. package/src/tools/__tests__/BashExecutor.test.ts +49 -0
  509. package/src/tools/__tests__/BrowserTools.test.js.map +1 -0
  510. package/src/tools/__tests__/CodeExecutor.test.ts +37 -36
  511. package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.js.map +1 -0
  512. package/src/tools/__tests__/ProgrammaticToolCalling.test.js.map +1 -0
  513. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +60 -0
  514. package/src/tools/__tests__/ReadFile.test.ts +44 -0
  515. package/src/tools/__tests__/SkillTool.test.ts +442 -0
  516. package/src/tools/__tests__/StreamingToolCallBuffer.test.js.map +1 -0
  517. package/src/tools/__tests__/SubagentExecutor.test.ts +1148 -0
  518. package/src/tools/__tests__/SubagentTool.test.ts +149 -0
  519. package/src/tools/__tests__/ToolApproval.test.js.map +1 -0
  520. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +1438 -0
  521. package/src/tools/__tests__/ToolNode.recovery.test.js.map +1 -0
  522. package/src/tools/__tests__/ToolNode.session.test.js.map +1 -0
  523. package/src/tools/__tests__/ToolSearch.integration.test.js.map +1 -0
  524. package/src/tools/__tests__/ToolSearch.test.js.map +1 -0
  525. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +479 -0
  526. package/src/tools/__tests__/handlers.test.js.map +1 -0
  527. package/src/tools/__tests__/skillCatalog.test.ts +161 -0
  528. package/src/tools/__tests__/subagentHooks.test.ts +210 -0
  529. package/src/tools/__tests__/toolOutputReferences.test.ts +415 -0
  530. package/src/tools/__tests__/truncation-recovery.integration.test.js.map +1 -0
  531. package/src/tools/handlers.js.map +1 -0
  532. package/src/tools/schema.js.map +1 -0
  533. package/src/tools/search/anthropic.js.map +1 -0
  534. package/src/tools/search/content.js.map +1 -0
  535. package/src/tools/search/content.test.js.map +1 -0
  536. package/src/tools/search/firecrawl.js.map +1 -0
  537. package/src/tools/search/format.js.map +1 -0
  538. package/src/tools/search/highlights.js.map +1 -0
  539. package/src/tools/search/index.js.map +1 -0
  540. package/src/tools/search/jina-reranker.test.js.map +1 -0
  541. package/src/tools/search/rerankers.js.map +1 -0
  542. package/src/tools/search/schema.js.map +1 -0
  543. package/src/tools/search/search.js.map +1 -0
  544. package/src/tools/search/search.ts +12 -2
  545. package/src/tools/search/serper-scraper.js.map +1 -0
  546. package/src/tools/search/tavily-scraper.ts +235 -0
  547. package/src/tools/search/tavily-search.ts +424 -0
  548. package/src/tools/search/tavily.test.ts +965 -0
  549. package/src/tools/search/test.js.map +1 -0
  550. package/src/tools/search/tool.js.map +1 -0
  551. package/src/tools/search/tool.ts +36 -2
  552. package/src/tools/search/types.js.map +1 -0
  553. package/src/tools/search/types.ts +133 -8
  554. package/src/tools/search/utils.js.map +1 -0
  555. package/src/tools/search/utils.ts +13 -5
  556. package/src/tools/skillCatalog.ts +126 -0
  557. package/src/tools/subagent/SubagentExecutor.ts +676 -0
  558. package/src/tools/subagent/index.ts +13 -0
  559. package/src/tools/subagent/types.test.ts +70 -0
  560. package/src/tools/subagent/types.ts +115 -0
  561. package/src/tools/toolOutputReferences.ts +825 -0
  562. package/src/types/agent-cache.ts +73 -0
  563. package/src/types/graph.js.map +1 -0
  564. package/src/types/graph.test.js.map +1 -0
  565. package/src/types/graph.ts +171 -20
  566. package/src/types/index.js.map +1 -0
  567. package/src/types/index.ts +3 -0
  568. package/src/types/llm.js.map +1 -0
  569. package/src/types/messages.js.map +1 -0
  570. package/src/types/messages.ts +27 -0
  571. package/src/types/run.js.map +1 -0
  572. package/src/types/run.ts +22 -0
  573. package/src/types/skill.ts +11 -0
  574. package/src/types/stream.js.map +1 -0
  575. package/src/types/tools.js.map +1 -0
  576. package/src/types/tools.ts +118 -0
  577. package/src/utils/__tests__/truncation.test.ts +66 -0
  578. package/src/utils/contextAnalytics.js.map +1 -0
  579. package/src/utils/contextAnalytics.test.js.map +1 -0
  580. package/src/utils/events.js.map +1 -0
  581. package/src/utils/graph.js.map +1 -0
  582. package/src/utils/handlers.js.map +1 -0
  583. package/src/utils/index.js.map +1 -0
  584. package/src/utils/index.ts +1 -3
  585. package/src/utils/llm.js.map +1 -0
  586. package/src/utils/llmConfig.js.map +1 -0
  587. package/src/utils/logging.js.map +1 -0
  588. package/src/utils/misc.js.map +1 -0
  589. package/src/utils/run.js.map +1 -0
  590. package/src/utils/schema.js.map +1 -0
  591. package/src/utils/title.js.map +1 -0
  592. package/src/utils/tokens.js.map +1 -0
  593. package/src/utils/toonFormat.js.map +1 -0
  594. package/src/utils/truncation.ts +154 -0
  595. package/dist/cjs/common/spawnPath.cjs +0 -104
  596. package/dist/cjs/common/spawnPath.cjs.map +0 -1
  597. package/dist/cjs/content/ArtifactStore.cjs +0 -579
  598. package/dist/cjs/content/ArtifactStore.cjs.map +0 -1
  599. package/dist/cjs/content/ContentStore.cjs +0 -638
  600. package/dist/cjs/content/ContentStore.cjs.map +0 -1
  601. package/dist/cjs/content/contentAnalyzer.cjs +0 -91
  602. package/dist/cjs/content/contentAnalyzer.cjs.map +0 -1
  603. package/dist/cjs/content/index.cjs +0 -20
  604. package/dist/cjs/content/index.cjs.map +0 -1
  605. package/dist/cjs/content/mcpAutoCache.cjs +0 -115
  606. package/dist/cjs/content/mcpAutoCache.cjs.map +0 -1
  607. package/dist/cjs/graphs/HandoffRegistry.cjs +0 -143
  608. package/dist/cjs/graphs/HandoffRegistry.cjs.map +0 -1
  609. package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs +0 -288
  610. package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs.map +0 -1
  611. package/dist/cjs/providers/a2a/client.cjs +0 -92
  612. package/dist/cjs/providers/a2a/client.cjs.map +0 -1
  613. package/dist/cjs/providers/a2a/config.cjs +0 -38
  614. package/dist/cjs/providers/a2a/config.cjs.map +0 -1
  615. package/dist/cjs/providers/capabilityNaming.cjs +0 -43
  616. package/dist/cjs/providers/capabilityNaming.cjs.map +0 -1
  617. package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs +0 -244
  618. package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs.map +0 -1
  619. package/dist/cjs/providers/mcp/config.cjs +0 -42
  620. package/dist/cjs/providers/mcp/config.cjs.map +0 -1
  621. package/dist/cjs/providers/mcp/transport.cjs +0 -65
  622. package/dist/cjs/providers/mcp/transport.cjs.map +0 -1
  623. package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs +0 -128
  624. package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs.map +0 -1
  625. package/dist/cjs/providers/types.cjs +0 -51
  626. package/dist/cjs/providers/types.cjs.map +0 -1
  627. package/dist/cjs/tools/artifacts/schema.cjs +0 -86
  628. package/dist/cjs/tools/artifacts/schema.cjs.map +0 -1
  629. package/dist/cjs/tools/artifacts/tool.cjs +0 -219
  630. package/dist/cjs/tools/artifacts/tool.cjs.map +0 -1
  631. package/dist/cjs/tools/fileSearch/formatter.cjs +0 -93
  632. package/dist/cjs/tools/fileSearch/formatter.cjs.map +0 -1
  633. package/dist/cjs/tools/fileSearch/ragClient.cjs +0 -102
  634. package/dist/cjs/tools/fileSearch/ragClient.cjs.map +0 -1
  635. package/dist/cjs/tools/fileSearch/schema.cjs +0 -18
  636. package/dist/cjs/tools/fileSearch/schema.cjs.map +0 -1
  637. package/dist/cjs/tools/fileSearch/tool.cjs +0 -155
  638. package/dist/cjs/tools/fileSearch/tool.cjs.map +0 -1
  639. package/dist/cjs/tools/proxyTool.cjs +0 -102
  640. package/dist/cjs/tools/proxyTool.cjs.map +0 -1
  641. package/dist/cjs/utils/childAgentContext.cjs +0 -242
  642. package/dist/cjs/utils/childAgentContext.cjs.map +0 -1
  643. package/dist/cjs/utils/credentials.cjs +0 -142
  644. package/dist/cjs/utils/credentials.cjs.map +0 -1
  645. package/dist/cjs/utils/httpClient.cjs +0 -74
  646. package/dist/cjs/utils/httpClient.cjs.map +0 -1
  647. package/dist/cjs/utils/toolManifest.cjs +0 -100
  648. package/dist/cjs/utils/toolManifest.cjs.map +0 -1
  649. package/dist/esm/common/spawnPath.mjs +0 -95
  650. package/dist/esm/common/spawnPath.mjs.map +0 -1
  651. package/dist/esm/content/ArtifactStore.mjs +0 -576
  652. package/dist/esm/content/ArtifactStore.mjs.map +0 -1
  653. package/dist/esm/content/ContentStore.mjs +0 -635
  654. package/dist/esm/content/ContentStore.mjs.map +0 -1
  655. package/dist/esm/content/contentAnalyzer.mjs +0 -87
  656. package/dist/esm/content/contentAnalyzer.mjs.map +0 -1
  657. package/dist/esm/content/index.mjs +0 -5
  658. package/dist/esm/content/mcpAutoCache.mjs +0 -111
  659. package/dist/esm/content/mcpAutoCache.mjs.map +0 -1
  660. package/dist/esm/graphs/HandoffRegistry.mjs +0 -141
  661. package/dist/esm/graphs/HandoffRegistry.mjs.map +0 -1
  662. package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs +0 -281
  663. package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs.map +0 -1
  664. package/dist/esm/providers/a2a/client.mjs +0 -88
  665. package/dist/esm/providers/a2a/client.mjs.map +0 -1
  666. package/dist/esm/providers/a2a/config.mjs +0 -35
  667. package/dist/esm/providers/a2a/config.mjs.map +0 -1
  668. package/dist/esm/providers/capabilityNaming.mjs +0 -39
  669. package/dist/esm/providers/capabilityNaming.mjs.map +0 -1
  670. package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs +0 -240
  671. package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs.map +0 -1
  672. package/dist/esm/providers/mcp/config.mjs +0 -39
  673. package/dist/esm/providers/mcp/config.mjs.map +0 -1
  674. package/dist/esm/providers/mcp/transport.mjs +0 -63
  675. package/dist/esm/providers/mcp/transport.mjs.map +0 -1
  676. package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs +0 -126
  677. package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs.map +0 -1
  678. package/dist/esm/providers/types.mjs +0 -51
  679. package/dist/esm/providers/types.mjs.map +0 -1
  680. package/dist/esm/tools/artifacts/schema.mjs +0 -79
  681. package/dist/esm/tools/artifacts/schema.mjs.map +0 -1
  682. package/dist/esm/tools/artifacts/tool.mjs +0 -213
  683. package/dist/esm/tools/artifacts/tool.mjs.map +0 -1
  684. package/dist/esm/tools/fileSearch/formatter.mjs +0 -90
  685. package/dist/esm/tools/fileSearch/formatter.mjs.map +0 -1
  686. package/dist/esm/tools/fileSearch/ragClient.mjs +0 -98
  687. package/dist/esm/tools/fileSearch/ragClient.mjs.map +0 -1
  688. package/dist/esm/tools/fileSearch/schema.mjs +0 -15
  689. package/dist/esm/tools/fileSearch/schema.mjs.map +0 -1
  690. package/dist/esm/tools/fileSearch/tool.mjs +0 -152
  691. package/dist/esm/tools/fileSearch/tool.mjs.map +0 -1
  692. package/dist/esm/tools/proxyTool.mjs +0 -100
  693. package/dist/esm/tools/proxyTool.mjs.map +0 -1
  694. package/dist/esm/utils/childAgentContext.mjs +0 -237
  695. package/dist/esm/utils/childAgentContext.mjs.map +0 -1
  696. package/dist/esm/utils/credentials.mjs +0 -135
  697. package/dist/esm/utils/credentials.mjs.map +0 -1
  698. package/dist/esm/utils/httpClient.mjs +0 -70
  699. package/dist/esm/utils/httpClient.mjs.map +0 -1
  700. package/dist/esm/utils/toolManifest.mjs +0 -96
  701. package/dist/esm/utils/toolManifest.mjs.map +0 -1
  702. package/dist/types/common/spawnPath.d.ts +0 -59
  703. package/dist/types/content/ArtifactStore.d.ts +0 -223
  704. package/dist/types/content/ContentStore.d.ts +0 -140
  705. package/dist/types/content/contentAnalyzer.d.ts +0 -38
  706. package/dist/types/content/index.d.ts +0 -24
  707. package/dist/types/content/mcpAutoCache.d.ts +0 -89
  708. package/dist/types/content/types.d.ts +0 -75
  709. package/dist/types/graphs/HandoffRegistry.d.ts +0 -97
  710. package/dist/types/providers/a2a/A2ACapabilityProvider.d.ts +0 -89
  711. package/dist/types/providers/a2a/client.d.ts +0 -47
  712. package/dist/types/providers/a2a/config.d.ts +0 -18
  713. package/dist/types/providers/a2a/index.d.ts +0 -6
  714. package/dist/types/providers/a2a/types.d.ts +0 -173
  715. package/dist/types/providers/capabilityNaming.d.ts +0 -25
  716. package/dist/types/providers/index.d.ts +0 -12
  717. package/dist/types/providers/mcp/MCPCapabilityProvider.d.ts +0 -54
  718. package/dist/types/providers/mcp/config.d.ts +0 -20
  719. package/dist/types/providers/mcp/index.d.ts +0 -5
  720. package/dist/types/providers/mcp/transport.d.ts +0 -18
  721. package/dist/types/providers/mcp/types.d.ts +0 -112
  722. package/dist/types/providers/tools-server/ToolsServerCapabilityProvider.d.ts +0 -59
  723. package/dist/types/providers/tools-server/index.d.ts +0 -1
  724. package/dist/types/providers/types.d.ts +0 -184
  725. package/dist/types/tools/artifacts/index.d.ts +0 -3
  726. package/dist/types/tools/artifacts/schema.d.ts +0 -63
  727. package/dist/types/tools/artifacts/tool.d.ts +0 -16
  728. package/dist/types/tools/artifacts/types.d.ts +0 -127
  729. package/dist/types/tools/fileSearch/formatter.d.ts +0 -25
  730. package/dist/types/tools/fileSearch/index.d.ts +0 -5
  731. package/dist/types/tools/fileSearch/ragClient.d.ts +0 -32
  732. package/dist/types/tools/fileSearch/schema.d.ts +0 -13
  733. package/dist/types/tools/fileSearch/tool.d.ts +0 -18
  734. package/dist/types/tools/fileSearch/types.d.ts +0 -139
  735. package/dist/types/tools/proxyTool.d.ts +0 -62
  736. package/dist/types/utils/childAgentContext.d.ts +0 -99
  737. package/dist/types/utils/credentials.d.ts +0 -77
  738. package/dist/types/utils/httpClient.d.ts +0 -46
  739. package/dist/types/utils/toolManifest.d.ts +0 -49
  740. package/src/common/__tests__/spawnPath.test.ts +0 -110
  741. package/src/common/spawnPath.ts +0 -101
  742. package/src/content/ArtifactStore.ts +0 -782
  743. package/src/content/ContentStore.ts +0 -753
  744. package/src/content/contentAnalyzer.ts +0 -105
  745. package/src/content/index.ts +0 -51
  746. package/src/content/mcpAutoCache.ts +0 -185
  747. package/src/content/types.ts +0 -82
  748. package/src/graphs/HandoffRegistry.ts +0 -199
  749. package/src/graphs/__tests__/HandoffRegistry.test.ts +0 -410
  750. package/src/graphs/__tests__/multi-agent-delegate.test.ts +0 -458
  751. package/src/graphs/__tests__/multi-agent-edges.test.ts +0 -276
  752. package/src/graphs/__tests__/multi-agent-nested-subgraph.test.ts +0 -221
  753. package/src/graphs/handoffValidation.test.ts +0 -353
  754. package/src/providers/__tests__/ToolsServerCapabilityProvider.integration.spec.ts +0 -79
  755. package/src/providers/__tests__/ToolsServerCapabilityProvider.test.ts +0 -271
  756. package/src/providers/__tests__/types.test.ts +0 -64
  757. package/src/providers/a2a/A2ACapabilityProvider.ts +0 -384
  758. package/src/providers/a2a/__tests__/A2ACapabilityProvider.integration.spec.ts +0 -345
  759. package/src/providers/a2a/__tests__/A2ACapabilityProvider.test.ts +0 -460
  760. package/src/providers/a2a/client.ts +0 -115
  761. package/src/providers/a2a/config.ts +0 -40
  762. package/src/providers/a2a/index.ts +0 -29
  763. package/src/providers/a2a/types.ts +0 -191
  764. package/src/providers/capabilityNaming.ts +0 -42
  765. package/src/providers/index.ts +0 -68
  766. package/src/providers/mcp/MCPCapabilityProvider.ts +0 -345
  767. package/src/providers/mcp/__tests__/MCPCapabilityProvider.integration.spec.ts +0 -386
  768. package/src/providers/mcp/__tests__/MCPCapabilityProvider.test.ts +0 -371
  769. package/src/providers/mcp/config.ts +0 -45
  770. package/src/providers/mcp/index.ts +0 -21
  771. package/src/providers/mcp/transport.ts +0 -76
  772. package/src/providers/mcp/types.ts +0 -139
  773. package/src/providers/tools-server/ToolsServerCapabilityProvider.ts +0 -249
  774. package/src/providers/tools-server/index.ts +0 -1
  775. package/src/providers/types.ts +0 -204
  776. package/src/scripts/test-bedrock-handoff-autonomous.ts +0 -267
  777. package/src/scripts/test-handoff-preamble.ts +0 -278
  778. package/src/specs/agent-handoffs-bedrock.integration.test.ts +0 -415
  779. package/src/tools/artifacts/__tests__/tool.test.ts +0 -259
  780. package/src/tools/artifacts/index.ts +0 -33
  781. package/src/tools/artifacts/schema.ts +0 -99
  782. package/src/tools/artifacts/tool.ts +0 -289
  783. package/src/tools/artifacts/types.ts +0 -162
  784. package/src/tools/fileSearch/__tests__/tool.test.ts +0 -261
  785. package/src/tools/fileSearch/formatter.ts +0 -129
  786. package/src/tools/fileSearch/index.ts +0 -23
  787. package/src/tools/fileSearch/ragClient.ts +0 -137
  788. package/src/tools/fileSearch/schema.ts +0 -19
  789. package/src/tools/fileSearch/tool.ts +0 -207
  790. package/src/tools/fileSearch/types.ts +0 -149
  791. package/src/tools/proxyTool.ts +0 -166
  792. package/src/utils/__tests__/childAgentContext.test.ts +0 -217
  793. package/src/utils/__tests__/credentials.test.ts +0 -130
  794. package/src/utils/__tests__/httpClient.test.ts +0 -75
  795. package/src/utils/__tests__/toolManifest.test.ts +0 -116
  796. package/src/utils/childAgentContext.ts +0 -259
  797. package/src/utils/credentials.ts +0 -157
  798. package/src/utils/httpClient.ts +0 -92
  799. package/src/utils/toolManifest.ts +0 -109
  800. /package/dist/esm/{content → langchain}/index.mjs.map +0 -0
@@ -4,7 +4,6 @@ import {
4
4
  AIMessage,
5
5
  ToolMessage,
6
6
  HumanMessage,
7
- SystemMessage,
8
7
  getBufferString,
9
8
  } from '@langchain/core/messages';
10
9
  import {
@@ -20,60 +19,35 @@ import type { LangGraphRunnableConfig } from '@langchain/langgraph';
20
19
  import type { BaseMessage, AIMessageChunk } from '@langchain/core/messages';
21
20
  import type { ToolRunnableConfig } from '@langchain/core/tools';
22
21
  import type * as t from '@/types';
23
- import { summarize, createEmergencySummary } from '@/messages';
24
22
  import { StandardGraph } from './Graph';
25
- import {
26
- Constants,
27
- EdgeType,
28
- GraphEvents,
29
- DEFAULT_HANDOFF_MAX_RESULT_CHARS,
30
- buildSpawnPath,
31
- spawnPathDepth,
32
- } from '@/common';
33
- import { safeDispatchCustomEvent } from '@/utils/events';
34
- import { mlog, mwarn } from '@/utils/logging';
35
- import {
36
- prepareHandoffMessages as prepareHandoffMessagesUtil,
37
- prepareIsolatedChildMessages as prepareIsolatedChildMessagesUtil,
38
- } from '@/utils/childAgentContext';
23
+ import { Constants, EdgeType } from '@/common';
39
24
  import {
40
25
  createApprovalGateNode,
41
26
  getApprovalGateNodeId,
42
27
  } from '@/nodes/ApprovalGateNode';
43
- // HandoffRegistry no longer needed — handoff tools use synchronous
44
- // browser-tool callback pattern (spawn → wait → return result)
45
28
 
46
29
  /** Pattern to extract instructions from transfer ToolMessage content */
47
- const TRANSFER_INSTRUCTIONS_PATTERN = /(?:Instructions?|Context):\s*(.+)/is;
30
+ const HANDOFF_INSTRUCTIONS_PATTERN = /(?:Instructions?|Context):\s*(.+)/is;
48
31
 
49
32
  /**
50
33
  * MultiAgentGraph extends StandardGraph to support dynamic multi-agent workflows
51
34
  * with handoffs, fan-in/fan-out, and other composable patterns.
52
35
  *
53
36
  * Key behavior:
54
- * - Agents with ONLY transfer edges: Can dynamically route to any transfer destination
55
- * - Agents with ONLY sequence edges: Always follow their sequence edges
56
- * - Agents with BOTH: Use Command for exclusive routing (transfer OR sequence, not both)
57
- * - If transfer occurs: Only the transfer destination executes
58
- * - If no transfer: Sequence edges execute (potentially in parallel)
37
+ * - Agents with ONLY handoff edges: Can dynamically route to any handoff destination
38
+ * - Agents with ONLY direct edges: Always follow their direct edges
39
+ * - Agents with BOTH: Use Command for exclusive routing (handoff OR direct, not both)
40
+ * - If handoff occurs: Only the handoff destination executes
41
+ * - If no handoff: Direct edges execute (potentially in parallel)
59
42
  *
60
- * This enables the common pattern where an agent either transfers (one-way)
61
- * OR continues its workflow (sequence edges), but not both simultaneously.
43
+ * This enables the common pattern where an agent either delegates (handoff)
44
+ * OR continues its workflow (direct edges), but not both simultaneously.
62
45
  */
63
46
  export class MultiAgentGraph extends StandardGraph {
64
47
  private edges: t.GraphEdge[];
65
48
  private startingNodes: Set<string> = new Set();
66
- private sequenceEdges: t.GraphEdge[] = [];
67
- private transferEdges: t.GraphEdge[] = [];
49
+ private directEdges: t.GraphEdge[] = [];
68
50
  private handoffEdges: t.GraphEdge[] = [];
69
- /**
70
- * Lazily populated registry of compiled subgraphs, keyed by agentId.
71
- * Handoff tools are created in the constructor but reference subgraphs
72
- * that are only created in createWorkflow(). This Map bridges that gap —
73
- * tools capture the Map reference in their closure, and createWorkflow()
74
- * populates it before any tool invocation occurs.
75
- */
76
- private subgraphRegistry: Map<string, t.CompiledAgentWorfklow> = new Map();
77
51
  /**
78
52
  * Map of agentId to parallel group info.
79
53
  * Contains groupId (incrementing number reflecting execution order) for agents in parallel groups.
@@ -85,70 +59,79 @@ export class MultiAgentGraph extends StandardGraph {
85
59
  * - summarizer: undefined (sequential, order 2)
86
60
  */
87
61
  private agentParallelGroups: Map<string, number> = new Map();
88
- /**
89
- * Tracks the ID of the last agent that produced output.
90
- * Used by auto-continuation to know which agent's context to preserve after handoff.
91
- */
92
- private lastActiveAgentId: string | undefined;
93
-
94
- /**
95
- * Registry for async handoff execution.
96
- * Enables autonomous orchestration: spawn children non-blocking,
97
- * orchestrator stays alive to reason and collect results when ready.
98
- */
99
- // HandoffRegistry removed — handoff tools are synchronous (callback pattern)
100
-
101
- /**
102
- * When set, the graph routes START to this agent instead of the default starting nodes.
103
- * Enables multi-turn resumption: follow-up messages go to the agent that last handled
104
- * the conversation rather than restarting from the root/router agent.
105
- */
106
- private resumeFromAgentId: string | undefined;
107
62
 
108
63
  constructor(input: t.MultiAgentGraphInput) {
109
64
  super(input);
110
65
  this.edges = input.edges;
111
- this.resumeFromAgentId = input.resumeFromAgentId;
66
+ this.validateEdgeAgents();
112
67
  this.categorizeEdges();
113
68
  this.analyzeGraph();
114
- this.createTransferTools();
115
69
  this.createHandoffTools();
116
- mlog(
117
- `[MultiAgentGraph] Constructor complete: ${this.agentContexts.size} agents, ${this.edges.length} edges`
70
+ }
71
+
72
+ /**
73
+ * Fails fast when an edge references an agent that is not in
74
+ * `agentContexts`. Without this check, the underlying LangGraph
75
+ * `StateGraph.compile()` would throw the opaque
76
+ * `Found edge ending at unknown node "<id>"` error after graph
77
+ * construction — far from the true root cause.
78
+ *
79
+ * This catches the common misuse of passing `edges` into a multi-agent
80
+ * config without also passing the corresponding sub-agent configs in
81
+ * `agents` (e.g. a host that forgot to pre-load handoff targets).
82
+ */
83
+ private validateEdgeAgents(): void {
84
+ const known = new Set(this.agentContexts.keys());
85
+ const unknown = new Set<string>();
86
+ for (const edge of this.edges) {
87
+ const participants = [
88
+ ...(Array.isArray(edge.from) ? edge.from : [edge.from]),
89
+ ...(Array.isArray(edge.to) ? edge.to : [edge.to]),
90
+ ];
91
+ for (const id of participants) {
92
+ if (typeof id === 'string' && !known.has(id)) {
93
+ unknown.add(id);
94
+ }
95
+ }
96
+ }
97
+ if (unknown.size === 0) {
98
+ return;
99
+ }
100
+ const missing = Array.from(unknown)
101
+ .map((id) => `"${id}"`)
102
+ .join(', ');
103
+ throw new Error(
104
+ `MultiAgentGraph: edges reference agent(s) not present in agents: [${missing}]. ` +
105
+ 'Ensure every agent referenced by an edge is also included in the `agents` array, ' +
106
+ 'or filter orphaned edges before constructing the graph.'
118
107
  );
119
108
  }
120
109
 
121
110
  /**
122
- * Categorize edges into handoff, transfer, and sequence types
111
+ * Categorize edges into handoff and direct types
123
112
  */
124
113
  private categorizeEdges(): void {
125
114
  for (const edge of this.edges) {
126
- if (edge.edgeType === EdgeType.HANDOFF) {
115
+ // Default behavior: edges with conditions or explicit 'handoff' type are handoff edges
116
+ // Edges with explicit 'direct' type or multi-destination without conditions are direct edges
117
+ if (edge.edgeType === EdgeType.DIRECT) {
118
+ this.directEdges.push(edge);
119
+ } else if (edge.edgeType === EdgeType.HANDOFF || edge.condition != null) {
127
120
  this.handoffEdges.push(edge);
128
- } else if (edge.edgeType === EdgeType.SEQUENCE) {
129
- this.sequenceEdges.push(edge);
130
- } else if (
131
- edge.edgeType === EdgeType.TRANSFER ||
132
- edge.condition != null
133
- ) {
134
- this.transferEdges.push(edge);
135
121
  } else {
136
- // Default: single-to-single edges are transfer, single-to-multiple are sequence
122
+ // Default: single-to-single edges are handoff, single-to-multiple are direct
137
123
  const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
138
124
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
139
125
 
140
126
  if (sources.length === 1 && destinations.length > 1) {
141
- // Fan-out pattern defaults to sequence
142
- this.sequenceEdges.push(edge);
127
+ // Fan-out pattern defaults to direct
128
+ this.directEdges.push(edge);
143
129
  } else {
144
- // Everything else defaults to transfer
145
- this.transferEdges.push(edge);
130
+ // Everything else defaults to handoff
131
+ this.handoffEdges.push(edge);
146
132
  }
147
133
  }
148
134
  }
149
- mlog(
150
- `[MultiAgentGraph] Edge categorization: ${this.handoffEdges.length} handoff, ${this.transferEdges.length} transfer, ${this.sequenceEdges.length} sequence (of ${this.edges.length} total)`
151
- );
152
135
  }
153
136
 
154
137
  /**
@@ -175,10 +158,6 @@ export class MultiAgentGraph extends StandardGraph {
175
158
  this.startingNodes.add(this.agentContexts.keys().next().value!);
176
159
  }
177
160
 
178
- mlog(
179
- `[MultiAgentGraph] Starting nodes identified: [${Array.from(this.startingNodes).join(', ')}]`
180
- );
181
-
182
161
  // Determine if graph has parallel execution capability
183
162
  this.computeParallelCapability();
184
163
  }
@@ -218,8 +197,8 @@ export class MultiAgentGraph extends StandardGraph {
218
197
  if (visited.has(current)) continue;
219
198
  visited.add(current);
220
199
 
221
- // Find sequence edges from this node
222
- for (const edge of this.sequenceEdges) {
200
+ // Find direct edges from this node
201
+ for (const edge of this.directEdges) {
223
202
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
224
203
  if (!sources.includes(current)) continue;
225
204
 
@@ -247,8 +226,8 @@ export class MultiAgentGraph extends StandardGraph {
247
226
  }
248
227
  }
249
228
 
250
- // Also follow transfer and handoff edges for traversal (they don't create parallel groups)
251
- for (const edge of [...this.transferEdges, ...this.handoffEdges]) {
229
+ // Also follow handoff edges for traversal (but they don't create parallel groups)
230
+ for (const edge of this.handoffEdges) {
252
231
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
253
232
  if (!sources.includes(current)) continue;
254
233
 
@@ -271,15 +250,6 @@ export class MultiAgentGraph extends StandardGraph {
271
250
  return this.agentParallelGroups.get(agentId);
272
251
  }
273
252
 
274
- /**
275
- * Returns the ID of the last agent that produced output.
276
- * Used by auto-continuation to determine which agent's context to preserve
277
- * when a response is truncated after an agent handoff.
278
- */
279
- getLastActiveAgentId(): string | undefined {
280
- return this.lastActiveAgentId;
281
- }
282
-
283
253
  /**
284
254
  * Override to indicate this is a multi-agent graph.
285
255
  * Enables agentId to be included in RunStep for frontend agent labeling.
@@ -298,71 +268,51 @@ export class MultiAgentGraph extends StandardGraph {
298
268
  }
299
269
 
300
270
  /**
301
- * Create transfer tools for agents based on transfer edges only.
302
- * Transfer tools return Command for one-way routing — parent exits, child takes over.
271
+ * Create handoff tools for agents based on handoff edges only
303
272
  */
304
- private createTransferTools(): void {
305
- const transfersByAgent = new Map<string, t.GraphEdge[]>();
273
+ private createHandoffTools(): void {
274
+ // Group handoff edges by source agent(s)
275
+ const handoffsByAgent = new Map<string, t.GraphEdge[]>();
306
276
 
307
- for (const edge of this.transferEdges) {
277
+ // Only process handoff edges for tool creation
278
+ for (const edge of this.handoffEdges) {
308
279
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
309
280
  sources.forEach((source) => {
310
- if (!transfersByAgent.has(source)) {
311
- transfersByAgent.set(source, []);
281
+ if (!handoffsByAgent.has(source)) {
282
+ handoffsByAgent.set(source, []);
312
283
  }
313
- transfersByAgent.get(source)!.push(edge);
284
+ handoffsByAgent.get(source)!.push(edge);
314
285
  });
315
286
  }
316
287
 
317
- for (const [agentId, edges] of transfersByAgent) {
288
+ // Create handoff tools for each agent
289
+ for (const [agentId, edges] of handoffsByAgent) {
318
290
  const agentContext = this.agentContexts.get(agentId);
319
291
  if (!agentContext) continue;
320
292
 
321
- const transferTools: t.GenericTool[] = [];
293
+ // Create handoff tools for this agent's outgoing edges
294
+ const handoffTools: t.GenericTool[] = [];
322
295
  const sourceAgentName = agentContext.name ?? agentId;
323
296
  for (const edge of edges) {
324
- transferTools.push(
325
- ...this.createTransferToolsForEdge(edge, agentId, sourceAgentName)
297
+ handoffTools.push(
298
+ ...this.createHandoffToolsForEdge(edge, agentId, sourceAgentName)
326
299
  );
327
300
  }
328
301
 
329
302
  if (!agentContext.graphTools) {
330
303
  agentContext.graphTools = [];
331
304
  }
332
- agentContext.graphTools.push(...transferTools);
333
- mlog(
334
- `[MultiAgentGraph] Transfer tools for "${agentId}": [${transferTools.map((t) => t.name).join(', ')}]`
335
- );
336
-
337
- // Inject orchestration guidance for agents with transfer tools
338
- const childDescs = edges.flatMap((e) => {
339
- const dests = Array.isArray(e.to) ? e.to : [e.to];
340
- return dests.map((d) => {
341
- const ctx = this.agentContexts.get(d);
342
- const name = ctx?.name ?? d;
343
- const desc = ctx?.description ? ` — ${ctx.description}` : '';
344
- return `${name}${desc}`;
345
- });
346
- });
347
- const guidance = this.buildOrchestratorGuidance(
348
- childDescs,
349
- transferTools.length
350
- );
351
- const existing = agentContext.additionalInstructions ?? '';
352
- agentContext.additionalInstructions = existing
353
- ? `${existing}\n\n${guidance}`
354
- : guidance;
305
+ agentContext.graphTools.push(...handoffTools);
355
306
  }
356
307
  }
357
308
 
358
309
  /**
359
- * Create transfer tools for an edge (handles multiple destinations).
360
- * Transfer tools return Command for one-way routing parent exits, child takes over.
361
- * @param edge - The graph edge defining the transfer
362
- * @param sourceAgentId - The ID of the agent that will perform the transfer
310
+ * Create handoff tools for an edge (handles multiple destinations)
311
+ * @param edge - The graph edge defining the handoff
312
+ * @param sourceAgentId - The ID of the agent that will perform the handoff
363
313
  * @param sourceAgentName - The human-readable name of the source agent
364
314
  */
365
- private createTransferToolsForEdge(
315
+ private createHandoffToolsForEdge(
366
316
  edge: t.GraphEdge,
367
317
  sourceAgentId: string,
368
318
  sourceAgentName: string
@@ -377,11 +327,9 @@ export class MultiAgentGraph extends StandardGraph {
377
327
  edge.description ?? 'Conditionally transfer control based on state';
378
328
 
379
329
  /** Check if we have a prompt for handoff input */
380
- const hasTransferInput =
330
+ const hasHandoffInput =
381
331
  edge.prompt != null && typeof edge.prompt === 'string';
382
- const transferInputDescription = hasTransferInput
383
- ? edge.prompt
384
- : undefined;
332
+ const handoffInputDescription = hasHandoffInput ? edge.prompt : undefined;
385
333
  const promptKey = edge.promptKey ?? 'instructions';
386
334
 
387
335
  tools.push(
@@ -410,7 +358,7 @@ export class MultiAgentGraph extends StandardGraph {
410
358
 
411
359
  let content = `Conditionally transferred to ${destination}`;
412
360
  if (
413
- hasTransferInput &&
361
+ hasHandoffInput &&
414
362
  promptKey in input &&
415
363
  input[promptKey] != null
416
364
  ) {
@@ -437,13 +385,13 @@ export class MultiAgentGraph extends StandardGraph {
437
385
  },
438
386
  {
439
387
  name: toolName,
440
- schema: hasTransferInput
388
+ schema: hasHandoffInput
441
389
  ? {
442
390
  type: 'object',
443
391
  properties: {
444
392
  [promptKey]: {
445
393
  type: 'string',
446
- description: transferInputDescription as string,
394
+ description: handoffInputDescription as string,
447
395
  },
448
396
  },
449
397
  required: [],
@@ -457,15 +405,13 @@ export class MultiAgentGraph extends StandardGraph {
457
405
  /** Create individual tools for each destination */
458
406
  for (const destination of destinations) {
459
407
  const toolName = `${Constants.LC_TRANSFER_TO_}${destination}`;
460
- const destContext = this.agentContexts.get(destination);
461
408
  const toolDescription =
462
- edge.description ??
463
- this.buildDefaultTransferDescription(destContext, destination);
409
+ edge.description ?? `Transfer control to agent '${destination}'`;
464
410
 
465
411
  /** Check if we have a prompt for handoff input */
466
- const hasTransferInput =
412
+ const hasHandoffInput =
467
413
  edge.prompt != null && typeof edge.prompt === 'string';
468
- const transferInputDescription = hasTransferInput
414
+ const handoffInputDescription = hasHandoffInput
469
415
  ? edge.prompt
470
416
  : undefined;
471
417
  const promptKey = edge.promptKey ?? 'instructions';
@@ -480,7 +426,7 @@ export class MultiAgentGraph extends StandardGraph {
480
426
 
481
427
  let content = `Successfully transferred to ${destination}`;
482
428
  if (
483
- hasTransferInput &&
429
+ hasHandoffInput &&
484
430
  promptKey in input &&
485
431
  input[promptKey] != null
486
432
  ) {
@@ -571,13 +517,13 @@ export class MultiAgentGraph extends StandardGraph {
571
517
  },
572
518
  {
573
519
  name: toolName,
574
- schema: hasTransferInput
520
+ schema: hasHandoffInput
575
521
  ? {
576
522
  type: 'object',
577
523
  properties: {
578
524
  [promptKey]: {
579
525
  type: 'string',
580
- description: transferInputDescription as string,
526
+ description: handoffInputDescription as string,
581
527
  },
582
528
  },
583
529
  required: [],
@@ -593,774 +539,12 @@ export class MultiAgentGraph extends StandardGraph {
593
539
  return tools;
594
540
  }
595
541
 
596
- /**
597
- * Builds orchestration guidance injected into the system message of agents
598
- * that have handoff or transfer tools (i.e., orchestrator agents).
599
- *
600
- * Implements two orchestration primitives:
601
- * - Execution bias guidance injected into the system prompt
602
- * - Multi-round autonomous execution for dependent tasks
603
- *
604
- * Handoff tools are synchronous (browser-tool callback pattern): spawn the
605
- * child, await completion, return the real text as the tool output. Parallel
606
- * handoff tool calls in one turn run concurrently via LangGraph's ToolNode,
607
- * so independent children run in parallel without explicit orchestration.
608
- *
609
- * @param childDescs - Display names (with optional descriptions) of child agents
610
- * @param toolCount - Number of handoff/transfer tools available
611
- */
612
- private buildOrchestratorGuidance(
613
- childDescs: string[],
614
- toolCount: number
615
- ): string {
616
- return [
617
- '## Agent Orchestration',
618
- '',
619
- `You have ${toolCount} specialist agent(s) available for delegation:`,
620
- ...childDescs.map((d) => `- ${d}`),
621
- '',
622
- '## Execution Bias',
623
- 'If the user asks you to do the work, start doing it in the same turn.',
624
- 'Use a real tool call or concrete action first when the task is actionable; do not stop at a plan or promise-to-act reply.',
625
- 'Commentary-only turns are incomplete when tools are available and the next action is clear.',
626
- 'If the work will take multiple steps or a while to finish, send one short progress update before or while acting.',
627
- '',
628
- '## How Delegation Works',
629
- 'Each handoff tool call spawns a sub-agent, waits for it to complete, and returns the real result directly — like a function call.',
630
- 'Independent tasks MAY be called in parallel (multiple handoff tool calls in one turn). They run concurrently and all results return together.',
631
- 'Dependent tasks MUST be sequential: call one agent, get the result, then call the next agent using that real data.',
632
- '',
633
- '## Agent Isolation',
634
- "Sub-agents CANNOT see your conversation or the user's original message. They ONLY see what you write in the `instructions` parameter.",
635
- "When writing instructions, include ALL data the agent needs. Copy exact values from the user's message — email addresses, names, URLs, dates, numbers.",
636
- 'When delegating follow-up work, include the real data from prior agent results directly in the instructions text.',
637
- 'Do NOT re-delegate a task that was already completed. If you have the data, pass it directly.',
638
- ].join('\n');
639
- }
640
-
641
- /**
642
- * Builds subagent context instructions injected into child agents that are
643
- * handoff destinations. This tells the child agent it is a subagent with
644
- * a focused task.
645
- *
646
- * @param orchestratorName - Display name of the parent orchestrator agent
647
- */
648
- private buildChildAgentContext(orchestratorName: string): string {
649
- return [
650
- '# Subagent Context',
651
- '',
652
- `You are a **subagent** spawned by the ${orchestratorName} for a specific task.`,
653
- '',
654
- '## Your Role',
655
- "- Complete this task. That's your entire purpose.",
656
- `- You are NOT the ${orchestratorName}. Don't try to be.`,
657
- '',
658
- '## Rules',
659
- '1. **Stay focused** - Do your assigned task, nothing else',
660
- `2. **Complete the task** - Your final message will be automatically reported to the ${orchestratorName}`,
661
- "3. **Don't initiate** - No heartbeats, no proactive actions, no side quests",
662
- "4. **Be ephemeral** - You may be terminated after task completion. That's fine.",
663
- '',
664
- '## Output Format',
665
- 'When complete, your final response should include:',
666
- '- What you accomplished or found',
667
- `- Any relevant details the ${orchestratorName} should know`,
668
- '- Keep it concise but informative',
669
- '',
670
- "## What You DON'T Do",
671
- `- NO user conversations (that's ${orchestratorName}'s job)`,
672
- '- NO external messages (email, tweets, etc.) unless explicitly tasked with a specific recipient/channel',
673
- '- NO cron jobs or persistent state',
674
- `- NO pretending to be the ${orchestratorName}`,
675
- ].join('\n');
676
- }
677
-
678
- /**
679
- * Builds a meaningful default description for a transfer tool when no explicit
680
- * edge.description is provided. Uses the destination agent's name and description
681
- * so the LLM can make informed routing decisions.
682
- * @param destContext - AgentContext of the destination agent (may be undefined)
683
- * @param destinationId - Raw agent ID (fallback when context unavailable)
684
- */
685
- private buildDefaultTransferDescription(
686
- destContext: import('@/agents/AgentContext').AgentContext | undefined,
687
- destinationId: string
688
- ): string {
689
- const displayName = destContext?.name ?? destinationId;
690
- const agentDescription = destContext?.description;
691
-
692
- if (agentDescription != null && agentDescription !== '') {
693
- return `Transfer to "${displayName}": ${agentDescription}`;
694
- }
695
- return `Transfer control to "${displayName}"`;
696
- }
697
-
698
- /**
699
- * Create handoff tools for agents based on handoff edges.
700
- * Handoff tools invoke child agent subgraphs inline and return the result
701
- * as a string to the parent agent's context. Unlike transfer tools (which
702
- * return Command for one-way routing), handoff tools execute the child,
703
- * extract the final text, and return it within the parent's agent loop.
704
- *
705
- * This enables the supervisor pattern: parent calls child → gets result → thinks → calls another.
706
- */
707
- private createHandoffTools(): void {
708
- const handoffsByAgent = new Map<string, t.GraphEdge[]>();
709
-
710
- for (const edge of this.handoffEdges) {
711
- const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
712
- sources.forEach((source) => {
713
- if (!handoffsByAgent.has(source)) {
714
- handoffsByAgent.set(source, []);
715
- }
716
- handoffsByAgent.get(source)!.push(edge);
717
- });
718
- }
719
-
720
- for (const [agentId, edges] of handoffsByAgent) {
721
- const agentContext = this.agentContexts.get(agentId);
722
- if (!agentContext) continue;
723
-
724
- const handoffTools: t.GenericTool[] = [];
725
- for (const edge of edges) {
726
- handoffTools.push(...this.createHandoffToolsForEdge(edge, agentId));
727
- }
728
-
729
- if (!agentContext.graphTools) {
730
- agentContext.graphTools = [];
731
- }
732
- agentContext.graphTools.push(...handoffTools);
733
-
734
- // No collect_results tool needed — handoff tools use the browser-tool
735
- // callback pattern: spawn child, wait for completion, return real result.
736
- // The LLM naturally gets child results as tool return values.
737
-
738
- mlog(
739
- `[MultiAgentGraph] Handoff tools for "${agentId}": [${handoffTools.map((t) => t.name).join(', ')}]`
740
- );
741
-
742
- // Inject autonomous orchestration guidance for agents with handoff tools.
743
- const childDescs = edges.flatMap((e) => {
744
- const dests = Array.isArray(e.to) ? e.to : [e.to];
745
- return dests.map((d) => {
746
- const ctx = this.agentContexts.get(d);
747
- const name = ctx?.name ?? d;
748
- const desc = ctx?.description ? ` — ${ctx.description}` : '';
749
- return `${name}${desc}`;
750
- });
751
- });
752
- const orchestrationGuidance = this.buildOrchestratorGuidance(
753
- childDescs,
754
- handoffTools.length
755
- );
756
-
757
- const existing = agentContext.additionalInstructions ?? '';
758
- agentContext.additionalInstructions = existing
759
- ? `${existing}\n\n${orchestrationGuidance}`
760
- : orchestrationGuidance;
761
-
762
- // Inject subagent context into each child/destination agent.
763
- // This tells child agents they are subagents with a focused task — stay focused,
764
- // execute (don't plan), and return results to the orchestrator.
765
- const orchestratorName = agentContext.name ?? agentId;
766
- const childAgentContext = this.buildChildAgentContext(orchestratorName);
767
- for (const edge of edges) {
768
- const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
769
- for (const destId of dests) {
770
- const destCtx = this.agentContexts.get(destId);
771
- if (!destCtx) continue;
772
- const existingChild = destCtx.additionalInstructions ?? '';
773
- // Avoid duplicate injection if agent is destination of multiple edges
774
- if (existingChild.includes('# Subagent Context')) continue;
775
- destCtx.additionalInstructions = existingChild
776
- ? `${existingChild}\n\n${childAgentContext}`
777
- : childAgentContext;
778
- }
779
- }
780
- }
781
- }
782
-
783
- /**
784
- * Create handoff tools for an edge (handles multiple destinations).
785
- * Each handoff tool spawns the child agent's compiled subgraph asynchronously
786
- * and returns immediately. The orchestrator uses `collect_results` to retrieve
787
- * outputs and `check_agents` to monitor status — a push-based autonomous
788
- * orchestration pattern.
789
- *
790
- * @param edge - The graph edge defining the handoff
791
- * @param sourceAgentId - The ID of the parent/supervisor agent
792
- */
793
- private createHandoffToolsForEdge(
794
- edge: t.GraphEdge,
795
- sourceAgentId: string
796
- ): t.GenericTool[] {
797
- const tools: t.GenericTool[] = [];
798
- const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
799
- const maxResultChars =
800
- edge.maxResultChars ?? DEFAULT_HANDOFF_MAX_RESULT_CHARS;
801
-
802
- for (const destination of destinations) {
803
- const toolName = `${Constants.LC_HANDOFF_TO_}${destination}`;
804
- const destContext = this.agentContexts.get(destination);
805
- const toolDescription =
806
- edge.description ??
807
- this.buildDefaultHandoffDescription(destContext, destination);
808
-
809
- /**
810
- * Always include an instructions parameter so the orchestrator can
811
- * pass scoped task descriptions to each child agent. Without this,
812
- * the child gets no context about what to do.
813
- */
814
- const promptKey = edge.promptKey ?? 'instructions';
815
- const destDesc = destContext?.description;
816
- const promptInputDescription =
817
- edge.prompt ??
818
- (destDesc
819
- ? `Task instructions for this agent (${destDesc}). Describe exactly what it should do.`
820
- : 'Specific task instructions for this agent. Describe exactly what it should do and what data to use.');
821
-
822
- /** Capture registry reference — Map populated in createWorkflow() */
823
- const subgraphReg = this.subgraphRegistry;
824
-
825
- tools.push(
826
- tool(
827
- async (rawInput, config) => {
828
- const input = rawInput as Record<string, unknown>;
829
- const subgraph = subgraphReg.get(destination);
830
- if (!subgraph) {
831
- throw new Error(
832
- `Handoff target "${destination}" subgraph not found in registry. ` +
833
- 'This is a bug: createWorkflow() should have populated the subgraph registry.'
834
- );
835
- }
836
-
837
- /**
838
- * Per-spawn unique key = the orchestrator's tool_call.id.
839
- * LangChain's ToolNode passes `config.toolCall.id` to the tool
840
- * function; this is the same id the frontend sees on the parent's
841
- * handoff content part, so the UI can match each AgentHandoff
842
- * indicator to its own sidebar task without collision when the
843
- * same agent is invoked multiple times.
844
- */
845
- const toolCallCfg = (
846
- config as { toolCall?: { id?: string } } | undefined
847
- )?.toolCall;
848
- const spawnKey =
849
- toolCallCfg?.id ??
850
- `${destination}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
851
-
852
- /**
853
- * Hierarchical spawnPath: parent's spawnPath (from metadata) + this spawnKey.
854
- * Root invocations have empty parentSpawnPath. Threaded through childConfig
855
- * so nested handoffs/sequences inherit the full ancestry.
856
- * See docs/multi-agent-nesting-architecture.md §4.
857
- */
858
- const parentMetadata = (
859
- config as { metadata?: Record<string, unknown> } | undefined
860
- )?.metadata;
861
- const parentSpawnPath =
862
- typeof parentMetadata?.spawnPath === 'string'
863
- ? parentMetadata.spawnPath
864
- : '';
865
- const childSpawnPath = buildSpawnPath(parentSpawnPath, spawnKey);
866
- const childDepth = spawnPathDepth(childSpawnPath);
867
-
868
- /**
869
- * Child agent message construction — three modes:
870
- *
871
- * 1. Default (isolated-session pattern): Child gets ONLY the orchestrator's
872
- * task instructions as a single HumanMessage. No parent conversation
873
- * leaks. Orchestrator controls exactly what context the child sees.
874
- *
875
- * 2. Passthrough (edge.passthrough = true): Child gets the full parent
876
- * conversation + orchestrator's instructions appended. Use this when
877
- * the child needs the full user context (e.g., a transfer-like handoff).
878
- *
879
- * 3. Fallback: If no instructions provided AND not passthrough, child
880
- * gets the agent's description as its task.
881
- */
882
- const taskDescription =
883
- promptKey in input && input[promptKey] != null
884
- ? String(input[promptKey])
885
- : '';
886
-
887
- let childMessages: BaseMessage[];
888
- if (edge.passthrough) {
889
- // Passthrough: full parent context + instructions appended
890
- const state = getCurrentTaskInput() as t.BaseGraphState;
891
- childMessages = MultiAgentGraph.prepareHandoffMessages([
892
- ...state.messages,
893
- ]);
894
- if (taskDescription) {
895
- childMessages.push(new HumanMessage(taskDescription));
896
- }
897
- } else {
898
- // Default: isolated — only orchestrator's instructions
899
- const fallbackTask =
900
- destContext?.description ?? 'Complete your assigned task.';
901
- childMessages = [
902
- new HumanMessage(taskDescription || fallbackTask),
903
- ];
904
- }
905
-
906
- const childState: t.BaseGraphState = {
907
- messages: childMessages,
908
- };
909
-
910
- const childContext = this.agentContexts.get(destination);
911
- const destName = destContext?.name ?? destination;
912
- mlog(
913
- `[MultiAgentGraph] Handoff "${sourceAgentId}" -> "${destination}" SPAWN (async)\n` +
914
- ` messages: ${childMessages.length}\n` +
915
- ` childTools: ${childContext?.tools?.length ?? 0} instances\n` +
916
- ` childToolDefs: ${childContext?.toolDefinitions?.length ?? 0} definitions`
917
- );
918
-
919
- /**
920
- * Dispatch transition BEFORE spawning the child subgraph so that
921
- * callbacks.js sets multiAgentTrace.isMultiAgent = true before the
922
- * child's ON_RUN_STEP events fire. spawnKey lets the UI create a
923
- * distinct sidebar task for this specific invocation.
924
- */
925
- mlog(
926
- `[MultiAgentGraph] Handoff SPAWN "${sourceAgentId}" -> "${destination}" spawnKey=${spawnKey}`
927
- );
928
- await safeDispatchCustomEvent(
929
- GraphEvents.ON_AGENT_TRANSITION,
930
- {
931
- sourceAgentId: sourceAgentId,
932
- sourceAgentName:
933
- this.agentContexts.get(sourceAgentId)?.name ?? sourceAgentId,
934
- destinationAgentId: destination,
935
- destinationAgentName: destName,
936
- edgeType: EdgeType.HANDOFF,
937
- timestamp: Date.now(),
938
- spawnKey,
939
- spawnPath: childSpawnPath,
940
- parentSpawnPath: parentSpawnPath || null,
941
- spawnDepth: childDepth,
942
- },
943
- config
944
- );
945
-
946
- /**
947
- * Child events need to carry spawnKey so callbacks.js can route
948
- * them to the correct child aggregator. LangChain propagates
949
- * `metadata` and `tags` from the parent config to all descendants,
950
- * so everything dispatched inside subgraph.invoke will have
951
- * metadata.spawnKey populated on the event's runtime metadata.
952
- */
953
- const childConfig = {
954
- ...(config ?? {}),
955
- metadata: {
956
- ...((
957
- config as { metadata?: Record<string, unknown> } | undefined
958
- )?.metadata ?? {}),
959
- spawnKey,
960
- spawnAgentId: destination,
961
- /** Hierarchical identity — see spawnPath.ts */
962
- spawnPath: childSpawnPath,
963
- parentSpawnPath: parentSpawnPath || null,
964
- spawnDepth: childDepth,
965
- },
966
- tags: [
967
- ...((config as { tags?: string[] } | undefined)?.tags ?? []),
968
- `spawn:${spawnKey}`,
969
- `depth:${childDepth}`,
970
- ],
971
- };
972
-
973
- /**
974
- * Callback pattern: spawn child, WAIT for completion, return real
975
- * result. The parent naturally sees child results in its tool
976
- * return, so no manual "collect_results" step is needed.
977
- *
978
- * Parallelism still works: when the LLM emits multiple handoff
979
- * tool calls in one response, LangGraph runs all tool functions
980
- * concurrently. Each waits for its child. All results land in
981
- * the LLM's next turn together.
982
- */
983
- const spawnedAt = Date.now();
984
-
985
- try {
986
- const result = await subgraph.invoke(childState, childConfig);
987
- const durationMs = Date.now() - spawnedAt;
988
-
989
- const resultText = MultiAgentGraph.extractHandoffResult(
990
- result.messages,
991
- destination
992
- );
993
- const truncated = MultiAgentGraph.truncateHandoffResult(
994
- resultText,
995
- maxResultChars
996
- );
997
-
998
- mlog(
999
- `[MultiAgentGraph] Handoff COMPLETED "${sourceAgentId}" -> "${destination}" ` +
1000
- `spawnKey=${spawnKey} (${durationMs}ms, ${truncated.length} chars)`
1001
- );
1002
-
1003
- /** Dispatch completion event for UI update — carries spawnKey so
1004
- * the frontend can mark the correct sidebar task as completed. */
1005
- safeDispatchCustomEvent(
1006
- GraphEvents.ON_AGENT_TRANSITION,
1007
- {
1008
- sourceAgentId: destination,
1009
- sourceAgentName: destName,
1010
- destinationAgentId: sourceAgentId,
1011
- destinationAgentName:
1012
- this.agentContexts.get(sourceAgentId)?.name ??
1013
- sourceAgentId,
1014
- edgeType: EdgeType.HANDOFF,
1015
- timestamp: Date.now(),
1016
- isCompletion: true,
1017
- durationMs,
1018
- resultLength: truncated.length,
1019
- spawnKey,
1020
- spawnPath: childSpawnPath,
1021
- parentSpawnPath: parentSpawnPath || null,
1022
- spawnDepth: childDepth,
1023
- },
1024
- config
1025
- ).catch(() => {
1026
- /* best-effort event dispatch */
1027
- });
1028
-
1029
- return truncated;
1030
- } catch (err: unknown) {
1031
- const durationMs = Date.now() - spawnedAt;
1032
- const errMsg = err instanceof Error ? err.message : String(err);
1033
-
1034
- // EPIPE from console.debug is non-fatal
1035
- if (errMsg.includes('EPIPE')) {
1036
- mwarn(
1037
- `[MultiAgentGraph] Child "${destination}" hit EPIPE (non-fatal) spawnKey=${spawnKey}`
1038
- );
1039
- safeDispatchCustomEvent(
1040
- GraphEvents.ON_AGENT_TRANSITION,
1041
- {
1042
- sourceAgentId: destination,
1043
- sourceAgentName: destName,
1044
- destinationAgentId: sourceAgentId,
1045
- destinationAgentName:
1046
- this.agentContexts.get(sourceAgentId)?.name ??
1047
- sourceAgentId,
1048
- edgeType: EdgeType.HANDOFF,
1049
- timestamp: Date.now(),
1050
- isCompletion: true,
1051
- durationMs,
1052
- spawnKey,
1053
- spawnPath: childSpawnPath,
1054
- parentSpawnPath: parentSpawnPath || null,
1055
- spawnDepth: childDepth,
1056
- },
1057
- config
1058
- ).catch(() => {
1059
- /* best-effort */
1060
- });
1061
- return `Agent "${destName}" completed but output was lost due to stream closure.`;
1062
- }
1063
-
1064
- console.error(
1065
- `[MultiAgentGraph] Handoff FAILED "${sourceAgentId}" -> "${destination}" ` +
1066
- `spawnKey=${spawnKey} (${durationMs}ms): ${errMsg}`
1067
- );
1068
-
1069
- safeDispatchCustomEvent(
1070
- GraphEvents.ON_AGENT_TRANSITION,
1071
- {
1072
- sourceAgentId: destination,
1073
- sourceAgentName: destName,
1074
- destinationAgentId: sourceAgentId,
1075
- destinationAgentName:
1076
- this.agentContexts.get(sourceAgentId)?.name ??
1077
- sourceAgentId,
1078
- edgeType: EdgeType.HANDOFF,
1079
- timestamp: Date.now(),
1080
- isCompletion: true,
1081
- durationMs,
1082
- spawnKey,
1083
- spawnPath: childSpawnPath,
1084
- parentSpawnPath: parentSpawnPath || null,
1085
- spawnDepth: childDepth,
1086
- error: errMsg,
1087
- },
1088
- config
1089
- ).catch(() => {
1090
- /* best-effort */
1091
- });
1092
-
1093
- return `Agent "${destName}" failed after ${durationMs}ms: ${errMsg}`;
1094
- }
1095
- },
1096
- {
1097
- name: toolName,
1098
- schema: {
1099
- type: 'object',
1100
- properties: {
1101
- [promptKey]: {
1102
- type: 'string',
1103
- description: promptInputDescription,
1104
- },
1105
- },
1106
- required: [promptKey],
1107
- },
1108
- description: toolDescription,
1109
- }
1110
- )
1111
- );
1112
- }
1113
-
1114
- return tools;
1115
- }
1116
-
1117
- /**
1118
- * Extract the final text result from a child agent's output messages.
1119
- * Walks backwards to find the last AIMessage with text content.
1120
- * Handles both string content and array content (multi-modal messages).
1121
- * @param messages - The child agent's output messages
1122
- * @param agentId - The child agent ID (for fallback message)
1123
- */
1124
- static extractHandoffResult(
1125
- messages: BaseMessage[],
1126
- agentId: string
1127
- ): string {
1128
- for (let i = messages.length - 1; i >= 0; i--) {
1129
- const msg = messages[i];
1130
- if (msg.getType() !== 'ai') continue;
1131
-
1132
- const content = msg.content;
1133
- if (typeof content === 'string' && content.trim()) {
1134
- return content.trim();
1135
- }
1136
-
1137
- /** Handle array content (multi-modal messages with text blocks) */
1138
- if (Array.isArray(content)) {
1139
- const textParts = content
1140
- .filter(
1141
- (
1142
- block
1143
- ): block is {
1144
- type: string;
1145
- text: string;
1146
- } =>
1147
- typeof block === 'object' &&
1148
- block !== null &&
1149
- 'type' in block &&
1150
- block.type === 'text' &&
1151
- 'text' in block &&
1152
- typeof block.text === 'string'
1153
- )
1154
- .map((block) => block.text);
1155
-
1156
- const text = textParts.join('\n').trim();
1157
- if (text) return text;
1158
- }
1159
- }
1160
-
1161
- return `[Agent "${agentId}" completed but produced no text output]`;
1162
- }
1163
-
1164
- /**
1165
- * Truncate handoff result using head/tail strategy (60/40 split).
1166
- * Preserves the beginning (key findings) and end (conclusions).
1167
- * Matches the TaskTool.truncateResult pattern used by host orchestrators.
1168
- * @param result - The full result text
1169
- * @param maxChars - Maximum allowed characters
1170
- */
1171
- static truncateHandoffResult(result: string, maxChars: number): string {
1172
- if (!result || result.length <= maxChars) {
1173
- return result;
1174
- }
1175
-
1176
- const truncationNotice =
1177
- '\n\n[... handoff output truncated — middle section omitted to fit parent context ...]\n\n';
1178
- const available = maxChars - truncationNotice.length;
1179
- if (available <= 0) {
1180
- return result.substring(0, maxChars);
1181
- }
1182
-
1183
- const headSize = Math.floor(available * 0.6);
1184
- const tailSize = available - headSize;
1185
-
1186
- return (
1187
- result.substring(0, headSize) +
1188
- truncationNotice +
1189
- result.substring(result.length - tailSize)
1190
- );
1191
- }
1192
-
1193
- /**
1194
- * Build a meaningful default description for a handoff tool.
1195
- * @param destContext - AgentContext of the destination agent
1196
- * @param destinationId - Raw agent ID (fallback)
1197
- */
1198
- private buildDefaultHandoffDescription(
1199
- destContext: import('@/agents/AgentContext').AgentContext | undefined,
1200
- destinationId: string
1201
- ): string {
1202
- const displayName = destContext?.name ?? destinationId;
1203
- const agentDescription = destContext?.description;
1204
-
1205
- if (agentDescription != null && agentDescription !== '') {
1206
- return `Hand off task to "${displayName}": ${agentDescription}. The agent will execute and return its result.`;
1207
- }
1208
- return `Hand off task to "${displayName}" and receive its result.`;
1209
- }
1210
-
1211
542
  /**
1212
543
  * Create a complete agent subgraph (similar to createReactAgent)
1213
544
  */
1214
545
  private createAgentSubgraph(agentId: string): t.CompiledAgentWorfklow {
1215
- /**
1216
- * Scoped subgraph build for handoff targets.
1217
- *
1218
- * If the handoff target has outgoing sequence/transfer edges (e.g. a
1219
- * "researcher" agent with its own sequence `[researcher → prod_assistant]`),
1220
- * we compile a mini-StateGraph containing the agent and all agents reachable
1221
- * from it via non-handoff edges. This way, when the parent hands off to
1222
- * researcher via `subgraph.invoke()`, the nested sequence runs to completion
1223
- * before the result is returned to the parent.
1224
- *
1225
- * Fast path: if no downstream agents are reachable, fall back to the
1226
- * previous single-node behavior (`createAgentNode`).
1227
- *
1228
- * See docs/multi-agent-nesting-architecture.md §6.
1229
- */
1230
- const reachable = this.computeReachableViaNonHandoff(agentId);
1231
- if (reachable.size === 1) {
1232
- return this.createAgentNode(agentId);
1233
- }
1234
- mlog(
1235
- `[MultiAgentGraph] Scoped subgraph for "${agentId}": ${reachable.size} nodes [${Array.from(reachable).join(', ')}]`
1236
- );
1237
- return this.buildScopedSubgraph(agentId, reachable);
1238
- }
1239
-
1240
- /**
1241
- * BFS from `rootAgentId` across sequence + transfer edges (NOT handoff edges).
1242
- * Returns the set of agents reachable in this agent's "local workflow".
1243
- */
1244
- private computeReachableViaNonHandoff(rootAgentId: string): Set<string> {
1245
- const reachable = new Set<string>([rootAgentId]);
1246
- const queue: string[] = [rootAgentId];
1247
- const localEdges = [...this.sequenceEdges, ...this.transferEdges];
1248
- while (queue.length > 0) {
1249
- const current = queue.shift()!;
1250
- for (const edge of localEdges) {
1251
- const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
1252
- if (!sources.includes(current)) continue;
1253
- const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1254
- for (const dest of dests) {
1255
- if (!reachable.has(dest) && this.agentContexts.has(dest)) {
1256
- reachable.add(dest);
1257
- queue.push(dest);
1258
- }
1259
- }
1260
- }
1261
- }
1262
- return reachable;
1263
- }
1264
-
1265
- /**
1266
- * Build a compiled scoped StateGraph containing `agentIds` as nodes, rooted
1267
- * at `rootAgentId`. Linear sequence edges where both endpoints are in scope
1268
- * are wired directly; nodes with no outgoing in-scope edges route to END.
1269
- *
1270
- * Each node is wrapped around the per-agent `createAgentNode` compiled
1271
- * workflow (agent + tools loop) to preserve isolated tool context.
1272
- */
1273
- private buildScopedSubgraph(
1274
- rootAgentId: string,
1275
- agentIds: Set<string>
1276
- ): t.CompiledAgentWorfklow {
1277
- const StateAnnotation = Annotation.Root({
1278
- messages: Annotation<BaseMessage[]>({
1279
- reducer: messagesStateReducer,
1280
- default: () => [],
1281
- }),
1282
- });
1283
- const builder = new StateGraph(StateAnnotation);
1284
-
1285
- // Precompile each scoped agent's inner workflow and wrap as a node.
1286
- //
1287
- // Two different isolation strategies depending on position:
1288
- //
1289
- // • ROOT node (the handoff target itself): receives the parent
1290
- // orchestrator's handoff frame. Use `prepareHandoffMessages` — drops
1291
- // orphaned tool_use, compacts paired tool calls, guarantees trailing
1292
- // HumanMessage for Bedrock/VertexAI compatibility. The root needs
1293
- // orchestrator context because it's responding to the handoff.
1294
- //
1295
- // • DOWNSTREAM nodes (sequence targets of the root): run as FULLY
1296
- // ISOLATED child sessions. They receive only:
1297
- // [original user request, synthetic HumanMessage describing what
1298
- // the upstream agent produced and asking them to act]
1299
- // No raw tool_use / tool_result blocks from the upstream agent —
1300
- // prevents schema confusion when a downstream agent sees noisy
1301
- // upstream context and produces malformed tool_use JSON.
1302
- //
1303
- // Each wrapper returns only the DELTA (new messages produced by the
1304
- // inner invoke), not the prepared input — otherwise messagesStateReducer
1305
- // would double-append the synthetic instruction into the scoped state.
1306
- for (const aid of agentIds) {
1307
- const inner = this.createAgentNode(aid);
1308
- const isRoot = aid === rootAgentId;
1309
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1310
- builder.addNode(aid as any, async (state: t.BaseGraphState, config) => {
1311
- const prepared = isRoot
1312
- ? MultiAgentGraph.prepareHandoffMessages(state.messages)
1313
- : MultiAgentGraph.prepareIsolatedChildMessages(state.messages);
1314
- mlog(
1315
- `[MultiAgentGraph] scoped node "${aid}" entering (isRoot=${isRoot}, stateMessages=${state.messages.length}, prepared=${prepared.length})`
1316
- );
1317
- const result = await inner.invoke(
1318
- { ...state, messages: prepared },
1319
- config
1320
- );
1321
- // Return only the messages the inner node appended beyond its input,
1322
- // so messagesStateReducer doesn't duplicate the synthetic wrapper
1323
- // prompt into the scoped state.
1324
- const delta =
1325
- result.messages.length > prepared.length
1326
- ? result.messages.slice(prepared.length)
1327
- : result.messages;
1328
- return { messages: delta };
1329
- });
1330
- }
1331
-
1332
- // START → root
1333
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1334
- // @ts-ignore — LangGraph string typing is too strict for dynamic agent ids
1335
- builder.addEdge(START, rootAgentId);
1336
-
1337
- // Wire sequence edges in scope (linear chain support)
1338
- const hasOutgoing = new Set<string>();
1339
- for (const edge of this.sequenceEdges) {
1340
- const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
1341
- const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1342
- for (const source of sources) {
1343
- if (!agentIds.has(source)) continue;
1344
- for (const dest of dests) {
1345
- if (!agentIds.has(dest)) continue;
1346
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1347
- // @ts-ignore
1348
- builder.addEdge(source, dest);
1349
- hasOutgoing.add(source);
1350
- }
1351
- }
1352
- }
1353
-
1354
- // Leaves (no outgoing in-scope edges) route to END
1355
- for (const aid of agentIds) {
1356
- if (!hasOutgoing.has(aid)) {
1357
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1358
- // @ts-ignore
1359
- builder.addEdge(aid, END);
1360
- }
1361
- }
1362
-
1363
- return builder.compile(this.compileOptions as unknown as never);
546
+ /** This is essentially the same as `createAgentNode` from `StandardGraph` */
547
+ return this.createAgentNode(agentId);
1364
548
  }
1365
549
 
1366
550
  /**
@@ -1375,26 +559,7 @@ export class MultiAgentGraph extends StandardGraph {
1375
559
  * @param agentId - The agent ID to check for handoff reception
1376
560
  * @returns Object with filtered messages, extracted instructions, source agent, and parallel siblings
1377
561
  */
1378
-
1379
- /**
1380
- * Prepare messages for a handoff child agent. See
1381
- * {@link prepareHandoffMessagesUtil} for the full implementation and
1382
- * semantics — this static method is a thin delegate preserved for
1383
- * backward compatibility with existing call sites and unit tests.
1384
- */
1385
- static prepareHandoffMessages(messages: BaseMessage[]): BaseMessage[] {
1386
- return prepareHandoffMessagesUtil(messages);
1387
- }
1388
-
1389
- /**
1390
- * Build an isolated message context for a downstream scoped-subgraph
1391
- * node. See {@link prepareIsolatedChildMessagesUtil} for details.
1392
- */
1393
- static prepareIsolatedChildMessages(messages: BaseMessage[]): BaseMessage[] {
1394
- return prepareIsolatedChildMessagesUtil(messages);
1395
- }
1396
-
1397
- private processTransferReception(
562
+ private processHandoffReception(
1398
563
  messages: BaseMessage[],
1399
564
  agentId: string
1400
565
  ): {
@@ -1434,9 +599,8 @@ export class MultiAgentGraph extends StandardGraph {
1434
599
  if (isTransferMessage) {
1435
600
  destinationAgent = toolName.replace(Constants.LC_TRANSFER_TO_, '');
1436
601
  } else if (isConditionalTransfer) {
1437
- const transferDest = candidateMsg.additional_kwargs.handoff_destination;
1438
- destinationAgent =
1439
- typeof transferDest === 'string' ? transferDest : null;
602
+ const handoffDest = candidateMsg.additional_kwargs.handoff_destination;
603
+ destinationAgent = typeof handoffDest === 'string' ? handoffDest : null;
1440
604
  }
1441
605
 
1442
606
  /** Check if this transfer targets our agent */
@@ -1456,7 +620,7 @@ export class MultiAgentGraph extends StandardGraph {
1456
620
  ? toolMessage.content
1457
621
  : JSON.stringify(toolMessage.content);
1458
622
 
1459
- const instructionsMatch = contentStr.match(TRANSFER_INSTRUCTIONS_PATTERN);
623
+ const instructionsMatch = contentStr.match(HANDOFF_INSTRUCTIONS_PATTERN);
1460
624
  const instructions = instructionsMatch?.[1]?.trim() ?? null;
1461
625
 
1462
626
  /** Extract source agent name from additional_kwargs */
@@ -1530,14 +694,9 @@ export class MultiAgentGraph extends StandardGraph {
1530
694
  remainingToolCalls.length > 0 ||
1531
695
  (typeof aiMsg.content === 'string' && aiMsg.content.trim())
1532
696
  ) {
1533
- /** Keep the message but without transfer tool calls.
1534
- * Trim trailing whitespace to prevent Bedrock validation errors. */
1535
- const trimmedContent =
1536
- typeof aiMsg.content === 'string'
1537
- ? aiMsg.content.trimEnd()
1538
- : aiMsg.content;
697
+ /** Keep the message but without transfer tool calls */
1539
698
  const filteredAiMsg = new AIMessage({
1540
- content: trimmedContent,
699
+ content: aiMsg.content,
1541
700
  tool_calls: remainingToolCalls,
1542
701
  id: aiMsg.id,
1543
702
  });
@@ -1553,133 +712,8 @@ export class MultiAgentGraph extends StandardGraph {
1553
712
  filteredMessages.push(msg);
1554
713
  }
1555
714
 
1556
- /**
1557
- * Flatten tool call/result pairs into text summaries for handoff.
1558
- *
1559
- * When agent A uses tools and then hands off to agent B, agent B may not
1560
- * have the same tools configured. Providers like Bedrock require toolConfig
1561
- * when tool_use/tool_result blocks are in the message history. Converting
1562
- * tool interactions to text summaries avoids this and reduces context bloat.
1563
- *
1564
- * Strategy: Walk through messages and merge each (AIMessage-with-tool_calls +
1565
- * following ToolMessages) group into a single AIMessage containing the original
1566
- * text plus a textual summary of the tool interaction. This preserves proper
1567
- * message role ordering (human/assistant alternation).
1568
- */
1569
- const compactedMessages: BaseMessage[] = [];
1570
-
1571
- for (let i = 0; i < filteredMessages.length; i++) {
1572
- const msg = filteredMessages[i];
1573
- const msgType = msg.getType();
1574
-
1575
- if (msgType === 'ai') {
1576
- const aiMsg = msg as AIMessage | AIMessageChunk;
1577
- const toolCalls = aiMsg.tool_calls;
1578
-
1579
- if (toolCalls && toolCalls.length > 0) {
1580
- /** Extract text content from the AIMessage */
1581
- const textContent =
1582
- typeof aiMsg.content === 'string'
1583
- ? aiMsg.content
1584
- : Array.isArray(aiMsg.content)
1585
- ? aiMsg.content
1586
- .filter(
1587
- (b): b is { type: string; text: string } =>
1588
- typeof b === 'object' &&
1589
- b.type === 'text' &&
1590
- 'text' in b
1591
- )
1592
- .map((b) => b.text)
1593
- .join('\n')
1594
- : '';
1595
-
1596
- /** Collect tool_call_ids so we can match following ToolMessages */
1597
- const callIds = new Set(toolCalls.map((tc) => tc.id).filter(Boolean));
1598
-
1599
- /** Build summary of what tools were called */
1600
- const callSummaries = toolCalls.map((tc) => `[Called "${tc.name}"]`);
1601
-
1602
- /** Consume following ToolMessages that belong to this AI message */
1603
- const resultSummaries: string[] = [];
1604
- while (i + 1 < filteredMessages.length) {
1605
- const next = filteredMessages[i + 1];
1606
- if (next.getType() !== 'tool') break;
1607
-
1608
- const toolMsg = next as ToolMessage;
1609
- if (!callIds.has(toolMsg.tool_call_id)) break;
1610
-
1611
- /** Extract and summarize the tool result */
1612
- const rawContent =
1613
- typeof toolMsg.content === 'string'
1614
- ? toolMsg.content
1615
- : Array.isArray(toolMsg.content)
1616
- ? toolMsg.content
1617
- .filter(
1618
- (b): b is { type: string; text: string } =>
1619
- typeof b === 'object' &&
1620
- 'text' in b &&
1621
- typeof (b as Record<string, unknown>).text ===
1622
- 'string'
1623
- )
1624
- .map((b) => b.text)
1625
- .join('\n')
1626
- : JSON.stringify(toolMsg.content);
1627
-
1628
- const summary =
1629
- rawContent.length > 500
1630
- ? rawContent.split('\n')[0] + ' [truncated for handoff]'
1631
- : rawContent;
1632
-
1633
- resultSummaries.push(
1634
- `[Tool "${toolMsg.name}" returned: ${summary}]`
1635
- );
1636
- i++; // Skip this ToolMessage in the outer loop
1637
- }
1638
-
1639
- /** Merge everything into a single AIMessage */
1640
- const parts = [
1641
- textContent,
1642
- ...callSummaries,
1643
- ...resultSummaries,
1644
- ].filter(Boolean);
1645
-
1646
- /** Bedrock rejects messages with trailing whitespace */
1647
- const mergedContent = (
1648
- parts.join('\n') || '[Agent processed tools]'
1649
- ).trimEnd();
1650
- compactedMessages.push(
1651
- new AIMessage({
1652
- content: mergedContent,
1653
- id: aiMsg.id,
1654
- })
1655
- );
1656
- continue;
1657
- }
1658
- }
1659
-
1660
- /** Skip orphaned ToolMessages (their AI parent was already handled above,
1661
- * or they belong to a transfer that was already filtered out) */
1662
- if (msgType === 'tool') {
1663
- continue;
1664
- }
1665
-
1666
- /** Trim trailing whitespace on AI messages to prevent Bedrock validation errors */
1667
- if (
1668
- msgType === 'ai' &&
1669
- typeof msg.content === 'string' &&
1670
- msg.content !== msg.content.trimEnd()
1671
- ) {
1672
- compactedMessages.push(
1673
- new AIMessage({ content: msg.content.trimEnd(), id: msg.id })
1674
- );
1675
- continue;
1676
- }
1677
-
1678
- compactedMessages.push(msg);
1679
- }
1680
-
1681
715
  return {
1682
- filteredMessages: compactedMessages,
716
+ filteredMessages,
1683
717
  instructions,
1684
718
  sourceAgentName,
1685
719
  parallelSiblings,
@@ -1687,7 +721,7 @@ export class MultiAgentGraph extends StandardGraph {
1687
721
  }
1688
722
 
1689
723
  /**
1690
- * Create the multi-agent workflow with handoffs, transfers, and sequences
724
+ * Create the multi-agent workflow with dynamic handoffs
1691
725
  */
1692
726
  override createWorkflow(): t.CompiledMultiAgentWorkflow {
1693
727
  const StateAnnotation = Annotation.Root({
@@ -1712,150 +746,72 @@ export class MultiAgentGraph extends StandardGraph {
1712
746
 
1713
747
  const builder = new StateGraph(StateAnnotation);
1714
748
 
1715
- /**
1716
- * Identify agents that are ONLY handoff destinations (not transfer/sequence
1717
- * destinations and not starting nodes). These agents are invoked inline via
1718
- * subgraph.invoke() inside handoff tools — they must NOT be added as
1719
- * top-level nodes in the parent graph because LangGraph validates that all
1720
- * nodes are reachable from START via edges.
1721
- */
1722
- const handoffOnlyDestinations = new Set<string>();
1723
- const transferOrSequenceDestinations = new Set<string>();
1724
-
1725
- for (const edge of this.handoffEdges) {
1726
- const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1727
- dests.forEach((d) => handoffOnlyDestinations.add(d));
1728
- }
1729
- for (const edge of [...this.transferEdges, ...this.sequenceEdges]) {
1730
- const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1731
- dests.forEach((d) => transferOrSequenceDestinations.add(d));
1732
- }
1733
- // Remove agents that are also transfer/sequence destinations or starting nodes
1734
- for (const d of transferOrSequenceDestinations) {
1735
- handoffOnlyDestinations.delete(d);
1736
- }
1737
- for (const startNode of this.startingNodes) {
1738
- handoffOnlyDestinations.delete(startNode);
1739
- }
1740
-
1741
- /**
1742
- * Nested-sequence expansion: for each handoff-only target, its downstream
1743
- * sequence/transfer agents MUST also become handoff-only — they exist only
1744
- * inside the target's scoped subgraph, not at top level. Without this,
1745
- * those downstream nodes would be added as top-level orphans and LangGraph
1746
- * would fail compilation (UNREACHABLE_NODE).
1747
- *
1748
- * See docs/multi-agent-nesting-architecture.md §6.
1749
- */
1750
- const nestedHandoffOnly = new Set<string>();
1751
- for (const target of handoffOnlyDestinations) {
1752
- const reachable = this.computeReachableViaNonHandoff(target);
1753
- for (const agent of reachable) {
1754
- if (agent === target) continue;
1755
- // Skip if this agent is legitimately a top-level starting node
1756
- if (this.startingNodes.has(agent)) continue;
1757
- nestedHandoffOnly.add(agent);
1758
- }
1759
- }
1760
- for (const agent of nestedHandoffOnly) {
1761
- handoffOnlyDestinations.add(agent);
1762
- }
1763
- if (nestedHandoffOnly.size > 0) {
1764
- mlog(
1765
- `[MultiAgentGraph] Nested handoff-only (scoped subgraph downstream): [${Array.from(nestedHandoffOnly).join(', ')}]`
1766
- );
1767
- }
1768
-
1769
- if (handoffOnlyDestinations.size > 0) {
1770
- mlog(
1771
- `[MultiAgentGraph] Handoff-only children (subgraph only, no top-level node): [${Array.from(handoffOnlyDestinations).join(', ')}]`
1772
- );
1773
- }
1774
-
1775
- // Add agents as nodes — skip handoff-only children (they exist as subgraphs only)
749
+ // Add all agents as complete subgraphs
1776
750
  for (const [agentId] of this.agentContexts) {
1777
751
  // Get all possible destinations for this agent
1778
- const transferDestinations = new Set<string>();
1779
- const sequenceDestinations = new Set<string>();
752
+ const handoffDestinations = new Set<string>();
753
+ const directDestinations = new Set<string>();
1780
754
 
1781
- // Check transfer edges for destinations
1782
- for (const edge of this.transferEdges) {
755
+ // Check handoff edges for destinations
756
+ for (const edge of this.handoffEdges) {
1783
757
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
1784
758
  if (sources.includes(agentId) === true) {
1785
759
  const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1786
- dests.forEach((dest) => transferDestinations.add(dest));
760
+ dests.forEach((dest) => handoffDestinations.add(dest));
1787
761
  }
1788
762
  }
1789
763
 
1790
- // Check sequence edges for destinations
1791
- for (const edge of this.sequenceEdges) {
764
+ // Check direct edges for destinations
765
+ for (const edge of this.directEdges) {
1792
766
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
1793
767
  if (sources.includes(agentId) === true) {
1794
768
  const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
1795
- dests.forEach((dest) => sequenceDestinations.add(dest));
769
+ dests.forEach((dest) => directDestinations.add(dest));
1796
770
  }
1797
771
  }
1798
772
 
1799
- /** Check if this agent has BOTH transfer and sequence edges */
1800
- const hasTransferEdges = transferDestinations.size > 0;
1801
- const hasSequenceEdges = sequenceDestinations.size > 0;
1802
- const needsCommandRouting = hasTransferEdges && hasSequenceEdges;
773
+ /** Check if this agent has BOTH handoff and direct edges */
774
+ const hasHandoffEdges = handoffDestinations.size > 0;
775
+ const hasDirectEdges = directDestinations.size > 0;
776
+ const needsCommandRouting = hasHandoffEdges && hasDirectEdges;
1803
777
 
1804
778
  /** Collect all possible destinations for this agent */
1805
779
  const allDestinations = new Set([
1806
- ...transferDestinations,
1807
- ...sequenceDestinations,
780
+ ...handoffDestinations,
781
+ ...directDestinations,
1808
782
  ]);
1809
- if (transferDestinations.size > 0 || sequenceDestinations.size === 0) {
783
+ if (handoffDestinations.size > 0 || directDestinations.size === 0) {
1810
784
  allDestinations.add(END);
1811
785
  }
1812
786
 
1813
787
  /** Agent subgraph (includes agent + tools) */
1814
788
  const agentSubgraph = this.createAgentSubgraph(agentId);
1815
789
 
1816
- /** Register subgraph for handoff tools (lazy reference resolution) */
1817
- this.subgraphRegistry.set(agentId, agentSubgraph);
1818
-
1819
- /**
1820
- * Handoff-only children are invoked inline via subgraph.invoke() — they
1821
- * don't need a top-level node. Adding them would cause LangGraph to reject
1822
- * the graph because no edge routes to them (UNREACHABLE_NODE).
1823
- */
1824
- if (handoffOnlyDestinations.has(agentId)) {
1825
- continue;
1826
- }
1827
-
1828
790
  /** Wrapper function that handles agentMessages channel, handoff reception, and conditional routing */
1829
791
  const agentWrapper = async (
1830
792
  state: t.MultiAgentGraphState,
1831
793
  config?: LangGraphRunnableConfig
1832
794
  ): Promise<t.MultiAgentGraphState | Command> => {
1833
- mlog(
1834
- `[MultiAgentGraph] Agent "${agentId}" wrapper ENTRY (messages: ${state.messages.length}, needsCommandRouting: ${needsCommandRouting})`
1835
- );
1836
795
  let result: t.MultiAgentGraphState;
1837
796
 
1838
797
  /**
1839
- * Check if this agent is receiving a transfer.
798
+ * Check if this agent is receiving a handoff.
1840
799
  * If so, filter out the transfer messages and inject instructions as preamble.
1841
800
  * This prevents the receiving agent from seeing the transfer as "completed work"
1842
801
  * and prematurely producing an end token.
1843
802
  */
1844
- const transferContext = this.processTransferReception(
803
+ const handoffContext = this.processHandoffReception(
1845
804
  state.messages,
1846
805
  agentId
1847
806
  );
1848
807
 
1849
- if (transferContext !== null) {
808
+ if (handoffContext !== null) {
1850
809
  const {
1851
810
  filteredMessages,
1852
811
  instructions,
1853
812
  sourceAgentName,
1854
813
  parallelSiblings,
1855
- } = transferContext;
1856
- mlog(
1857
- `[MultiAgentGraph] Agent "${agentId}" receiving transfer from "${sourceAgentName}" (instructions: ${instructions != null}, parallelSiblings: ${parallelSiblings.length})`
1858
- );
814
+ } = handoffContext;
1859
815
 
1860
816
  /**
1861
817
  * Set handoff context on the receiving agent.
@@ -1992,16 +948,9 @@ export class MultiAgentGraph extends StandardGraph {
1992
948
  result = await agentSubgraph.invoke(state, config);
1993
949
  }
1994
950
 
1995
- /** Track the last agent that produced output for continuation support */
1996
- this.lastActiveAgentId = agentId;
1997
-
1998
- mlog(
1999
- `[MultiAgentGraph] Agent "${agentId}" wrapper EXIT (result messages: ${result.messages.length})`
2000
- );
2001
-
2002
- /** If agent has both transfer and sequence edges, use Command for exclusive routing */
951
+ /** If agent has both handoff and direct edges, use Command for exclusive routing */
2003
952
  if (needsCommandRouting) {
2004
- /** Check if a transfer occurred */
953
+ /** Check if a handoff occurred */
2005
954
  const lastMessage = result.messages[
2006
955
  result.messages.length - 1
2007
956
  ] as BaseMessage | null;
@@ -2011,166 +960,18 @@ export class MultiAgentGraph extends StandardGraph {
2011
960
  typeof lastMessage.name === 'string' &&
2012
961
  lastMessage.name.startsWith(Constants.LC_TRANSFER_TO_)
2013
962
  ) {
2014
- /** Transfer occurred - extract destination and navigate there exclusively */
2015
- const transferDest = lastMessage.name.replace(
963
+ /** Handoff occurred - extract destination and navigate there exclusively */
964
+ const handoffDest = lastMessage.name.replace(
2016
965
  Constants.LC_TRANSFER_TO_,
2017
966
  ''
2018
967
  );
2019
- mlog(
2020
- `[MultiAgentGraph] Command routing: "${agentId}" -> transfer to "${transferDest}" (sequence edges skipped: [${Array.from(sequenceDestinations).join(', ')}])`
2021
- );
2022
-
2023
- /** Validate destination agent exists */
2024
- if (!this.agentContexts.has(transferDest)) {
2025
- const availableAgents = Array.from(
2026
- this.agentContexts.keys()
2027
- ).join(', ');
2028
- console.error(
2029
- `[MultiAgentGraph] Transfer to non-existent agent "${transferDest}". Available: ${availableAgents}`
2030
- );
2031
- /** Return error to model so it can self-correct */
2032
- const errorMsg = new ToolMessage({
2033
- content: `Transfer failed: agent "${transferDest}" does not exist. Available agents: ${availableAgents}. Please choose a valid agent to transfer to.`,
2034
- tool_call_id: (lastMessage as ToolMessage).tool_call_id,
2035
- name: lastMessage.name,
2036
- });
2037
- (errorMsg as ToolMessage).status = 'error';
2038
- return {
2039
- messages: [...result.messages, errorMsg],
2040
- };
2041
- }
2042
-
2043
- /** Pre-handoff context compaction: if receiving agent has smaller budget */
2044
- const receiverContext = this.agentContexts.get(transferDest);
2045
- const senderContext = this.agentContexts.get(agentId);
2046
- if (
2047
- receiverContext?.maxContextTokens != null &&
2048
- senderContext?.tokenCounter != null &&
2049
- receiverContext.maxContextTokens > 0
2050
- ) {
2051
- let currentSize = 0;
2052
- for (const msg of result.messages) {
2053
- currentSize += senderContext.tokenCounter(msg);
2054
- }
2055
- const receiverBudget = receiverContext.maxContextTokens;
2056
-
2057
- if (currentSize > receiverBudget * 0.7) {
2058
- mwarn(
2059
- `[MultiAgentGraph] Pre-handoff compaction: context (${currentSize} tokens) exceeds ` +
2060
- `70% of receiver "${transferDest}" budget (${receiverBudget} tokens)`
2061
- );
2062
-
2063
- /** Generate handoff briefing */
2064
- const senderName = senderContext.name ?? agentId;
2065
- if (senderContext.summarizeCallback) {
2066
- try {
2067
- const briefingResult = await summarize(
2068
- result.messages,
2069
- async (prompt, _maxTokens) =>
2070
- senderContext.summarizeCallback!([
2071
- new HumanMessage(prompt),
2072
- ]),
2073
- {
2074
- tokenCounter: senderContext.tokenCounter,
2075
- summaryBudget: Math.floor(receiverBudget * 0.2),
2076
- isMultiAgent: true,
2077
- agentWorkflowState: {
2078
- currentAgentId: transferDest,
2079
- agentChain: [agentId, transferDest],
2080
- pendingAgents: [],
2081
- },
2082
- }
2083
- );
2084
-
2085
- const briefingMsg = new SystemMessage(
2086
- `[Handoff Briefing from "${senderName}"]\n${briefingResult.summary}`
2087
- );
2088
-
2089
- /** Replace messages with briefing + last 3 messages */
2090
- const keepCount = Math.min(3, result.messages.length);
2091
- result = {
2092
- ...result,
2093
- messages: [
2094
- briefingMsg,
2095
- ...result.messages.slice(
2096
- result.messages.length - keepCount
2097
- ),
2098
- ],
2099
- };
2100
-
2101
- console.info(
2102
- `[MultiAgentGraph] Pre-handoff compaction complete: ${currentSize} tokens → briefing + ${keepCount} messages`
2103
- );
2104
- } catch (compactErr) {
2105
- console.error(
2106
- '[MultiAgentGraph] Pre-handoff compaction failed:',
2107
- compactErr
2108
- );
2109
- /** Continue without compaction — let receiver handle the overflow */
2110
- }
2111
- } else {
2112
- /** No summary callback — use emergency summary */
2113
- const emergencySummary = createEmergencySummary(
2114
- result.messages
2115
- );
2116
- const briefingMsg = new SystemMessage(
2117
- `[Handoff Briefing from "${senderName}" — Emergency]\n${emergencySummary}`
2118
- );
2119
- const keepCount = Math.min(3, result.messages.length);
2120
- result = {
2121
- ...result,
2122
- messages: [
2123
- briefingMsg,
2124
- ...result.messages.slice(
2125
- result.messages.length - keepCount
2126
- ),
2127
- ],
2128
- };
2129
- }
2130
- }
2131
- }
2132
-
2133
- await safeDispatchCustomEvent(
2134
- GraphEvents.ON_AGENT_TRANSITION,
2135
- {
2136
- sourceAgentId: agentId,
2137
- sourceAgentName:
2138
- this.agentContexts.get(agentId)?.name ?? agentId,
2139
- destinationAgentId: transferDest,
2140
- destinationAgentName:
2141
- this.agentContexts.get(transferDest)?.name ?? transferDest,
2142
- edgeType: EdgeType.TRANSFER,
2143
- timestamp: Date.now(),
2144
- },
2145
- config
2146
- );
2147
-
2148
968
  return new Command({
2149
969
  update: result,
2150
- goto: transferDest,
970
+ goto: handoffDest,
2151
971
  });
2152
972
  } else {
2153
- /** No transfer - proceed with sequence edges */
2154
- mlog(
2155
- `[MultiAgentGraph] Command routing: "${agentId}" -> no transfer, following sequence edges: [${Array.from(sequenceDestinations).join(', ')}]`
2156
- );
2157
- const directDests = Array.from(sequenceDestinations);
2158
- for (const dest of directDests) {
2159
- await safeDispatchCustomEvent(
2160
- GraphEvents.ON_AGENT_TRANSITION,
2161
- {
2162
- sourceAgentId: agentId,
2163
- sourceAgentName:
2164
- this.agentContexts.get(agentId)?.name ?? agentId,
2165
- destinationAgentId: dest,
2166
- destinationAgentName:
2167
- this.agentContexts.get(dest)?.name ?? dest,
2168
- edgeType: EdgeType.SEQUENCE,
2169
- timestamp: Date.now(),
2170
- },
2171
- config
2172
- );
2173
- }
973
+ /** No handoff - proceed with direct edges */
974
+ const directDests = Array.from(directDestinations);
2174
975
  if (directDests.length === 1) {
2175
976
  return new Command({
2176
977
  update: result,
@@ -2186,37 +987,7 @@ export class MultiAgentGraph extends StandardGraph {
2186
987
  }
2187
988
  }
2188
989
 
2189
- /**
2190
- * No Command routing needed — dispatch ON_AGENT_TRANSITION for all
2191
- * destinations so callbacks.js can register child agents for event
2192
- * isolation BEFORE they start streaming.
2193
- */
2194
- const allDests = new Set([
2195
- ...transferDestinations,
2196
- ...sequenceDestinations,
2197
- ]);
2198
- if (allDests.size > 0) {
2199
- const edgeType = hasTransferEdges
2200
- ? EdgeType.TRANSFER
2201
- : EdgeType.SEQUENCE;
2202
- for (const dest of allDests) {
2203
- await safeDispatchCustomEvent(
2204
- GraphEvents.ON_AGENT_TRANSITION,
2205
- {
2206
- sourceAgentId: agentId,
2207
- sourceAgentName:
2208
- this.agentContexts.get(agentId)?.name ?? agentId,
2209
- destinationAgentId: dest,
2210
- destinationAgentName:
2211
- this.agentContexts.get(dest)?.name ?? dest,
2212
- edgeType,
2213
- timestamp: Date.now(),
2214
- },
2215
- config
2216
- );
2217
- }
2218
- }
2219
-
990
+ /** No special routing needed - return state normally */
2220
991
  return result;
2221
992
  };
2222
993
 
@@ -2226,66 +997,21 @@ export class MultiAgentGraph extends StandardGraph {
2226
997
  });
2227
998
  }
2228
999
 
2229
- /**
2230
- * Add starting edges from START to entry agent(s).
2231
- *
2232
- * Multi-turn resumption: when `resumeFromAgentId` is set and refers to a
2233
- * valid agent in this graph, START routes exclusively to that agent so
2234
- * follow-up messages continue where the previous turn left off.
2235
- *
2236
- * Default behavior (no resume): static edges to all starting nodes,
2237
- * preserving parallel execution for graphs with multiple entry points.
2238
- */
2239
- const validResumeAgent =
2240
- this.resumeFromAgentId != null &&
2241
- this.agentContexts.has(this.resumeFromAgentId);
2242
-
2243
- if (validResumeAgent) {
2244
- const resumeAgentId = this.resumeFromAgentId!;
2245
- mlog(
2246
- `[MultiAgentGraph] Multi-turn resumption: routing START → "${resumeAgentId}" (skipping default starting nodes: [${Array.from(this.startingNodes).join(', ')}])`
2247
- );
2248
-
2249
- /**
2250
- * Build route map containing both the resume agent and default starting
2251
- * nodes. This is required by LangGraph — all possible destinations must
2252
- * be declared even if the router always picks one.
2253
- */
2254
- const allPossibleStarts = new Set([...this.startingNodes, resumeAgentId]);
2255
- const routeMap: Record<string, string> = {};
2256
- for (const nodeId of allPossibleStarts) {
2257
- routeMap[nodeId] = nodeId;
2258
- }
2259
-
2260
- builder.addConditionalEdges(
2261
- START,
2262
- () => resumeAgentId,
2263
- routeMap as unknown as never
2264
- );
2265
- } else {
2266
- if (this.resumeFromAgentId != null) {
2267
- mwarn(
2268
- `[MultiAgentGraph] resumeFromAgentId "${this.resumeFromAgentId}" not found in graph — falling back to default starting nodes`
2269
- );
2270
- }
2271
- for (const startNode of this.startingNodes) {
2272
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2273
- /** @ts-ignore */
2274
- builder.addEdge(START, startNode);
2275
- }
1000
+ // Add starting edges for all starting nodes
1001
+ for (const startNode of this.startingNodes) {
1002
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1003
+ /** @ts-ignore */
1004
+ builder.addEdge(START, startNode);
2276
1005
  }
2277
1006
 
2278
1007
  /**
2279
- * Add approval gate nodes for sequence edges with approvalGate config.
2280
- * Gates are inserted between source and destination agents.
2281
- * They ALWAYS fire regardless of ExecutionContext.
1008
+ * Add approval-gate nodes for sequence edges that declare an approvalGate
1009
+ * config (Ranger-only feature, not present upstream). Gates fire
1010
+ * regardless of ExecutionContext and sit between source and destination.
2282
1011
  */
2283
1012
  const gatedEdges = new Set<t.GraphEdge>();
2284
-
2285
- for (const edge of this.sequenceEdges) {
2286
- if (!edge.approvalGate) {
2287
- continue;
2288
- }
1013
+ for (const edge of this.directEdges) {
1014
+ if (!edge.approvalGate) continue;
2289
1015
 
2290
1016
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
2291
1017
  const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
@@ -2293,9 +1019,6 @@ export class MultiAgentGraph extends StandardGraph {
2293
1019
  for (const source of sources) {
2294
1020
  for (const dest of destinations) {
2295
1021
  const gateNodeId = getApprovalGateNodeId(edge.approvalGate.gateId);
2296
- const onDeny = edge.approvalGate.onDeny ?? 'stop';
2297
-
2298
- // Add the gate node
2299
1022
  const gateNode = createApprovalGateNode(
2300
1023
  edge.approvalGate,
2301
1024
  source,
@@ -2305,60 +1028,28 @@ export class MultiAgentGraph extends StandardGraph {
2305
1028
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2306
1029
  /** @ts-ignore */
2307
1030
  builder.addNode(gateNodeId, gateNode);
2308
-
2309
- // Wire: source → gate
2310
1031
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2311
1032
  /** @ts-ignore */
2312
1033
  builder.addEdge(source, gateNodeId);
2313
-
2314
- // Wire: gate → destination (always, since approval is handled
2315
- // by the interrupt/resume mechanism — if denied, the host
2316
- // can choose not to resume, or resume with approved=false
2317
- // and the gate returns empty state)
2318
- if (onDeny === 'skip') {
2319
- // Conditional edge: approved → destination, denied → END
2320
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2321
- /** @ts-ignore */
2322
- builder.addEdge(gateNodeId, dest);
2323
- } else {
2324
- // Direct edge to destination — denial stops via non-resume or
2325
- // the host terminates the graph
2326
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2327
- /** @ts-ignore */
2328
- builder.addEdge(gateNodeId, dest);
2329
- }
1034
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1035
+ /** @ts-ignore */
1036
+ builder.addEdge(gateNodeId, dest);
2330
1037
  }
2331
1038
  }
2332
-
2333
1039
  gatedEdges.add(edge);
2334
1040
  }
2335
1041
 
2336
1042
  /**
2337
1043
  * Add sequence edges for automatic transitions
2338
1044
  * Group edges by destination to handle fan-in scenarios
2339
- * Skip edges that have approval gates (already handled above)
1045
+ * (Skip edges that already have an approval gate above.)
2340
1046
  */
2341
1047
  const edgesByDestination = new Map<string, t.GraphEdge[]>();
2342
1048
 
2343
- for (const edge of this.sequenceEdges) {
2344
- if (gatedEdges.has(edge)) {
2345
- continue;
2346
- }
2347
- /**
2348
- * Skip sequence edges where either endpoint lives only inside a scoped
2349
- * handoff subgraph. Those edges are wired inside `buildScopedSubgraph`,
2350
- * not at the top level — adding them here would reference non-existent
2351
- * top-level nodes and fail compilation.
2352
- */
2353
- const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
2354
- const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
2355
- const anyEndpointHandoffOnly = [...sources, ...dests].some((n) =>
2356
- handoffOnlyDestinations.has(n)
2357
- );
2358
- if (anyEndpointHandoffOnly) {
2359
- continue;
2360
- }
2361
- for (const destination of dests) {
1049
+ for (const edge of this.directEdges) {
1050
+ if (gatedEdges.has(edge)) continue;
1051
+ const destinations = Array.isArray(edge.to) ? edge.to : [edge.to];
1052
+ for (const destination of destinations) {
2362
1053
  if (!edgesByDestination.has(destination)) {
2363
1054
  edgesByDestination.set(destination, []);
2364
1055
  }
@@ -2455,21 +1146,18 @@ export class MultiAgentGraph extends StandardGraph {
2455
1146
  for (const edge of edges) {
2456
1147
  const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
2457
1148
  for (const source of sources) {
2458
- /** Check if this source node has both transfer and sequence edges */
2459
- const sourceTransferEdges = this.transferEdges.filter((e) => {
1149
+ /** Check if this source node has both handoff and direct edges */
1150
+ const sourceHandoffEdges = this.handoffEdges.filter((e) => {
2460
1151
  const eSources = Array.isArray(e.from) ? e.from : [e.from];
2461
1152
  return eSources.includes(source);
2462
1153
  });
2463
- const sourceSequenceEdges = this.sequenceEdges.filter((e) => {
1154
+ const sourceDirectEdges = this.directEdges.filter((e) => {
2464
1155
  const eSources = Array.isArray(e.from) ? e.from : [e.from];
2465
1156
  return eSources.includes(source);
2466
1157
  });
2467
1158
 
2468
1159
  /** Skip adding edge if source uses Command routing (has both types) */
2469
- if (
2470
- sourceTransferEdges.length > 0 &&
2471
- sourceSequenceEdges.length > 0
2472
- ) {
1160
+ if (sourceHandoffEdges.length > 0 && sourceDirectEdges.length > 0) {
2473
1161
  continue;
2474
1162
  }
2475
1163