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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (653) 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/graphs/phases/memoryFlushPhase.cjs +1 -1
  11. package/dist/cjs/graphs/phases/memoryFlushPhase.cjs.map +1 -1
  12. package/dist/cjs/hooks/HookRegistry.cjs +162 -0
  13. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -0
  14. package/dist/cjs/hooks/executeHooks.cjs +276 -0
  15. package/dist/cjs/hooks/executeHooks.cjs.map +1 -0
  16. package/dist/cjs/hooks/matchers.cjs +256 -0
  17. package/dist/cjs/hooks/matchers.cjs.map +1 -0
  18. package/dist/cjs/hooks/types.cjs +27 -0
  19. package/dist/cjs/hooks/types.cjs.map +1 -0
  20. package/dist/cjs/langchain/google-common.cjs +3 -0
  21. package/dist/cjs/langchain/google-common.cjs.map +1 -0
  22. package/dist/cjs/langchain/index.cjs +86 -0
  23. package/dist/cjs/langchain/index.cjs.map +1 -0
  24. package/dist/cjs/langchain/language_models/chat_models.cjs +3 -0
  25. package/dist/cjs/langchain/language_models/chat_models.cjs.map +1 -0
  26. package/dist/cjs/langchain/messages/tool.cjs +3 -0
  27. package/dist/cjs/langchain/messages/tool.cjs.map +1 -0
  28. package/dist/cjs/langchain/messages.cjs +51 -0
  29. package/dist/cjs/langchain/messages.cjs.map +1 -0
  30. package/dist/cjs/langchain/openai.cjs +3 -0
  31. package/dist/cjs/langchain/openai.cjs.map +1 -0
  32. package/dist/cjs/langchain/prompts.cjs +11 -0
  33. package/dist/cjs/langchain/prompts.cjs.map +1 -0
  34. package/dist/cjs/langchain/runnables.cjs +19 -0
  35. package/dist/cjs/langchain/runnables.cjs.map +1 -0
  36. package/dist/cjs/langchain/tools.cjs +23 -0
  37. package/dist/cjs/langchain/tools.cjs.map +1 -0
  38. package/dist/cjs/langchain/utils/env.cjs +11 -0
  39. package/dist/cjs/langchain/utils/env.cjs.map +1 -0
  40. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +5 -1
  41. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  42. package/dist/cjs/llm/bedrock/cacheSupport.cjs +55 -0
  43. package/dist/cjs/llm/bedrock/cacheSupport.cjs.map +1 -0
  44. package/dist/cjs/llm/bedrock/index.cjs +61 -33
  45. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  46. package/dist/cjs/llm/openai/index.cjs +1 -4
  47. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  48. package/dist/cjs/llm/openai/utils/index.cjs +27 -10
  49. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  50. package/dist/cjs/main.cjs +178 -127
  51. package/dist/cjs/main.cjs.map +1 -1
  52. package/dist/cjs/memory/citations.cjs +4 -4
  53. package/dist/cjs/memory/citations.cjs.map +1 -1
  54. package/dist/cjs/memory/constants.cjs +17 -17
  55. package/dist/cjs/memory/constants.cjs.map +1 -1
  56. package/dist/cjs/memory/mmr.cjs +1 -1
  57. package/dist/cjs/memory/mmr.cjs.map +1 -1
  58. package/dist/cjs/memory/paths.cjs +1 -1
  59. package/dist/cjs/memory/paths.cjs.map +1 -1
  60. package/dist/cjs/memory/recallTracking.cjs +3 -3
  61. package/dist/cjs/memory/recallTracking.cjs.map +1 -1
  62. package/dist/cjs/memory/temporalDecay.cjs +2 -2
  63. package/dist/cjs/memory/temporalDecay.cjs.map +1 -1
  64. package/dist/cjs/messages/cache.cjs +89 -0
  65. package/dist/cjs/messages/cache.cjs.map +1 -1
  66. package/dist/cjs/messages/contextPruning.cjs +156 -0
  67. package/dist/cjs/messages/contextPruning.cjs.map +1 -0
  68. package/dist/cjs/messages/contextPruningSettings.cjs +53 -0
  69. package/dist/cjs/messages/contextPruningSettings.cjs.map +1 -0
  70. package/dist/cjs/messages/format.cjs +144 -20
  71. package/dist/cjs/messages/format.cjs.map +1 -1
  72. package/dist/cjs/messages/prune.cjs +505 -4
  73. package/dist/cjs/messages/prune.cjs.map +1 -1
  74. package/dist/cjs/run.cjs +141 -1
  75. package/dist/cjs/run.cjs.map +1 -1
  76. package/dist/cjs/tools/BashExecutor.cjs +235 -0
  77. package/dist/cjs/tools/BashExecutor.cjs.map +1 -0
  78. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +297 -0
  79. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -0
  80. package/dist/cjs/tools/CodeExecutor.cjs +45 -47
  81. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  82. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +16 -11
  83. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  84. package/dist/cjs/tools/ReadFile.cjs +44 -0
  85. package/dist/cjs/tools/ReadFile.cjs.map +1 -0
  86. package/dist/cjs/tools/SkillTool.cjs +51 -0
  87. package/dist/cjs/tools/SkillTool.cjs.map +1 -0
  88. package/dist/cjs/tools/SubagentTool.cjs +93 -0
  89. package/dist/cjs/tools/SubagentTool.cjs.map +1 -0
  90. package/dist/cjs/tools/ToolNode.cjs +450 -24
  91. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  92. package/dist/cjs/tools/memory/memoryAppendTool.cjs +1 -1
  93. package/dist/cjs/tools/memory/memoryAppendTool.cjs.map +1 -1
  94. package/dist/cjs/tools/memory/memoryGetTool.cjs +2 -2
  95. package/dist/cjs/tools/memory/memoryGetTool.cjs.map +1 -1
  96. package/dist/cjs/tools/memory/memorySearchTool.cjs +3 -3
  97. package/dist/cjs/tools/memory/memorySearchTool.cjs.map +1 -1
  98. package/dist/cjs/tools/memory/shared.cjs +1 -1
  99. package/dist/cjs/tools/memory/shared.cjs.map +1 -1
  100. package/dist/cjs/tools/search/search.cjs +11 -3
  101. package/dist/cjs/tools/search/search.cjs.map +1 -1
  102. package/dist/cjs/tools/search/tavily-scraper.cjs +189 -0
  103. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -0
  104. package/dist/cjs/tools/search/tavily-search.cjs +372 -0
  105. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -0
  106. package/dist/cjs/tools/search/tool.cjs +28 -4
  107. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  108. package/dist/cjs/tools/search/utils.cjs +10 -3
  109. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  110. package/dist/cjs/tools/skillCatalog.cjs +84 -0
  111. package/dist/cjs/tools/skillCatalog.cjs.map +1 -0
  112. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +512 -0
  113. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -0
  114. package/dist/cjs/tools/toolOutputReferences.cjs +670 -0
  115. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -0
  116. package/dist/cjs/types/agent-cache.cjs +54 -0
  117. package/dist/cjs/types/agent-cache.cjs.map +1 -0
  118. package/dist/cjs/types/graph.cjs.map +1 -1
  119. package/dist/cjs/utils/truncation.cjs +135 -0
  120. package/dist/cjs/utils/truncation.cjs.map +1 -0
  121. package/dist/esm/agents/AgentContext.mjs +274 -67
  122. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  123. package/dist/esm/common/enum.mjs +44 -12
  124. package/dist/esm/common/enum.mjs.map +1 -1
  125. package/dist/esm/graphs/Graph.mjs +182 -5
  126. package/dist/esm/graphs/Graph.mjs.map +1 -1
  127. package/dist/esm/graphs/MultiAgentGraph.mjs +155 -1170
  128. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  129. package/dist/esm/graphs/phases/memoryFlushPhase.mjs +1 -1
  130. package/dist/esm/graphs/phases/memoryFlushPhase.mjs.map +1 -1
  131. package/dist/esm/hooks/HookRegistry.mjs +160 -0
  132. package/dist/esm/hooks/HookRegistry.mjs.map +1 -0
  133. package/dist/esm/hooks/executeHooks.mjs +273 -0
  134. package/dist/esm/hooks/executeHooks.mjs.map +1 -0
  135. package/dist/esm/hooks/matchers.mjs +251 -0
  136. package/dist/esm/hooks/matchers.mjs.map +1 -0
  137. package/dist/esm/hooks/types.mjs +25 -0
  138. package/dist/esm/hooks/types.mjs.map +1 -0
  139. package/dist/esm/langchain/google-common.mjs +2 -0
  140. package/dist/esm/langchain/google-common.mjs.map +1 -0
  141. package/dist/esm/langchain/index.mjs +5 -0
  142. package/dist/esm/langchain/language_models/chat_models.mjs +2 -0
  143. package/dist/esm/langchain/language_models/chat_models.mjs.map +1 -0
  144. package/dist/esm/langchain/messages/tool.mjs +2 -0
  145. package/dist/esm/langchain/messages/tool.mjs.map +1 -0
  146. package/dist/esm/langchain/messages.mjs +2 -0
  147. package/dist/esm/langchain/messages.mjs.map +1 -0
  148. package/dist/esm/langchain/openai.mjs +2 -0
  149. package/dist/esm/langchain/openai.mjs.map +1 -0
  150. package/dist/esm/langchain/prompts.mjs +2 -0
  151. package/dist/esm/langchain/prompts.mjs.map +1 -0
  152. package/dist/esm/langchain/runnables.mjs +2 -0
  153. package/dist/esm/langchain/runnables.mjs.map +1 -0
  154. package/dist/esm/langchain/tools.mjs +2 -0
  155. package/dist/esm/langchain/tools.mjs.map +1 -0
  156. package/dist/esm/langchain/utils/env.mjs +2 -0
  157. package/dist/esm/langchain/utils/env.mjs.map +1 -0
  158. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +5 -1
  159. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  160. package/dist/esm/llm/bedrock/cacheSupport.mjs +52 -0
  161. package/dist/esm/llm/bedrock/cacheSupport.mjs.map +1 -0
  162. package/dist/esm/llm/bedrock/index.mjs +61 -34
  163. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  164. package/dist/esm/llm/openai/index.mjs +1 -4
  165. package/dist/esm/llm/openai/index.mjs.map +1 -1
  166. package/dist/esm/llm/openai/utils/index.mjs +27 -10
  167. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  168. package/dist/esm/main.mjs +21 -27
  169. package/dist/esm/main.mjs.map +1 -1
  170. package/dist/esm/memory/citations.mjs +4 -4
  171. package/dist/esm/memory/citations.mjs.map +1 -1
  172. package/dist/esm/memory/constants.mjs +17 -17
  173. package/dist/esm/memory/constants.mjs.map +1 -1
  174. package/dist/esm/memory/mmr.mjs +1 -1
  175. package/dist/esm/memory/mmr.mjs.map +1 -1
  176. package/dist/esm/memory/paths.mjs +1 -1
  177. package/dist/esm/memory/paths.mjs.map +1 -1
  178. package/dist/esm/memory/recallTracking.mjs +3 -3
  179. package/dist/esm/memory/recallTracking.mjs.map +1 -1
  180. package/dist/esm/memory/temporalDecay.mjs +2 -2
  181. package/dist/esm/memory/temporalDecay.mjs.map +1 -1
  182. package/dist/esm/messages/cache.mjs +89 -0
  183. package/dist/esm/messages/cache.mjs.map +1 -1
  184. package/dist/esm/messages/contextPruning.mjs +154 -0
  185. package/dist/esm/messages/contextPruning.mjs.map +1 -0
  186. package/dist/esm/messages/contextPruningSettings.mjs +50 -0
  187. package/dist/esm/messages/contextPruningSettings.mjs.map +1 -0
  188. package/dist/esm/messages/format.mjs +136 -12
  189. package/dist/esm/messages/format.mjs.map +1 -1
  190. package/dist/esm/messages/prune.mjs +504 -7
  191. package/dist/esm/messages/prune.mjs.map +1 -1
  192. package/dist/esm/run.mjs +141 -1
  193. package/dist/esm/run.mjs.map +1 -1
  194. package/dist/esm/tools/BashExecutor.mjs +227 -0
  195. package/dist/esm/tools/BashExecutor.mjs.map +1 -0
  196. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +288 -0
  197. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -0
  198. package/dist/esm/tools/CodeExecutor.mjs +45 -48
  199. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  200. package/dist/esm/tools/ProgrammaticToolCalling.mjs +17 -12
  201. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  202. package/dist/esm/tools/ReadFile.mjs +39 -0
  203. package/dist/esm/tools/ReadFile.mjs.map +1 -0
  204. package/dist/esm/tools/SkillTool.mjs +46 -0
  205. package/dist/esm/tools/SkillTool.mjs.map +1 -0
  206. package/dist/esm/tools/SubagentTool.mjs +86 -0
  207. package/dist/esm/tools/SubagentTool.mjs.map +1 -0
  208. package/dist/esm/tools/ToolNode.mjs +452 -26
  209. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  210. package/dist/esm/tools/memory/memoryAppendTool.mjs +1 -1
  211. package/dist/esm/tools/memory/memoryAppendTool.mjs.map +1 -1
  212. package/dist/esm/tools/memory/memoryGetTool.mjs +2 -2
  213. package/dist/esm/tools/memory/memoryGetTool.mjs.map +1 -1
  214. package/dist/esm/tools/memory/memorySearchTool.mjs +3 -3
  215. package/dist/esm/tools/memory/memorySearchTool.mjs.map +1 -1
  216. package/dist/esm/tools/memory/shared.mjs +1 -1
  217. package/dist/esm/tools/memory/shared.mjs.map +1 -1
  218. package/dist/esm/tools/search/search.mjs +11 -3
  219. package/dist/esm/tools/search/search.mjs.map +1 -1
  220. package/dist/esm/tools/search/tavily-scraper.mjs +186 -0
  221. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -0
  222. package/dist/esm/tools/search/tavily-search.mjs +370 -0
  223. package/dist/esm/tools/search/tavily-search.mjs.map +1 -0
  224. package/dist/esm/tools/search/tool.mjs +28 -4
  225. package/dist/esm/tools/search/tool.mjs.map +1 -1
  226. package/dist/esm/tools/search/utils.mjs +10 -3
  227. package/dist/esm/tools/search/utils.mjs.map +1 -1
  228. package/dist/esm/tools/skillCatalog.mjs +82 -0
  229. package/dist/esm/tools/skillCatalog.mjs.map +1 -0
  230. package/dist/esm/tools/subagent/SubagentExecutor.mjs +506 -0
  231. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -0
  232. package/dist/esm/tools/toolOutputReferences.mjs +662 -0
  233. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -0
  234. package/dist/esm/types/agent-cache.mjs +52 -0
  235. package/dist/esm/types/agent-cache.mjs.map +1 -0
  236. package/dist/esm/types/graph.mjs.map +1 -1
  237. package/dist/esm/utils/truncation.mjs +128 -0
  238. package/dist/esm/utils/truncation.mjs.map +1 -0
  239. package/dist/types/agents/AgentContext.d.ts +101 -8
  240. package/dist/types/common/enum.d.ts +39 -12
  241. package/dist/types/common/index.d.ts +0 -1
  242. package/dist/types/graphs/Graph.d.ts +43 -0
  243. package/dist/types/graphs/MultiAgentGraph.d.ts +26 -150
  244. package/dist/types/graphs/index.d.ts +0 -1
  245. package/dist/types/graphs/phases/memoryFlushPhase.d.ts +2 -2
  246. package/dist/types/hooks/HookRegistry.d.ts +56 -0
  247. package/dist/types/hooks/executeHooks.d.ts +79 -0
  248. package/dist/types/hooks/index.d.ts +6 -0
  249. package/dist/types/hooks/matchers.d.ts +95 -0
  250. package/dist/types/hooks/types.d.ts +320 -0
  251. package/dist/types/index.d.ts +9 -9
  252. package/dist/types/langchain/google-common.d.ts +1 -0
  253. package/dist/types/langchain/index.d.ts +8 -0
  254. package/dist/types/langchain/language_models/chat_models.d.ts +1 -0
  255. package/dist/types/langchain/messages/tool.d.ts +1 -0
  256. package/dist/types/langchain/messages.d.ts +2 -0
  257. package/dist/types/langchain/openai.d.ts +1 -0
  258. package/dist/types/langchain/prompts.d.ts +1 -0
  259. package/dist/types/langchain/runnables.d.ts +2 -0
  260. package/dist/types/langchain/tools.d.ts +2 -0
  261. package/dist/types/langchain/utils/env.d.ts +1 -0
  262. package/dist/types/llm/bedrock/cacheSupport.d.ts +35 -0
  263. package/dist/types/llm/bedrock/index.d.ts +54 -1
  264. package/dist/types/llm/openai/index.d.ts +1 -1
  265. package/dist/types/memory/citations.d.ts +4 -4
  266. package/dist/types/memory/constants.d.ts +17 -17
  267. package/dist/types/memory/mmr.d.ts +3 -3
  268. package/dist/types/memory/paths.d.ts +1 -1
  269. package/dist/types/memory/temporalDecay.d.ts +2 -2
  270. package/dist/types/memory/types.d.ts +3 -3
  271. package/dist/types/messages/contextPruning.d.ts +42 -0
  272. package/dist/types/messages/contextPruningSettings.d.ts +44 -0
  273. package/dist/types/messages/format.d.ts +9 -1
  274. package/dist/types/messages/index.d.ts +2 -0
  275. package/dist/types/messages/prune.d.ts +91 -1
  276. package/dist/types/run.d.ts +2 -0
  277. package/dist/types/tools/BashExecutor.d.ts +76 -0
  278. package/dist/types/tools/BashProgrammaticToolCalling.d.ts +72 -0
  279. package/dist/types/tools/CodeExecutor.d.ts +8 -26
  280. package/dist/types/tools/ReadFile.d.ts +28 -0
  281. package/dist/types/tools/SkillTool.d.ts +40 -0
  282. package/dist/types/tools/SubagentTool.d.ts +36 -0
  283. package/dist/types/tools/ToolNode.d.ts +77 -5
  284. package/dist/types/tools/memory/shared.d.ts +1 -1
  285. package/dist/types/tools/search/tavily-scraper.d.ts +19 -0
  286. package/dist/types/tools/search/tavily-search.d.ts +4 -0
  287. package/dist/types/tools/search/types.d.ts +99 -5
  288. package/dist/types/tools/search/utils.d.ts +2 -2
  289. package/dist/types/tools/skillCatalog.d.ts +19 -0
  290. package/dist/types/tools/subagent/SubagentExecutor.d.ts +137 -0
  291. package/dist/types/tools/subagent/index.d.ts +2 -0
  292. package/dist/types/tools/subagent/types.d.ts +84 -0
  293. package/dist/types/tools/toolOutputReferences.d.ts +236 -0
  294. package/dist/types/types/agent-cache.d.ts +71 -0
  295. package/dist/types/types/graph.d.ts +163 -22
  296. package/dist/types/types/index.d.ts +3 -0
  297. package/dist/types/types/messages.d.ts +26 -0
  298. package/dist/types/types/run.d.ts +22 -0
  299. package/dist/types/types/skill.d.ts +9 -0
  300. package/dist/types/types/tools.d.ts +111 -0
  301. package/dist/types/utils/index.d.ts +1 -3
  302. package/dist/types/utils/truncation.d.ts +70 -0
  303. package/package.json +57 -17
  304. package/src/agents/AgentContext.ts +321 -78
  305. package/src/agents/__tests__/AgentContext.cacheTtl.live.test.ts +259 -0
  306. package/src/agents/__tests__/AgentContext.crossAgentTier1.live.test.ts +266 -0
  307. package/src/agents/__tests__/AgentContext.crossUserCache.live.test.ts +342 -0
  308. package/src/agents/__tests__/AgentContext.test.ts +632 -0
  309. package/src/common/__tests__/enum.test.ts +7 -17
  310. package/src/common/enum.ts +43 -12
  311. package/src/common/index.ts +0 -1
  312. package/src/graphs/Graph.ts +222 -2
  313. package/src/graphs/MultiAgentGraph.ts +154 -1466
  314. package/src/graphs/__tests__/MultiAgentGraph.test.ts +91 -0
  315. package/src/graphs/gapFeatures.test.ts +1 -1
  316. package/src/graphs/index.ts +0 -1
  317. package/src/graphs/phases/__tests__/memoryFlushPhase.test.ts +1 -1
  318. package/src/graphs/phases/memoryFlushPhase.ts +2 -2
  319. package/src/hooks/HookRegistry.ts +208 -0
  320. package/src/hooks/__tests__/HookRegistry.test.ts +190 -0
  321. package/src/hooks/__tests__/compactHooks.test.ts +214 -0
  322. package/src/hooks/__tests__/executeHooks.test.ts +1013 -0
  323. package/src/hooks/__tests__/integration.test.ts +337 -0
  324. package/src/hooks/__tests__/matchers.test.ts +238 -0
  325. package/src/hooks/__tests__/toolHooks.test.ts +665 -0
  326. package/src/hooks/executeHooks.ts +375 -0
  327. package/src/hooks/index.ts +57 -0
  328. package/src/hooks/matchers.ts +280 -0
  329. package/src/hooks/types.ts +404 -0
  330. package/src/index.ts +15 -24
  331. package/src/langchain/google-common.ts +1 -0
  332. package/src/langchain/index.ts +8 -0
  333. package/src/langchain/language_models/chat_models.ts +1 -0
  334. package/src/langchain/messages/tool.ts +5 -0
  335. package/src/langchain/messages.ts +21 -0
  336. package/src/langchain/openai.ts +1 -0
  337. package/src/langchain/prompts.ts +1 -0
  338. package/src/langchain/runnables.ts +7 -0
  339. package/src/langchain/tools.ts +8 -0
  340. package/src/langchain/utils/env.ts +1 -0
  341. package/src/llm/anthropic/utils/message_inputs.ts +10 -1
  342. package/src/llm/anthropic/utils/server-tool-inputs.test.ts +436 -0
  343. package/src/llm/bedrock/__tests__/bedrock-caching.test.ts +166 -18
  344. package/src/llm/bedrock/cacheSupport.test.ts +99 -0
  345. package/src/llm/bedrock/cacheSupport.ts +53 -0
  346. package/src/llm/bedrock/index.ts +116 -41
  347. package/src/llm/openai/index.ts +2 -2
  348. package/src/llm/openai/utils/index.ts +31 -14
  349. package/src/memory/citations.ts +4 -4
  350. package/src/memory/constants.ts +17 -17
  351. package/src/memory/mmr.ts +3 -3
  352. package/src/memory/paths.ts +1 -1
  353. package/src/memory/recallTracking.ts +3 -3
  354. package/src/memory/temporalDecay.ts +2 -2
  355. package/src/memory/types.ts +3 -3
  356. package/src/messages/__tests__/contextPruning.test.ts +228 -0
  357. package/src/messages/cache.test.ts +62 -24
  358. package/src/messages/cache.ts +112 -0
  359. package/src/messages/contextPruning.ts +191 -0
  360. package/src/messages/contextPruningSettings.ts +90 -0
  361. package/src/messages/ensureThinkingBlock.test.ts +1 -1
  362. package/src/messages/format.ts +164 -12
  363. package/src/messages/formatAgentMessages.skills.test.ts +413 -0
  364. package/src/messages/formatAgentMessages.test.ts +1 -1
  365. package/src/messages/index.ts +2 -0
  366. package/src/messages/prune.ts +661 -4
  367. package/src/run.ts +155 -1
  368. package/src/scripts/multi-agent-chain.ts +2 -2
  369. package/src/scripts/multi-agent-document-review-chain.ts +2 -2
  370. package/src/scripts/multi-agent-hybrid-flow.ts +4 -4
  371. package/src/scripts/multi-agent-parallel.ts +3 -3
  372. package/src/scripts/multi-agent-sequence.ts +3 -3
  373. package/src/scripts/multi-agent-subagent.ts +246 -0
  374. package/src/scripts/multi-agent-supervisor.ts +5 -5
  375. package/src/scripts/poc-multi-agent-comprehensive.ts +8 -8
  376. package/src/scripts/sequential-full-metadata-test.ts +2 -2
  377. package/src/scripts/subagent-event-driven-debug.ts +190 -0
  378. package/src/scripts/subagent-tools-debug.ts +160 -0
  379. package/src/scripts/test-custom-prompt-key.ts +3 -3
  380. package/src/scripts/test-handoff-input.ts +1 -1
  381. package/src/scripts/test-handoff-steering.ts +3 -3
  382. package/src/scripts/test-multi-agent-list-handoff.ts +1 -1
  383. package/src/scripts/test-parallel-agent-labeling.ts +3 -3
  384. package/src/scripts/test-parallel-handoffs.ts +2 -2
  385. package/src/scripts/test-thinking-handoff-bedrock.ts +1 -1
  386. package/src/scripts/test-thinking-handoff.ts +1 -1
  387. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +1 -1
  388. package/src/scripts/test-tool-before-handoff-role-order.ts +1 -1
  389. package/src/scripts/test-tools-before-handoff.ts +1 -1
  390. package/src/specs/agent-handoffs.test.ts +26 -483
  391. package/src/specs/anthropic.simple.test.ts +61 -0
  392. package/src/specs/multi-agent-summarization.test.ts +396 -0
  393. package/src/specs/prune.orphans.test.ts +248 -0
  394. package/src/specs/prune.test.ts +104 -16
  395. package/src/specs/thinking-handoff.test.ts +19 -19
  396. package/src/tools/BashExecutor.ts +281 -0
  397. package/src/tools/BashProgrammaticToolCalling.ts +397 -0
  398. package/src/tools/CodeExecutor.ts +63 -54
  399. package/src/tools/ProgrammaticToolCalling.ts +29 -14
  400. package/src/tools/ReadFile.ts +39 -0
  401. package/src/tools/SkillTool.ts +46 -0
  402. package/src/tools/SubagentTool.ts +100 -0
  403. package/src/tools/ToolNode.ts +548 -26
  404. package/src/tools/__tests__/BashExecutor.test.ts +49 -0
  405. package/src/tools/__tests__/CodeExecutor.test.ts +37 -36
  406. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +60 -0
  407. package/src/tools/__tests__/ReadFile.test.ts +44 -0
  408. package/src/tools/__tests__/SkillTool.test.ts +442 -0
  409. package/src/tools/__tests__/SubagentExecutor.test.ts +1148 -0
  410. package/src/tools/__tests__/SubagentTool.test.ts +149 -0
  411. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +1438 -0
  412. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +479 -0
  413. package/src/tools/__tests__/skillCatalog.test.ts +161 -0
  414. package/src/tools/__tests__/subagentHooks.test.ts +210 -0
  415. package/src/tools/__tests__/toolOutputReferences.test.ts +415 -0
  416. package/src/tools/memory/memoryAppendTool.ts +1 -1
  417. package/src/tools/memory/memoryGetTool.ts +2 -2
  418. package/src/tools/memory/memorySearchTool.ts +3 -3
  419. package/src/tools/memory/shared.ts +1 -1
  420. package/src/tools/search/search.ts +12 -2
  421. package/src/tools/search/tavily-scraper.ts +235 -0
  422. package/src/tools/search/tavily-search.ts +424 -0
  423. package/src/tools/search/tavily.test.ts +965 -0
  424. package/src/tools/search/tool.ts +36 -2
  425. package/src/tools/search/types.ts +133 -8
  426. package/src/tools/search/utils.ts +13 -5
  427. package/src/tools/skillCatalog.ts +126 -0
  428. package/src/tools/subagent/SubagentExecutor.ts +676 -0
  429. package/src/tools/subagent/index.ts +13 -0
  430. package/src/tools/subagent/types.test.ts +70 -0
  431. package/src/tools/subagent/types.ts +115 -0
  432. package/src/tools/toolOutputReferences.ts +825 -0
  433. package/src/types/agent-cache.ts +74 -0
  434. package/src/types/graph.ts +172 -20
  435. package/src/types/index.ts +3 -0
  436. package/src/types/messages.ts +27 -0
  437. package/src/types/run.ts +22 -0
  438. package/src/types/skill.ts +11 -0
  439. package/src/types/tools.ts +118 -0
  440. package/src/utils/__tests__/truncation.test.ts +66 -0
  441. package/src/utils/index.ts +1 -3
  442. package/src/utils/truncation.ts +154 -0
  443. package/dist/cjs/common/spawnPath.cjs +0 -104
  444. package/dist/cjs/common/spawnPath.cjs.map +0 -1
  445. package/dist/cjs/content/ArtifactStore.cjs +0 -579
  446. package/dist/cjs/content/ArtifactStore.cjs.map +0 -1
  447. package/dist/cjs/content/ContentStore.cjs +0 -638
  448. package/dist/cjs/content/ContentStore.cjs.map +0 -1
  449. package/dist/cjs/content/contentAnalyzer.cjs +0 -91
  450. package/dist/cjs/content/contentAnalyzer.cjs.map +0 -1
  451. package/dist/cjs/content/index.cjs +0 -20
  452. package/dist/cjs/content/index.cjs.map +0 -1
  453. package/dist/cjs/content/mcpAutoCache.cjs +0 -115
  454. package/dist/cjs/content/mcpAutoCache.cjs.map +0 -1
  455. package/dist/cjs/graphs/HandoffRegistry.cjs +0 -143
  456. package/dist/cjs/graphs/HandoffRegistry.cjs.map +0 -1
  457. package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs +0 -288
  458. package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs.map +0 -1
  459. package/dist/cjs/providers/a2a/client.cjs +0 -92
  460. package/dist/cjs/providers/a2a/client.cjs.map +0 -1
  461. package/dist/cjs/providers/a2a/config.cjs +0 -38
  462. package/dist/cjs/providers/a2a/config.cjs.map +0 -1
  463. package/dist/cjs/providers/capabilityNaming.cjs +0 -43
  464. package/dist/cjs/providers/capabilityNaming.cjs.map +0 -1
  465. package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs +0 -244
  466. package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs.map +0 -1
  467. package/dist/cjs/providers/mcp/config.cjs +0 -42
  468. package/dist/cjs/providers/mcp/config.cjs.map +0 -1
  469. package/dist/cjs/providers/mcp/transport.cjs +0 -65
  470. package/dist/cjs/providers/mcp/transport.cjs.map +0 -1
  471. package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs +0 -128
  472. package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs.map +0 -1
  473. package/dist/cjs/providers/types.cjs +0 -51
  474. package/dist/cjs/providers/types.cjs.map +0 -1
  475. package/dist/cjs/tools/artifacts/schema.cjs +0 -86
  476. package/dist/cjs/tools/artifacts/schema.cjs.map +0 -1
  477. package/dist/cjs/tools/artifacts/tool.cjs +0 -219
  478. package/dist/cjs/tools/artifacts/tool.cjs.map +0 -1
  479. package/dist/cjs/tools/fileSearch/formatter.cjs +0 -93
  480. package/dist/cjs/tools/fileSearch/formatter.cjs.map +0 -1
  481. package/dist/cjs/tools/fileSearch/ragClient.cjs +0 -102
  482. package/dist/cjs/tools/fileSearch/ragClient.cjs.map +0 -1
  483. package/dist/cjs/tools/fileSearch/schema.cjs +0 -18
  484. package/dist/cjs/tools/fileSearch/schema.cjs.map +0 -1
  485. package/dist/cjs/tools/fileSearch/tool.cjs +0 -155
  486. package/dist/cjs/tools/fileSearch/tool.cjs.map +0 -1
  487. package/dist/cjs/tools/proxyTool.cjs +0 -102
  488. package/dist/cjs/tools/proxyTool.cjs.map +0 -1
  489. package/dist/cjs/utils/childAgentContext.cjs +0 -242
  490. package/dist/cjs/utils/childAgentContext.cjs.map +0 -1
  491. package/dist/cjs/utils/credentials.cjs +0 -142
  492. package/dist/cjs/utils/credentials.cjs.map +0 -1
  493. package/dist/cjs/utils/httpClient.cjs +0 -74
  494. package/dist/cjs/utils/httpClient.cjs.map +0 -1
  495. package/dist/cjs/utils/toolManifest.cjs +0 -100
  496. package/dist/cjs/utils/toolManifest.cjs.map +0 -1
  497. package/dist/esm/common/spawnPath.mjs +0 -95
  498. package/dist/esm/common/spawnPath.mjs.map +0 -1
  499. package/dist/esm/content/ArtifactStore.mjs +0 -576
  500. package/dist/esm/content/ArtifactStore.mjs.map +0 -1
  501. package/dist/esm/content/ContentStore.mjs +0 -635
  502. package/dist/esm/content/ContentStore.mjs.map +0 -1
  503. package/dist/esm/content/contentAnalyzer.mjs +0 -87
  504. package/dist/esm/content/contentAnalyzer.mjs.map +0 -1
  505. package/dist/esm/content/index.mjs +0 -5
  506. package/dist/esm/content/mcpAutoCache.mjs +0 -111
  507. package/dist/esm/content/mcpAutoCache.mjs.map +0 -1
  508. package/dist/esm/graphs/HandoffRegistry.mjs +0 -141
  509. package/dist/esm/graphs/HandoffRegistry.mjs.map +0 -1
  510. package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs +0 -281
  511. package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs.map +0 -1
  512. package/dist/esm/providers/a2a/client.mjs +0 -88
  513. package/dist/esm/providers/a2a/client.mjs.map +0 -1
  514. package/dist/esm/providers/a2a/config.mjs +0 -35
  515. package/dist/esm/providers/a2a/config.mjs.map +0 -1
  516. package/dist/esm/providers/capabilityNaming.mjs +0 -39
  517. package/dist/esm/providers/capabilityNaming.mjs.map +0 -1
  518. package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs +0 -240
  519. package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs.map +0 -1
  520. package/dist/esm/providers/mcp/config.mjs +0 -39
  521. package/dist/esm/providers/mcp/config.mjs.map +0 -1
  522. package/dist/esm/providers/mcp/transport.mjs +0 -63
  523. package/dist/esm/providers/mcp/transport.mjs.map +0 -1
  524. package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs +0 -126
  525. package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs.map +0 -1
  526. package/dist/esm/providers/types.mjs +0 -51
  527. package/dist/esm/providers/types.mjs.map +0 -1
  528. package/dist/esm/tools/artifacts/schema.mjs +0 -79
  529. package/dist/esm/tools/artifacts/schema.mjs.map +0 -1
  530. package/dist/esm/tools/artifacts/tool.mjs +0 -213
  531. package/dist/esm/tools/artifacts/tool.mjs.map +0 -1
  532. package/dist/esm/tools/fileSearch/formatter.mjs +0 -90
  533. package/dist/esm/tools/fileSearch/formatter.mjs.map +0 -1
  534. package/dist/esm/tools/fileSearch/ragClient.mjs +0 -98
  535. package/dist/esm/tools/fileSearch/ragClient.mjs.map +0 -1
  536. package/dist/esm/tools/fileSearch/schema.mjs +0 -15
  537. package/dist/esm/tools/fileSearch/schema.mjs.map +0 -1
  538. package/dist/esm/tools/fileSearch/tool.mjs +0 -152
  539. package/dist/esm/tools/fileSearch/tool.mjs.map +0 -1
  540. package/dist/esm/tools/proxyTool.mjs +0 -100
  541. package/dist/esm/tools/proxyTool.mjs.map +0 -1
  542. package/dist/esm/utils/childAgentContext.mjs +0 -237
  543. package/dist/esm/utils/childAgentContext.mjs.map +0 -1
  544. package/dist/esm/utils/credentials.mjs +0 -135
  545. package/dist/esm/utils/credentials.mjs.map +0 -1
  546. package/dist/esm/utils/httpClient.mjs +0 -70
  547. package/dist/esm/utils/httpClient.mjs.map +0 -1
  548. package/dist/esm/utils/toolManifest.mjs +0 -96
  549. package/dist/esm/utils/toolManifest.mjs.map +0 -1
  550. package/dist/types/common/spawnPath.d.ts +0 -59
  551. package/dist/types/content/ArtifactStore.d.ts +0 -223
  552. package/dist/types/content/ContentStore.d.ts +0 -140
  553. package/dist/types/content/contentAnalyzer.d.ts +0 -38
  554. package/dist/types/content/index.d.ts +0 -24
  555. package/dist/types/content/mcpAutoCache.d.ts +0 -89
  556. package/dist/types/content/types.d.ts +0 -75
  557. package/dist/types/graphs/HandoffRegistry.d.ts +0 -97
  558. package/dist/types/providers/a2a/A2ACapabilityProvider.d.ts +0 -89
  559. package/dist/types/providers/a2a/client.d.ts +0 -47
  560. package/dist/types/providers/a2a/config.d.ts +0 -18
  561. package/dist/types/providers/a2a/index.d.ts +0 -6
  562. package/dist/types/providers/a2a/types.d.ts +0 -173
  563. package/dist/types/providers/capabilityNaming.d.ts +0 -25
  564. package/dist/types/providers/index.d.ts +0 -12
  565. package/dist/types/providers/mcp/MCPCapabilityProvider.d.ts +0 -54
  566. package/dist/types/providers/mcp/config.d.ts +0 -20
  567. package/dist/types/providers/mcp/index.d.ts +0 -5
  568. package/dist/types/providers/mcp/transport.d.ts +0 -18
  569. package/dist/types/providers/mcp/types.d.ts +0 -112
  570. package/dist/types/providers/tools-server/ToolsServerCapabilityProvider.d.ts +0 -59
  571. package/dist/types/providers/tools-server/index.d.ts +0 -1
  572. package/dist/types/providers/types.d.ts +0 -184
  573. package/dist/types/tools/artifacts/index.d.ts +0 -3
  574. package/dist/types/tools/artifacts/schema.d.ts +0 -63
  575. package/dist/types/tools/artifacts/tool.d.ts +0 -16
  576. package/dist/types/tools/artifacts/types.d.ts +0 -127
  577. package/dist/types/tools/fileSearch/formatter.d.ts +0 -25
  578. package/dist/types/tools/fileSearch/index.d.ts +0 -5
  579. package/dist/types/tools/fileSearch/ragClient.d.ts +0 -32
  580. package/dist/types/tools/fileSearch/schema.d.ts +0 -13
  581. package/dist/types/tools/fileSearch/tool.d.ts +0 -18
  582. package/dist/types/tools/fileSearch/types.d.ts +0 -139
  583. package/dist/types/tools/proxyTool.d.ts +0 -62
  584. package/dist/types/tools/search/test.d.ts +0 -1
  585. package/dist/types/utils/childAgentContext.d.ts +0 -99
  586. package/dist/types/utils/credentials.d.ts +0 -77
  587. package/dist/types/utils/httpClient.d.ts +0 -46
  588. package/dist/types/utils/toolManifest.d.ts +0 -49
  589. package/src/common/__tests__/spawnPath.test.ts +0 -110
  590. package/src/common/spawnPath.ts +0 -101
  591. package/src/content/ArtifactStore.ts +0 -782
  592. package/src/content/ContentStore.ts +0 -753
  593. package/src/content/contentAnalyzer.ts +0 -105
  594. package/src/content/index.ts +0 -51
  595. package/src/content/mcpAutoCache.ts +0 -185
  596. package/src/content/types.ts +0 -82
  597. package/src/graphs/HandoffRegistry.ts +0 -199
  598. package/src/graphs/__tests__/HandoffRegistry.test.ts +0 -410
  599. package/src/graphs/__tests__/multi-agent-delegate.test.ts +0 -458
  600. package/src/graphs/__tests__/multi-agent-edges.test.ts +0 -276
  601. package/src/graphs/__tests__/multi-agent-nested-subgraph.test.ts +0 -221
  602. package/src/graphs/handoffValidation.test.ts +0 -353
  603. package/src/providers/__tests__/ToolsServerCapabilityProvider.integration.spec.ts +0 -79
  604. package/src/providers/__tests__/ToolsServerCapabilityProvider.test.ts +0 -271
  605. package/src/providers/__tests__/types.test.ts +0 -64
  606. package/src/providers/a2a/A2ACapabilityProvider.ts +0 -384
  607. package/src/providers/a2a/__tests__/A2ACapabilityProvider.integration.spec.ts +0 -345
  608. package/src/providers/a2a/__tests__/A2ACapabilityProvider.test.ts +0 -460
  609. package/src/providers/a2a/client.ts +0 -115
  610. package/src/providers/a2a/config.ts +0 -40
  611. package/src/providers/a2a/index.ts +0 -29
  612. package/src/providers/a2a/types.ts +0 -191
  613. package/src/providers/capabilityNaming.ts +0 -42
  614. package/src/providers/index.ts +0 -68
  615. package/src/providers/mcp/MCPCapabilityProvider.ts +0 -345
  616. package/src/providers/mcp/__tests__/MCPCapabilityProvider.integration.spec.ts +0 -386
  617. package/src/providers/mcp/__tests__/MCPCapabilityProvider.test.ts +0 -371
  618. package/src/providers/mcp/config.ts +0 -45
  619. package/src/providers/mcp/index.ts +0 -21
  620. package/src/providers/mcp/transport.ts +0 -76
  621. package/src/providers/mcp/types.ts +0 -139
  622. package/src/providers/tools-server/ToolsServerCapabilityProvider.ts +0 -249
  623. package/src/providers/tools-server/index.ts +0 -1
  624. package/src/providers/types.ts +0 -204
  625. package/src/scripts/test-bedrock-handoff-autonomous.ts +0 -267
  626. package/src/scripts/test-handoff-preamble.ts +0 -278
  627. package/src/specs/agent-handoffs-bedrock.integration.test.ts +0 -415
  628. package/src/tools/artifacts/__tests__/tool.test.ts +0 -259
  629. package/src/tools/artifacts/index.ts +0 -33
  630. package/src/tools/artifacts/schema.ts +0 -99
  631. package/src/tools/artifacts/tool.ts +0 -289
  632. package/src/tools/artifacts/types.ts +0 -162
  633. package/src/tools/fileSearch/__tests__/tool.test.ts +0 -261
  634. package/src/tools/fileSearch/formatter.ts +0 -129
  635. package/src/tools/fileSearch/index.ts +0 -23
  636. package/src/tools/fileSearch/ragClient.ts +0 -137
  637. package/src/tools/fileSearch/schema.ts +0 -19
  638. package/src/tools/fileSearch/tool.ts +0 -207
  639. package/src/tools/fileSearch/types.ts +0 -149
  640. package/src/tools/proxyTool.ts +0 -166
  641. package/src/tools/search/output.md +0 -2775
  642. package/src/tools/search/test.html +0 -884
  643. package/src/tools/search/test.md +0 -643
  644. package/src/tools/search/test.ts +0 -159
  645. package/src/utils/__tests__/childAgentContext.test.ts +0 -217
  646. package/src/utils/__tests__/credentials.test.ts +0 -130
  647. package/src/utils/__tests__/httpClient.test.ts +0 -75
  648. package/src/utils/__tests__/toolManifest.test.ts +0 -116
  649. package/src/utils/childAgentContext.ts +0 -259
  650. package/src/utils/credentials.ts +0 -157
  651. package/src/utils/httpClient.ts +0 -92
  652. package/src/utils/toolManifest.ts +0 -109
  653. /package/dist/esm/{content → langchain}/index.mjs.map +0 -0
