@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,248 @@
1
+ // Orphan tool message repair + sanitize coverage. Ported from the reference implementation's
2
+ // `prune.test.ts` "Tool Message Handling" + top-level `sanitizeOrphanToolBlocks`
3
+ // describes — kept in a dedicated file to keep the diff against illuma's
4
+ // existing prune.test.ts narrow.
5
+ import {
6
+ AIMessage,
7
+ BaseMessage,
8
+ ToolMessage,
9
+ HumanMessage,
10
+ SystemMessage,
11
+ } from '@langchain/core/messages';
12
+ import type * as t from '@/types';
13
+ import {
14
+ repairOrphanedToolMessages,
15
+ sanitizeOrphanToolBlocks,
16
+ } from '@/messages/prune';
17
+
18
+ const createTestTokenCounter = (): t.TokenCounter => {
19
+ return (message: BaseMessage): number => {
20
+ if (typeof message.content === 'string') {
21
+ return Math.max(1, Math.ceil(message.content.length / 4));
22
+ }
23
+ if (Array.isArray(message.content)) {
24
+ let total = 0;
25
+ for (const block of message.content) {
26
+ if (typeof block === 'object' && block !== null) {
27
+ total += Math.ceil(JSON.stringify(block).length / 4);
28
+ }
29
+ }
30
+ return Math.max(1, total);
31
+ }
32
+ return 1;
33
+ };
34
+ };
35
+
36
+ describe('repairOrphanedToolMessages', () => {
37
+ it('drops orphan ToolMessages that no longer have a matching AIMessage tool_call', () => {
38
+ const tokenCounter = createTestTokenCounter();
39
+ const context = [
40
+ new SystemMessage('System'),
41
+ new ToolMessage({ content: 'Orphan result', tool_call_id: 'gone' }),
42
+ new HumanMessage('User question'),
43
+ new AIMessage({
44
+ content: 'thinking',
45
+ tool_calls: [{ name: 't1', args: {}, id: 'tool1' }],
46
+ }),
47
+ new ToolMessage({ content: 'Tool result 1', tool_call_id: 'tool1' }),
48
+ ];
49
+
50
+ const result = repairOrphanedToolMessages({
51
+ context,
52
+ allMessages: context,
53
+ tokenCounter,
54
+ indexTokenCountMap: {},
55
+ });
56
+
57
+ expect(result.droppedOrphanCount).toBe(1);
58
+ expect(result.context).toHaveLength(4);
59
+ expect(
60
+ result.context.some(
61
+ (m) =>
62
+ m.getType() === 'tool' && (m as ToolMessage).tool_call_id === 'gone'
63
+ )
64
+ ).toBe(false);
65
+ expect(result.droppedMessages).toHaveLength(1);
66
+ });
67
+
68
+ it('strips orphan tool_use content blocks from AIMessages whose ToolMessage was dropped', () => {
69
+ const tokenCounter = createTestTokenCounter();
70
+ const context = [
71
+ new HumanMessage('Hi'),
72
+ new AIMessage({
73
+ content: [
74
+ { type: 'text', text: 'Calling tool…' },
75
+ { type: 'tool_use', id: 'tool_orphan', name: 'foo', input: {} },
76
+ ],
77
+ tool_calls: [{ name: 'foo', args: {}, id: 'tool_orphan' }],
78
+ }),
79
+ // Note: NO matching ToolMessage for tool_orphan
80
+ ];
81
+
82
+ const result = repairOrphanedToolMessages({
83
+ context,
84
+ allMessages: context,
85
+ tokenCounter,
86
+ indexTokenCountMap: {},
87
+ });
88
+
89
+ // The AI message should still be in context, but with the tool_use block stripped
90
+ expect(result.context).toHaveLength(2);
91
+ const ai = result.context[1] as AIMessage;
92
+ expect(ai.tool_calls?.length ?? 0).toBe(0);
93
+ if (Array.isArray(ai.content)) {
94
+ const toolUseBlocks = ai.content.filter(
95
+ (b) =>
96
+ typeof b === 'object' &&
97
+ ((b as { type?: string }).type === 'tool_use' ||
98
+ (b as { type?: string }).type === 'tool_call')
99
+ );
100
+ expect(toolUseBlocks).toHaveLength(0);
101
+ }
102
+ });
103
+
104
+ it('drops the entire AIMessage when stripping leaves no content blocks', () => {
105
+ const tokenCounter = createTestTokenCounter();
106
+ const context = [
107
+ new HumanMessage('Question'),
108
+ new AIMessage({
109
+ content: [
110
+ { type: 'tool_use', id: 'orphan_only', name: 'foo', input: {} },
111
+ ],
112
+ tool_calls: [{ name: 'foo', args: {}, id: 'orphan_only' }],
113
+ }),
114
+ ];
115
+
116
+ const result = repairOrphanedToolMessages({
117
+ context,
118
+ allMessages: context,
119
+ tokenCounter,
120
+ indexTokenCountMap: {},
121
+ });
122
+
123
+ expect(result.context).toHaveLength(1);
124
+ expect(result.droppedOrphanCount).toBe(1);
125
+ expect(result.droppedMessages).toHaveLength(1);
126
+ });
127
+
128
+ it('preserves matched tool_call ↔ tool_result pairs intact', () => {
129
+ const tokenCounter = createTestTokenCounter();
130
+ const context = [
131
+ new HumanMessage('Question'),
132
+ new AIMessage({
133
+ content: 'thinking',
134
+ tool_calls: [{ name: 'foo', args: {}, id: 'paired' }],
135
+ }),
136
+ new ToolMessage({ content: 'result', tool_call_id: 'paired' }),
137
+ ];
138
+
139
+ const result = repairOrphanedToolMessages({
140
+ context,
141
+ allMessages: context,
142
+ tokenCounter,
143
+ indexTokenCountMap: {},
144
+ });
145
+
146
+ expect(result.context).toEqual(context);
147
+ expect(result.droppedOrphanCount).toBe(0);
148
+ });
149
+ });
150
+
151
+ describe('sanitizeOrphanToolBlocks', () => {
152
+ it('strips orphan tool_use blocks from AI messages with no matching ToolMessage', () => {
153
+ const messages: BaseMessage[] = [
154
+ new HumanMessage('Hello'),
155
+ new AIMessage({
156
+ content: [
157
+ { type: 'text', text: 'Let me check.' },
158
+ { type: 'tool_use', id: 'tu_orphan', name: 'search', input: {} },
159
+ ],
160
+ tool_calls: [{ name: 'search', args: {}, id: 'tu_orphan' }],
161
+ }),
162
+ // No ToolMessage with tool_call_id 'tu_orphan'
163
+ new HumanMessage('Follow-up'),
164
+ ];
165
+
166
+ const out = sanitizeOrphanToolBlocks(messages);
167
+ // The result depends on whether the stripped AI is at the end (popped by
168
+ // the trailing-stripped-AI rule). Here it is NOT trailing, so it stays.
169
+ expect(out).toHaveLength(3);
170
+ const ai = out[1] as AIMessage;
171
+ expect(ai.tool_calls?.length ?? 0).toBe(0);
172
+ if (Array.isArray(ai.content)) {
173
+ expect(
174
+ ai.content.some(
175
+ (b) =>
176
+ typeof b === 'object' &&
177
+ (b as { type?: string }).type === 'tool_use'
178
+ )
179
+ ).toBe(false);
180
+ }
181
+ });
182
+
183
+ it('drops orphan ToolMessages whose matching tool_use is missing', () => {
184
+ const messages: BaseMessage[] = [
185
+ new HumanMessage('Hi'),
186
+ new AIMessage('Plain response'),
187
+ new ToolMessage({ content: 'orphaned', tool_call_id: 'gone' }),
188
+ ];
189
+
190
+ const out = sanitizeOrphanToolBlocks(messages);
191
+ expect(out).toHaveLength(2);
192
+ expect(out.find((m) => m.getType() === 'tool')).toBeUndefined();
193
+ });
194
+
195
+ it('returns the original array unchanged when every pair is matched (fast path)', () => {
196
+ const messages: BaseMessage[] = [
197
+ new HumanMessage('Hi'),
198
+ new AIMessage({
199
+ content: 'thinking',
200
+ tool_calls: [{ name: 't1', args: {}, id: 'tool1' }],
201
+ }),
202
+ new ToolMessage({ content: 'r1', tool_call_id: 'tool1' }),
203
+ ];
204
+ const out = sanitizeOrphanToolBlocks(messages);
205
+ expect(out).toBe(messages);
206
+ });
207
+
208
+ it('pops trailing AI messages whose tool_use blocks were all stripped', () => {
209
+ const messages: BaseMessage[] = [
210
+ new HumanMessage('Hi'),
211
+ new AIMessage({
212
+ content: [
213
+ { type: 'tool_use', id: 'orphan_trail', name: 'x', input: {} },
214
+ ],
215
+ tool_calls: [{ name: 'x', args: {}, id: 'orphan_trail' }],
216
+ }),
217
+ ];
218
+
219
+ const out = sanitizeOrphanToolBlocks(messages);
220
+ // Trailing stripped-AI is popped per Bedrock/Anthropic rule: the
221
+ // conversation must not end with an empty assistant exchange.
222
+ expect(out).toHaveLength(1);
223
+ expect(out[0].getType()).toBe('human');
224
+ });
225
+
226
+ it('ignores Anthropic server-tool ids (srvtoolu_*)', () => {
227
+ const messages: BaseMessage[] = [
228
+ new HumanMessage('Hi'),
229
+ new AIMessage({
230
+ content: [
231
+ {
232
+ type: 'tool_use',
233
+ id: 'srvtoolu_anthropic_internal',
234
+ name: 'web_search',
235
+ input: {},
236
+ },
237
+ ],
238
+ tool_calls: [
239
+ { name: 'web_search', args: {}, id: 'srvtoolu_anthropic_internal' },
240
+ ],
241
+ }),
242
+ ];
243
+
244
+ const out = sanitizeOrphanToolBlocks(messages);
245
+ // No orphans detected — the server-tool prefix is exempt.
246
+ expect(out).toBe(messages);
247
+ });
248
+ });
@@ -11,7 +11,10 @@ import {
11
11
  import type { RunnableConfig } from '@langchain/core/runnables';
12
12
  import type { UsageMetadata } from '@langchain/core/messages';
13
13
  import type * as t from '@/types';
14
- import { createPruneMessages } from '@/messages/prune';
14
+ import {
15
+ createPruneMessages,
16
+ getMessagesWithinTokenLimit as realGetMessagesWithinTokenLimit,
17
+ } from '@/messages/prune';
15
18
  import { getLLMConfig } from '@/utils/llmConfig';
16
19
  import { Providers } from '@/common';
17
20
  import { Run } from '@/run';
@@ -362,6 +365,64 @@ describe('Prune Messages Tests', () => {
362
365
  });
363
366
  });