@@ -0,0 +1,210 @@
1
+ import { HumanMessage } from '@langchain/core/messages';
2
+ import { FakeListChatModel } from '@langchain/core/utils/testing';
3
+ import type { ToolCall } from '@langchain/core/messages/tool';
4
+ import type * as t from '@/types';
5
+ import type {
6
+ HookCallback,
7
+ SubagentStartHookInput,
8
+ SubagentStartHookOutput,
9
+ SubagentStopHookInput,
10
+ SubagentStopHookOutput,
11
+ } from '@/hooks/types';
12
+ import { HookRegistry } from '@/hooks/HookRegistry';
13
+ import { Run } from '@/run';
14
+ import { Constants, GraphEvents, Providers } from '@/common';
15
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
16
+ import * as providers from '@/llm/providers';
17
+
18
+ const CHILD_RESPONSE = 'Hook test child response.';
19
+
20
+ const callerConfig = {
21
+ configurable: { thread_id: 'hook-test-thread' },
22
+ streamMode: 'values' as const,
23
+ version: 'v2' as const,
24
+ };
25
+
26
+ const originalGetChatModelClass = providers.getChatModelClass;
27
+
28
+ function makeSubagentToolCall(): ToolCall {
29
+ return {
30
+ name: Constants.SUBAGENT,
31
+ args: {
32
+ description: 'Test task for hook verification',
33
+ subagent_type: 'researcher',
34
+ },
35
+ id: `call_sub_${Date.now()}`,
36
+ type: 'tool_call',
37
+ };
38
+ }
39
+
40
+ function createParentAgent(): t.AgentInputs {
41
+ return {
42
+ agentId: 'hook-parent',
43
+ provider: Providers.OPENAI,
44
+ clientOptions: { modelName: 'gpt-4o-mini', apiKey: 'test-key' },
45
+ instructions: 'Delegate research tasks to subagents.',
46
+ maxContextTokens: 8000,
47
+ subagentConfigs: [
48
+ {
49
+ type: 'researcher',
50
+ name: 'Researcher',
51
+ description: 'Researches topics',
52
+ agentInputs: {
53
+ agentId: 'researcher-child',
54
+ provider: Providers.OPENAI,
55
+ clientOptions: { modelName: 'gpt-4o-mini', apiKey: 'test-key' },
56
+ instructions: 'Answer concisely.',
57
+ maxContextTokens: 8000,
58
+ },
59
+ },
60
+ ],
61
+ };
62
+ }
63
+
64
+ async function createSubagentRun(
65
+ hooks: HookRegistry,
66
+ runId = `subagent-hook-${Date.now()}`
67
+ ): Promise<Run<t.IState>> {
68
+ return Run.create<t.IState>({
69
+ runId,
70
+ graphConfig: {
71
+ type: 'standard',
72
+ agents: [createParentAgent()],
73
+ },
74
+ returnContent: true,
75
+ skipCleanup: true,
76
+ customHandlers: {
77
+ [GraphEvents.TOOL_END]: new ToolEndHandler(),
78
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
79
+ },
80
+ hooks,
81
+ });
82
+ }
83
+
84
+ describe('Subagent hook integration (end-to-end via Run)', () => {
85
+ jest.setTimeout(15000);
86
+
87
+ let getChatModelClassSpy: jest.SpyInstance;
88
+
89
+ beforeEach(() => {
90
+ getChatModelClassSpy = jest
91
+ .spyOn(providers, 'getChatModelClass')
92
+ .mockImplementation(((provider: Providers) => {
93
+ if (provider === Providers.OPENAI) {
94
+ return class extends FakeListChatModel {
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ constructor(_options: any) {
97
+ super({ responses: [CHILD_RESPONSE] });
98
+ }
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ } as any;
101
+ }
102
+ return originalGetChatModelClass(provider);
103
+ }) as typeof providers.getChatModelClass);
104
+ });
105
+
106
+ afterEach(() => {
107
+ getChatModelClassSpy.mockRestore();
108
+ });
109
+
110
+ it('SubagentStart fires with correct payload through real Run pipeline', async () => {
111
+ const registry = new HookRegistry();
112
+ let captured: SubagentStartHookInput | undefined;
113
+
114
+ const hook: HookCallback<'SubagentStart'> = async (
115
+ input
116
+ ): Promise<SubagentStartHookOutput> => {
117
+ captured = input;
118
+ return {};
119
+ };
120
+ registry.register('SubagentStart', { hooks: [hook] });
121
+
122
+ const tc = makeSubagentToolCall();
123
+ const run = await createSubagentRun(registry);
124
+ run.Graph!.overrideTestModel(['Delegating...', 'Final answer.'], 5, [tc]);
125
+
126
+ await run.processStream(
127
+ { messages: [new HumanMessage('research something')] },
128
+ callerConfig
129
+ );
130
+
131
+ expect(captured).toBeDefined();
132
+ expect(captured!.hook_event_name).toBe('SubagentStart');
133
+ expect(captured!.agentType).toBe('researcher');
134
+ expect(captured!.parentAgentId).toBe('hook-parent');
135
+ expect(captured!.threadId).toBe('hook-test-thread');
136
+ expect(captured!.inputs).toHaveLength(1);
137
+ expect(captured!.inputs[0].content).toContain(
138
+ 'Test task for hook verification'
139
+ );
140
+ });
141
+
142
+ it('SubagentStop fires with messages from child execution', async () => {
143
+ const registry = new HookRegistry();
144
+ let captured: SubagentStopHookInput | undefined;
145
+
146
+ const hook: HookCallback<'SubagentStop'> = async (
147
+ input
148
+ ): Promise<SubagentStopHookOutput> => {
149
+ captured = input;
150
+ return {};
151
+ };
152
+ registry.register('SubagentStop', { hooks: [hook] });
153
+
154
+ const tc = makeSubagentToolCall();
155
+ const run = await createSubagentRun(registry);
156
+ run.Graph!.overrideTestModel(['Delegating...', 'Final answer.'], 5, [tc]);
157
+
158
+ await run.processStream(
159
+ { messages: [new HumanMessage('research something')] },
160
+ callerConfig
161
+ );
162
+
163
+ expect(captured).toBeDefined();
164
+ expect(captured!.hook_event_name).toBe('SubagentStop');
165
+ expect(captured!.agentType).toBe('researcher');
166
+ expect(captured!.threadId).toBe('hook-test-thread');
167
+ expect(captured!.messages.length).toBeGreaterThan(0);
168
+ });
169
+
170
+ it('SubagentStart deny blocks subagent execution and returns blocked message', async () => {
171
+ const registry = new HookRegistry();
172
+ const denyHook: HookCallback<
173
+ 'SubagentStart'
174
+ > = async (): Promise<SubagentStartHookOutput> => ({
175
+ decision: 'deny',
176
+ reason: 'policy violation',
177
+ });
178
+ registry.register('SubagentStart', {
179
+ pattern: '^researcher$',
180
+ hooks: [denyHook],
181
+ });
182
+
183
+ const tc = makeSubagentToolCall();
184
+ const run = await createSubagentRun(registry);
185
+ run.Graph!.overrideTestModel(
186
+ ['Delegating...', 'The subagent was blocked.'],
187
+ 5,
188
+ [tc]
189
+ );
190
+
191
+ await run.processStream(
192
+ { messages: [new HumanMessage('research something')] },
193
+ callerConfig
194
+ );
195
+
196
+ const runMessages = run.getRunMessages();
197
+ expect(runMessages).toBeDefined();
198
+
199
+ const toolMessages = runMessages!.filter(
200
+ (msg) =>
201
+ msg._getType() === 'tool' &&
202
+ 'name' in msg &&
203
+ msg.name === Constants.SUBAGENT
204
+ );
205
+ expect(toolMessages.length).toBe(1);
206
+ expect(String(toolMessages[0].content)).toContain(
207
+ 'Blocked: policy violation'
208
+ );
209
+ });
210
+ });
@@ -0,0 +1,415 @@
1
+ import { describe, it, expect } from '@jest/globals';
2
+ import {
3
+ ToolOutputReferenceRegistry,
4
+ annotateToolOutputWithReference,
5
+ buildReferenceKey,
6
+ buildReferencePrefix,
7
+ TOOL_OUTPUT_REF_KEY,
8
+ TOOL_OUTPUT_REF_PATTERN,
9
+ } from '../toolOutputReferences';
10
+
11
+ describe('ToolOutputReferenceRegistry', () => {
12
+ describe('buildReferenceKey', () => {
13
+ it('formats keys as tool<idx>turn<turn>', () => {
14
+ expect(buildReferenceKey(0, 0)).toBe('tool0turn0');
15
+ expect(buildReferenceKey(3, 7)).toBe('tool3turn7');
16
+ });
17
+ });
18
+
19
+ describe('set / get', () => {
20
+ it('stores and retrieves outputs by key', () => {
21
+ const reg = new ToolOutputReferenceRegistry();
22
+ reg.set('r', 'tool0turn0', 'hello world');
23
+ expect(reg.get('r', 'tool0turn0')).toBe('hello world');
24
+ expect(reg.size).toBe(1);
25
+ });
26
+
27
+ it('clips stored values to the per-output limit', () => {
28
+ const reg = new ToolOutputReferenceRegistry({ maxOutputSize: 5 });
29
+ reg.set('r', 'tool0turn0', 'abcdefghij');
30
+ expect(reg.get('r', 'tool0turn0')).toBe('abcde');
31
+ });
32
+
33
+ it('replaces existing entries under the same key without double-counting size', () => {
34
+ const reg = new ToolOutputReferenceRegistry({
35
+ maxOutputSize: 100,
36
+ maxTotalSize: 20,
37
+ });
38
+ reg.set('r', 'tool0turn0', 'hello');
39
+ reg.set('r', 'tool0turn0', 'world-longer');
40
+ expect(reg.get('r', 'tool0turn0')).toBe('world-longer');
41
+ expect(reg.size).toBe(1);
42
+ });
43
+ });
44
+
45
+ describe('clear / releaseRun', () => {
46
+ it('clear() drops every run bucket', () => {
47
+ const reg = new ToolOutputReferenceRegistry();
48
+ reg.set('run-A', 'tool0turn0', 'A');
49
+ reg.set('run-B', 'tool0turn0', 'B');
50
+ expect(reg.size).toBe(2);
51
+ reg.clear();
52
+ expect(reg.size).toBe(0);
53
+ expect(reg.get('run-A', 'tool0turn0')).toBeUndefined();
54
+ expect(reg.get('run-B', 'tool0turn0')).toBeUndefined();
55
+ });
56
+
57
+ it('releaseRun() drops only the named run', () => {
58
+ const reg = new ToolOutputReferenceRegistry();
59
+ reg.set('run-A', 'tool0turn0', 'A');
60
+ reg.set('run-B', 'tool0turn0', 'B');
61
+ reg.releaseRun('run-A');
62
+ expect(reg.get('run-A', 'tool0turn0')).toBeUndefined();
63
+ expect(reg.get('run-B', 'tool0turn0')).toBe('B');
64
+ });
65
+ });
66
+
67
+ describe('FIFO eviction', () => {
68
+ it('evicts oldest entries when the aggregate cap is exceeded', () => {
69
+ const reg = new ToolOutputReferenceRegistry({
70
+ maxOutputSize: 10,
71
+ maxTotalSize: 12,
72
+ });
73
+ reg.set('r', 'tool0turn0', '1234567'); // 7 chars
74
+ reg.set('r', 'tool1turn0', '89'); // 9 total
75
+ reg.set('r', 'tool2turn0', 'abc'); // 12 total — at limit
76
+ reg.set('r', 'tool3turn0', 'XY'); // 14 → must evict oldest
77
+ expect(reg.get('r', 'tool0turn0')).toBeUndefined();
78
+ expect(reg.get('r', 'tool1turn0')).toBe('89');
79
+ expect(reg.get('r', 'tool2turn0')).toBe('abc');
80
+ expect(reg.get('r', 'tool3turn0')).toBe('XY');
81
+ });
82
+
83
+ it('keeps evicting oldest entries until the aggregate fits', () => {
84
+ const reg = new ToolOutputReferenceRegistry({
85
+ maxOutputSize: 10,
86
+ maxTotalSize: 8,
87
+ });
88
+ reg.set('r', 'tool0turn0', 'aaa');
89
+ reg.set('r', 'tool1turn0', 'bbb');
90
+ reg.set('r', 'tool2turn0', 'ccccccc'); // total 3+3+7=13 > 8, evict aaa then bbb
91
+ expect(reg.get('r', 'tool0turn0')).toBeUndefined();
92
+ expect(reg.get('r', 'tool1turn0')).toBeUndefined();
93
+ expect(reg.get('r', 'tool2turn0')).toBe('ccccccc');
94
+ });
95
+
96
+ it('clamps the per-output cap to maxTotalSize so no entry exceeds the aggregate', () => {
97
+ const reg = new ToolOutputReferenceRegistry({
98
+ maxOutputSize: 1000,
99
+ maxTotalSize: 10,
100
+ });
101
+ reg.set('r', 'tool0turn0', 'x'.repeat(500));
102
+ const stored = reg.get('r', 'tool0turn0');
103
+ expect(stored).toBeDefined();
104
+ expect(stored!.length).toBeLessThanOrEqual(10);
105
+ });
106
+
107
+ it('clamps a caller-supplied maxTotalSize to the documented hard cap', () => {
108
+ // 50 MB requested; should be clamped to the 5 MB hard cap.
109
+ const reg = new ToolOutputReferenceRegistry({
110
+ maxTotalSize: 50_000_000,
111
+ });
112
+ // `totalLimit` getter exposes the effective post-clamp value.
113
+ expect(reg.totalLimit).toBeLessThanOrEqual(5_000_000);
114
+ // Per-output is also bound by the same effective total.
115
+ expect(reg.perOutputLimit).toBeLessThanOrEqual(5_000_000);
116
+ });
117
+
118
+ it('evicts the oldest run bucket when maxActiveRuns is exceeded', () => {
119
+ const reg = new ToolOutputReferenceRegistry({ maxActiveRuns: 2 });
120
+ reg.set('run-A', 'tool0turn0', 'A');
121
+ reg.set('run-B', 'tool0turn0', 'B');
122
+ reg.set('run-C', 'tool0turn0', 'C');
123
+ // run-A was the oldest insertion; LRU evicted it when run-C
124
+ // pushed the bucket count above the cap.
125
+ expect(reg.get('run-A', 'tool0turn0')).toBeUndefined();
126
+ expect(reg.get('run-B', 'tool0turn0')).toBe('B');
127
+ expect(reg.get('run-C', 'tool0turn0')).toBe('C');
128
+ });
129
+ });
130
+
131
+ describe('resolve', () => {
132
+ it('replaces placeholders in string args', () => {
133
+ const reg = new ToolOutputReferenceRegistry();
134
+ reg.set('r', 'tool0turn0', 'HELLO');
135
+ const { resolved, unresolved } = reg.resolve('r', 'echo {{tool0turn0}}');
136
+ expect(resolved).toBe('echo HELLO');
137
+ expect(unresolved).toEqual([]);
138
+ });
139
+
140
+ it('replaces placeholders in nested object args', () => {
141
+ const reg = new ToolOutputReferenceRegistry();
142
+ reg.set('r', 'tool0turn0', 'DATA');
143
+ const input = {
144
+ command: 'cat {{tool0turn0}}',
145
+ meta: { note: 'uses {{tool0turn0}} twice' },
146
+ };
147
+ const { resolved } = reg.resolve('r', input);
148
+ expect(resolved).toEqual({
149
+ command: 'cat DATA',
150
+ meta: { note: 'uses DATA twice' },
151
+ });
152
+ });
153
+
154
+ it('replaces placeholders inside array values', () => {
155
+ const reg = new ToolOutputReferenceRegistry();
156
+ reg.set('r', 'tool1turn2', '42');
157
+ const { resolved } = reg.resolve('r', {
158
+ args: ['--id', '{{tool1turn2}}', 'plain'],
159
+ });
160
+ expect(resolved).toEqual({ args: ['--id', '42', 'plain'] });
161
+ });
162
+
163
+ it('reports unresolved references and leaves the placeholder in place', () => {
164
+ const reg = new ToolOutputReferenceRegistry();
165
+ reg.set('r', 'tool0turn0', 'known');
166
+ const { resolved, unresolved } = reg.resolve(
167
+ 'r',
168
+ 'use {{tool0turn0}} and {{tool5turn9}}'
169
+ );
170
+ expect(resolved).toBe('use known and {{tool5turn9}}');
171
+ expect(unresolved).toEqual(['tool5turn9']);
172
+ });
173
+
174
+ it('deduplicates repeated unresolved keys', () => {
175
+ const reg = new ToolOutputReferenceRegistry();
176
+ const { unresolved } = reg.resolve(
177
+ 'r',
178
+ '{{tool7turn0}} and {{tool7turn0}} again'
179
+ );
180
+ expect(unresolved).toEqual(['tool7turn0']);
181
+ });
182
+
183
+ it('does not touch non-placeholder strings', () => {
184
+ const reg = new ToolOutputReferenceRegistry();
185
+ reg.set('r', 'tool0turn0', 'X');
186
+ const { resolved } = reg.resolve('r', 'nothing to see here');
187
+ expect(resolved).toBe('nothing to see here');
188
+ });
189
+
190
+ it('passes through primitive values untouched', () => {
191
+ const reg = new ToolOutputReferenceRegistry();
192
+ const { resolved } = reg.resolve('r', {
193
+ count: 3,
194
+ enabled: true,
195
+ note: null,
196
+ });
197
+ expect(resolved).toEqual({ count: 3, enabled: true, note: null });
198
+ });
199
+ });
200
+
201
+ describe('snapshot', () => {
202
+ it('resolves against the captured state and ignores later mutations', () => {
203
+ const reg = new ToolOutputReferenceRegistry();
204
+ reg.set('r', 'tool0turn0', 'OLD');
205
+ const view = reg.snapshot('r');
206
+ // Mutate after taking the snapshot.
207
+ reg.set('r', 'tool0turn0', 'NEW');
208
+ reg.set('r', 'tool1turn0', 'LATER');
209
+ // Snapshot still resolves to the captured value and treats
210
+ // post-snapshot additions as unresolved.
211
+ expect(view.resolve('echo {{tool0turn0}}').resolved).toBe('echo OLD');
212
+ const { resolved, unresolved } = view.resolve('see {{tool1turn0}}');
213
+ expect(resolved).toBe('see {{tool1turn0}}');
214
+ expect(unresolved).toEqual(['tool1turn0']);
215
+ });
216
+
217
+ it('returns an empty view for a runId with no bucket', () => {
218
+ const reg = new ToolOutputReferenceRegistry();
219
+ const view = reg.snapshot('never-touched');
220
+ const { resolved, unresolved } = view.resolve('see {{tool0turn0}}');
221
+ expect(resolved).toBe('see {{tool0turn0}}');
222
+ expect(unresolved).toEqual(['tool0turn0']);
223
+ });
224
+
225
+ it('returns an isolated view per snapshot call', () => {
226
+ const reg = new ToolOutputReferenceRegistry();
227
+ reg.set('r', 'tool0turn0', 'A');
228
+ const view1 = reg.snapshot('r');
229
+ reg.set('r', 'tool0turn0', 'B');
230
+ const view2 = reg.snapshot('r');
231
+ expect(view1.resolve('{{tool0turn0}}').resolved).toBe('A');
232
+ expect(view2.resolve('{{tool0turn0}}').resolved).toBe('B');
233
+ });
234
+ });
235
+
236
+ describe('annotateToolOutputWithReference', () => {
237
+ it('injects _ref into plain JSON objects', () => {
238
+ const content = '{"a":1,"b":"x"}';
239
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
240
+ const parsed = JSON.parse(annotated);
241
+ expect(parsed[TOOL_OUTPUT_REF_KEY]).toBe('tool0turn0');
242
+ expect(parsed.a).toBe(1);
243
+ expect(parsed.b).toBe('x');
244
+ });
245
+
246
+ it('preserves pretty-printed formatting when the original was pretty', () => {
247
+ const content = '{\n "a": 1\n}';
248
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
249
+ expect(annotated).toContain('\n "');
250
+ const parsed = JSON.parse(annotated);
251
+ expect(parsed[TOOL_OUTPUT_REF_KEY]).toBe('tool0turn0');
252
+ });
253
+
254
+ it('uses the [ref: …] prefix for JSON arrays', () => {
255
+ const content = '[1,2,3]';
256
+ const annotated = annotateToolOutputWithReference(content, 'tool1turn0');
257
+ expect(annotated).toBe(`${buildReferencePrefix('tool1turn0')}\n[1,2,3]`);
258
+ });
259
+
260
+ it('uses the [ref: …] prefix for JSON primitives', () => {
261
+ expect(annotateToolOutputWithReference('42', 'tool0turn0')).toBe(
262
+ '[ref: tool0turn0]\n42'
263
+ );
264
+ });
265
+
266
+ it('uses the [ref: …] prefix for plain strings', () => {
267
+ expect(annotateToolOutputWithReference('hello', 'tool0turn0')).toBe(
268
+ '[ref: tool0turn0]\nhello'
269
+ );
270
+ });
271
+
272
+ it('falls back to the prefix on JSON _ref collision', () => {
273
+ const content = '{"_ref":"other-value","data":1}';
274
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
275
+ expect(annotated.startsWith('[ref: tool0turn0]\n')).toBe(true);
276
+ });
277
+
278
+ it('injects when the existing _ref matches the target key', () => {
279
+ const content = '{"_ref":"tool0turn0","data":1}';
280
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
281
+ const parsed = JSON.parse(annotated);
282
+ expect(parsed._ref).toBe('tool0turn0');
283
+ expect(parsed.data).toBe(1);
284
+ });
285
+
286
+ it('overwrites an existing _ref:null with the injected key', () => {
287
+ const content = '{"_ref":null,"data":1}';
288
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
289
+ const parsed = JSON.parse(annotated);
290
+ expect(parsed._ref).toBe('tool0turn0');
291
+ expect(parsed.data).toBe(1);
292
+ });
293
+
294
+ it('places the injected _ref as the first key in the serialized JSON', () => {
295
+ const content = '{"a":1,"b":"x"}';
296
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
297
+ expect(annotated.indexOf('"_ref"')).toBe(1);
298
+ const annotatedFromNull = annotateToolOutputWithReference(
299
+ '{"_ref":null,"a":1}',
300
+ 'tool0turn0'
301
+ );
302
+ expect(annotatedFromNull.indexOf('"_ref"')).toBe(1);
303
+ });
304
+
305
+ it('falls back to the prefix when parsing fails', () => {
306
+ const content = '{ not actually json';
307
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
308
+ expect(annotated).toBe(`[ref: tool0turn0]\n${content}`);
309
+ });
310
+
311
+ it('carries unresolved refs as a JSON field on parseable objects', () => {
312
+ const content = '{"a":1}';
313
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0', [
314
+ 'tool9turn9',
315
+ 'tool7turn0',
316
+ ]);
317
+ const parsed = JSON.parse(annotated);
318
+ expect(parsed._ref).toBe('tool0turn0');
319
+ expect(parsed._unresolved_refs).toEqual(['tool9turn9', 'tool7turn0']);
320
+ expect(parsed.a).toBe(1);
321
+ });
322
+
323
+ it('appends unresolved refs as a trailer line on non-object content', () => {
324
+ const annotated = annotateToolOutputWithReference(
325
+ 'plain text',
326
+ 'tool0turn0',
327
+ ['tool9turn9']
328
+ );
329
+ expect(annotated).toBe(
330
+ '[ref: tool0turn0]\nplain text\n[unresolved refs: tool9turn9]'
331
+ );
332
+ });
333
+
334
+ it('supports unresolved-only annotation (no ref key)', () => {
335
+ const annotated = annotateToolOutputWithReference(
336
+ 'error text',
337
+ undefined,
338
+ ['tool9turn9']
339
+ );
340
+ expect(annotated).toBe('error text\n[unresolved refs: tool9turn9]');
341
+ });
342
+
343
+ it('keeps JSON parseable for unresolved-only annotation on object content', () => {
344
+ const annotated = annotateToolOutputWithReference(
345
+ '{"error":"bad"}',
346
+ undefined,
347
+ ['tool9turn9']
348
+ );
349
+ const parsed = JSON.parse(annotated);
350
+ expect(parsed._unresolved_refs).toEqual(['tool9turn9']);
351
+ expect(parsed.error).toBe('bad');
352
+ expect(parsed._ref).toBeUndefined();
353
+ });
354
+
355
+ it('returns content unchanged when there is nothing to annotate', () => {
356
+ expect(annotateToolOutputWithReference('plain', undefined, [])).toBe(
357
+ 'plain'
358
+ );
359
+ });
360
+
361
+ it('preserves an existing _unresolved_refs payload when only injecting a ref key', () => {
362
+ const content = '{"data":1,"_unresolved_refs":["user-supplied"]}';
363
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0');
364
+ const parsed = JSON.parse(annotated);
365
+ expect(parsed._ref).toBe('tool0turn0');
366
+ expect(parsed._unresolved_refs).toEqual(['user-supplied']);
367
+ expect(parsed.data).toBe(1);
368
+ });
369
+
370
+ it('preserves an existing _ref payload on the unresolved-only path', () => {
371
+ const content = '{"data":1,"_ref":"preserved-value"}';
372
+ const annotated = annotateToolOutputWithReference(content, undefined, [
373
+ 'tool9turn9',
374
+ ]);
375
+ const parsed = JSON.parse(annotated);
376
+ expect(parsed._ref).toBe('preserved-value');
377
+ expect(parsed._unresolved_refs).toEqual(['tool9turn9']);
378
+ expect(parsed.data).toBe(1);
379
+ });
380
+
381
+ it('falls back to the prefix when _unresolved_refs conflicts with a non-matching array', () => {
382
+ const content = '{"data":1,"_unresolved_refs":["legacy"]}';
383
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0', [
384
+ 'tool9turn9',
385
+ ]);
386
+ expect(annotated.startsWith('[ref: tool0turn0]\n')).toBe(true);
387
+ expect(annotated).toContain('[unresolved refs: tool9turn9]');
388
+ });
389
+
390
+ it('accepts a deep-equal existing _unresolved_refs array', () => {
391
+ const content = '{"data":1,"_unresolved_refs":["tool9turn9"]}';
392
+ const annotated = annotateToolOutputWithReference(content, 'tool0turn0', [
393
+ 'tool9turn9',
394
+ ]);
395
+ const parsed = JSON.parse(annotated);
396
+ expect(parsed._unresolved_refs).toEqual(['tool9turn9']);
397
+ expect(parsed._ref).toBe('tool0turn0');
398
+ });
399
+ });
400
+
401
+ describe('TOOL_OUTPUT_REF_PATTERN', () => {
402
+ it('matches braced tool<N>turn<M> tokens and captures the key', () => {
403
+ const match = '{{tool0turn0}}'.match(TOOL_OUTPUT_REF_PATTERN);
404
+ expect(match?.[1]).toBe('tool0turn0');
405
+ });
406
+
407
+ it('rejects bare tool<N>turn<M> tokens without braces', () => {
408
+ expect(TOOL_OUTPUT_REF_PATTERN.test('tool0turn0')).toBe(false);
409
+ });
410
+
411
+ it('is non-global so callers cannot trip on stale lastIndex', () => {
412
+ expect(TOOL_OUTPUT_REF_PATTERN.flags).not.toContain('g');
413
+ });
414
+ });
415
+ });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `memory_append` — the reflection-phase-only write tool.
3
3
  *
4
- * New (not present in upstream verbatim). Upstream enforces append-only via
4
+ * New (not present in verbatim). Reference implementations enforce append-only via
5
5
  * `wrapToolMemoryFlushAppendOnlyWrite`; we combine the tool and the phase
6
6
  * gate in one place because the agents library has a simpler graph state.
7
7
  *
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * `memory_get` — safe snippet read.
3
3
  *
4
- * Port of upstream `createMemoryGetTool` at
5
- * `upstream reference`.
4
+ * Port of `createMemoryGetTool` at
5
+ * `reference`.
6
6
  */
7
7
  import { tool } from '@langchain/core/tools';
8
8
  import {
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * `memory_search` — the mandatory-recall tool.
3
3
  *
4
- * Port of upstream `createMemorySearchTool` at
5
- * `upstream reference`. The tool description
6
- * is verbatim "Mandatory recall step..." from upstream — this is the load-
4
+ * Port of `createMemorySearchTool` at
5
+ * `reference`. The tool description
6
+ * is verbatim "Mandatory recall step..." from a reference implementation — this is the load-
7
7
  * bearing line that turns "the agent may recall" into "the agent will recall".
8
8
  */
9
9
  import { tool } from '@langchain/core/tools';
@@ -117,7 +117,7 @@ export function buildMemorySearchUnavailableResult(
117
117
 
118
118
  /**
119
119
  * Clamp a ranked result list to a total character budget.
120
- * Ported from upstream `tools.citations.ts::clampResultsByInjectedChars`.
120
+ * Ported from a reference implementation `tools.citations.ts::clampResultsByInjectedChars`.
121
121
  */
122
122
  export function clampResultsByInjectedChars<T extends { content: string }>(
123
123
  results: T[],