364
367
 
368
+ describe('instructionTokens budget reservation', () => {
369
+ it('reserves overhead from the budget when no system message is in the messages array', () => {
370
+ const tokenCounter = createTestTokenCounter();
371
+ // Budget is 100; `instructionTokens` claims 60 of it for runtime-built
372
+ // system + tool schemas. Effective message budget is 40 + 3 (assistant
373
+ // priming) = 37. Two AI messages of 30 tokens each must drop one.
374
+ const messages = [
375
+ new HumanMessage('q'),
376
+ new AIMessage('first response'),
377
+ new AIMessage('second response'),
378
+ ];
379
+ const indexTokenCountMap = { 0: 5, 1: 30, 2: 30 };
380
+
381
+ const resultWithReservation = realGetMessagesWithinTokenLimit({
382
+ messages,
383
+ maxContextTokens: 100,
384
+ indexTokenCountMap,
385
+ tokenCounter,
386
+ instructionTokens: 60,
387
+ });
388
+
389
+ const resultWithoutReservation = realGetMessagesWithinTokenLimit({
390
+ messages,
391
+ maxContextTokens: 100,
392
+ indexTokenCountMap,
393
+ tokenCounter,
394
+ });
395
+
396
+ // With reservation, fewer messages fit.
397
+ expect(resultWithReservation.context.length).toBeLessThan(
398
+ resultWithoutReservation.context.length
399
+ );
400
+ });
401
+
402
+ it('ignores instructionTokens when a system message is already in the messages array', () => {
403
+ const tokenCounter = createTestTokenCounter();
404
+ // Caller wires the system message in directly — its tokens come from
405
+ // indexTokenCountMap[0], not from instructionTokens. Setting
406
+ // instructionTokens here must not cause a double-deduction.
407
+ const messages = [
408
+ new SystemMessage('sys'),
409
+ new HumanMessage('q'),
410
+ new AIMessage('a'),
411
+ ];
412
+ const indexTokenCountMap = { 0: 10, 1: 5, 2: 5 };
413
+
414
+ const result = realGetMessagesWithinTokenLimit({
415
+ messages,
416
+ maxContextTokens: 50,
417
+ indexTokenCountMap,
418
+ tokenCounter,
419
+ instructionTokens: 9999, // would over-reserve if double-counted
420
+ });
421
+
422
+ expect(result.context.length).toBe(3);
423
+ });
424
+ });
425
+
365
426
  describe('checkValidNumber', () => {
366
427
  it('should return true for valid positive numbers', () => {
367
428
  expect(checkValidNumber(5)).toBe(true);
@@ -537,9 +598,15 @@ describe('Prune Messages Tests', () => {
537
598
  const tokenCounter = createTestTokenCounter();
538
599
  const messages = [
539
600
  new SystemMessage('System instruction'),
540
- new AIMessage('AI message 1'),
601
+ new AIMessage({
602
+ content: 'AI message 1',
603
+ tool_calls: [{ name: 't1', args: {}, id: 'tool1' }],
604
+ }),
541
605
  new ToolMessage({ content: 'Tool result 1', tool_call_id: 'tool1' }),
542
- new AIMessage('AI message 2'),
606
+ new AIMessage({
607
+ content: 'AI message 2',
608
+ tool_calls: [{ name: 't2', args: {}, id: 'tool2' }],
609
+ }),
543
610
  new ToolMessage({ content: 'Tool result 2', tool_call_id: 'tool2' }),
544
611
  ];
545
612
 
@@ -574,7 +641,10 @@ describe('Prune Messages Tests', () => {
574
641
  const messages = [
575
642
  new SystemMessage('System instruction'),
576
643
  new HumanMessage('Human message 1'),
577
- new AIMessage('AI message 1'),
644
+ new AIMessage({
645
+ content: 'AI message 1',
646
+ tool_calls: [{ name: 't1', args: {}, id: 'tool1' }],
647
+ }),
578
648
  new ToolMessage({ content: 'Tool result 1', tool_call_id: 'tool1' }),
579
649
  new HumanMessage('Human message 2'),
580
650
  new ToolMessage({ content: 'Tool result 2', tool_call_id: 'tool2' }),
@@ -599,12 +669,12 @@ describe('Prune Messages Tests', () => {
599
669
 
600
670
  const result = pruneMessages({ messages });
601
671
 
602
- // The context should include the system message, Human message 2, and Tool result 2
603
- // It should NOT start with Tool result 2 alone
604
- expect(result.context.length).toBe(3);
672
+ // Tool result 2 has no parent AIMessage with a matching tool_call (the
673
+ // test fixture is structurally broken), so orphan repair drops it.
674
+ // The context now ends cleanly at the Human message.
675
+ expect(result.context.length).toBe(2);
605
676
  expect(result.context[0]).toBe(messages[0]); // System message
606
677
  expect(result.context[1]).toBe(messages[4]); // Human message 2
607
- expect(result.context[2]).toBe(messages[5]); // Tool result 2
608
678
  });
609
679
 
610
680
  it('should handle the case where a tool message is followed by an AI message', () => {
@@ -676,11 +746,20 @@ describe('Prune Messages Tests', () => {
676
746
  const messages = [
677
747
  new SystemMessage('System instruction'),
678
748
  new HumanMessage('Human message 1'),
679
- new AIMessage('AI message 1 with tool use'),
749
+ new AIMessage({
750
+ content: 'AI message 1 with tool use',
751
+ tool_calls: [{ name: 't1', args: {}, id: 'tool1' }],
752
+ }),
680
753
  new ToolMessage({ content: 'Tool result 1', tool_call_id: 'tool1' }),
681
- new AIMessage('AI message 2 with tool use'),
754
+ new AIMessage({
755
+ content: 'AI message 2 with tool use',
756
+ tool_calls: [{ name: 't2', args: {}, id: 'tool2' }],
757
+ }),
682
758
  new ToolMessage({ content: 'Tool result 2', tool_call_id: 'tool2' }),
683
- new AIMessage('AI message 3 with tool use'),
759
+ new AIMessage({
760
+ content: 'AI message 3 with tool use',
761
+ tool_calls: [{ name: 't3', args: {}, id: 'tool3' }],
762
+ }),
684
763
  new ToolMessage({ content: 'Tool result 3', tool_call_id: 'tool3' }),
685
764
  ];
686
765
 
@@ -749,10 +828,10 @@ describe('Prune Messages Tests', () => {
749
828
  const tokenCounter = createTestTokenCounter();
750
829
  const messages = [
751
830
  new SystemMessage('System instruction'), // 18 chars
752
- new HumanMessage('First message from user'), // 23 chars
831
+ new HumanMessage('First message from user'), // 23 chars
753
832
  new AIMessage('First response from assistant'), // 29 chars
754
833
  new HumanMessage('Second message from user'), // 24 chars
755
- new AIMessage('Second response'), // 15 chars
834
+ new AIMessage('Second response'), // 15 chars
756
835
  new HumanMessage('Third message'), // 13 chars
757
836
  new AIMessage('Third response'), // 14 chars
758
837
  ];
@@ -798,7 +877,7 @@ describe('Prune Messages Tests', () => {
798
877
  for (const msg of result.messagesToRefine) {
799
878
  expect(msg).toBeDefined();
800
879
  expect(typeof msg.getType()).toBe('string');
801
- };
880
+ }
802
881
  });
803
882
 
804
883
  it('should return messagesToRefine compatible with summarization callbacks', () => {
@@ -837,7 +916,14 @@ describe('Prune Messages Tests', () => {
837
916
 
838
917
  // Each message should have a valid type
839
918
  const msgType = msg.getType();
840
- expect(['human', 'ai', 'system', 'tool', 'generic', 'function']).toContain(msgType);
919
+ expect([
920
+ 'human',
921
+ 'ai',
922
+ 'system',
923
+ 'tool',
924
+ 'generic',
925
+ 'function',
926
+ ]).toContain(msgType);
841
927
 
842
928
  // Each message should have accessible content (string or array)
843
929
  expect(msg.content).toBeDefined();
@@ -852,7 +938,9 @@ describe('Prune Messages Tests', () => {
852
938
  content: msg.content,
853
939
  }));
854
940
  expect(serialized.length).toBe(result.messagesToRefine.length);
855
- expect(serialized.every((s) => s.type && s.content !== undefined)).toBe(true);
941
+ expect(serialized.every((s) => s.type && s.content !== undefined)).toBe(
942
+ true
943
+ );
856
944
  });
857
945
  });
858
946
 
@@ -61,7 +61,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
61
61
  agentId: 'specialist',
62
62
  provider: Providers.ANTHROPIC,
63
63
  clientOptions: {
64
- modelName: 'claude-3-7-sonnet-20250219',
64
+ modelName: 'claude-sonnet-4-5-20250929',
65
65
  apiKey: 'test-key',
66
66
  thinking: {
67
67
  type: 'enabled',
@@ -77,7 +77,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
77
77
  {
78
78
  from: 'supervisor',
79
79
  to: 'specialist',
80
- edgeType: EdgeType.TRANSFER,
80
+ edgeType: EdgeType.HANDOFF,
81
81
  description: 'Transfer to specialist for detailed analysis',
82
82
  },
83
83
  ];
@@ -150,7 +150,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
150
150
  agentId: 'agent_b',
151
151
  provider: Providers.ANTHROPIC,
152
152
  clientOptions: {
153
- modelName: 'claude-3-7-sonnet-20250219',
153
+ modelName: 'claude-sonnet-4-5-20250929',
154
154
  apiKey: 'test-key',
155
155
  thinking: {
156
156
  type: 'enabled',
@@ -166,7 +166,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
166
166
  {
167
167
  from: 'agent_a',
168
168
  to: 'agent_b',
169
- edgeType: EdgeType.TRANSFER,
169
+ edgeType: EdgeType.HANDOFF,
170
170
  },
171
171
  ];
172
172
 
@@ -195,7 +195,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
195
195
  provider: Providers.BEDROCK,
196
196
  clientOptions: {
197
197
  region: 'us-east-1',
198
- model: 'anthropic.claude-3-5-haiku-20241022-v1:0',
198
+ model: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
199
199
  // No thinking config
200
200
  },
201
201
  instructions: 'You are a coordinator',
@@ -206,7 +206,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
206
206
  provider: Providers.BEDROCK,
207
207
  clientOptions: {
208
208
  region: 'us-east-1',
209
- model: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
209
+ model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
210
210
  additionalModelRequestFields: {
211
211
  thinking: {
212
212
  type: 'enabled',
@@ -223,7 +223,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
223
223
  {
224
224
  from: 'coordinator',
225
225
  to: 'analyst',
226
- edgeType: EdgeType.TRANSFER,
226
+ edgeType: EdgeType.HANDOFF,
227
227
  description: 'Transfer to analyst for deep analysis',
228
228
  },
229
229
  ];
@@ -280,7 +280,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
280
280
  provider: Providers.BEDROCK,
281
281
  clientOptions: {
282
282
  region: 'us-east-1',
283
- model: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
283
+ model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
284
284
  additionalModelRequestFields: {
285
285
  thinking: {
286
286
  type: 'enabled',
@@ -297,7 +297,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
297
297
  {
298
298
  from: 'agent_a',
299
299
  to: 'agent_b',
300
- edgeType: EdgeType.TRANSFER,
300
+ edgeType: EdgeType.HANDOFF,
301
301
  },
302
302
  ];
303
303
 
@@ -343,7 +343,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
343
343
  provider: Providers.BEDROCK,
344
344
  clientOptions: {
345
345
  region: 'us-east-1',
346
- model: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
346
+ model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
347
347
  additionalModelRequestFields: {
348
348
  thinking: {
349
349
  type: 'enabled',
@@ -360,7 +360,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
360
360
  {
361
361
  from: 'supervisor',
362
362
  to: 'bedrock_specialist',
363
- edgeType: EdgeType.TRANSFER,
363
+ edgeType: EdgeType.HANDOFF,
364
364
  description: 'Transfer to Bedrock specialist',
365
365
  },
366
366
  ];
@@ -434,7 +434,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
434
434
  agentId: 'reviewer',
435
435
  provider: Providers.ANTHROPIC,
436
436
  clientOptions: {
437
- modelName: 'claude-3-7-sonnet-20250219',
437
+ modelName: 'claude-sonnet-4-5-20250929',
438
438
  apiKey: 'test-key',
439
439
  thinking: {
440
440
  type: 'enabled',
@@ -450,12 +450,12 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
450
450
  {
451
451
  from: 'router',
452
452
  to: 'processor',
453
- edgeType: EdgeType.TRANSFER,
453
+ edgeType: EdgeType.HANDOFF,
454
454
  },
455
455
  {
456
456
  from: 'processor',
457
457
  to: 'reviewer',
458
- edgeType: EdgeType.TRANSFER,
458
+ edgeType: EdgeType.HANDOFF,
459
459
  },
460
460
  ];
461
461
 
@@ -508,7 +508,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
508
508
  agentId: 'agent_a',
509
509
  provider: Providers.ANTHROPIC,
510
510
  clientOptions: {
511
- modelName: 'claude-3-7-sonnet-20250219',
511
+ modelName: 'claude-sonnet-4-5-20250929',
512
512
  apiKey: 'test-key',
513
513
  thinking: {
514
514
  type: 'enabled',
@@ -522,7 +522,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
522
522
  agentId: 'agent_b',
523
523
  provider: Providers.ANTHROPIC,
524
524
  clientOptions: {
525
- modelName: 'claude-3-7-sonnet-20250219',
525
+ modelName: 'claude-sonnet-4-5-20250929',
526
526
  apiKey: 'test-key',
527
527
  thinking: {
528
528
  type: 'enabled',
@@ -538,7 +538,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
538
538
  {
539
539
  from: 'agent_a',
540
540
  to: 'agent_b',
541
- edgeType: EdgeType.TRANSFER,
541
+ edgeType: EdgeType.HANDOFF,
542
542
  },
543
543
  ];
544
544
 
@@ -587,7 +587,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
587
587
  agentId: 'agent_b',
588
588
  provider: Providers.ANTHROPIC,
589
589
  clientOptions: {
590
- modelName: 'claude-3-7-sonnet-20250219',
590
+ modelName: 'claude-sonnet-4-5-20250929',
591
591
  apiKey: 'test-key',
592
592
  thinking: {
593
593
  type: 'enabled',
@@ -603,7 +603,7 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
603
603
  {
604
604
  from: 'agent_a',
605
605
  to: 'agent_b',
606
- edgeType: EdgeType.TRANSFER,
606
+ edgeType: EdgeType.HANDOFF,
607
607
  },
608
608
  ];
609
609