@strands-agents/sdk 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (435) hide show
  1. package/README.md +11 -11
  2. package/dist/src/__fixtures__/agent-helpers.d.ts.map +1 -1
  3. package/dist/src/__fixtures__/agent-helpers.js +9 -0
  4. package/dist/src/__fixtures__/agent-helpers.js.map +1 -1
  5. package/dist/src/__fixtures__/register-node-defaults.d.ts +2 -0
  6. package/dist/src/__fixtures__/register-node-defaults.d.ts.map +1 -0
  7. package/dist/src/__fixtures__/register-node-defaults.js +6 -0
  8. package/dist/src/__fixtures__/register-node-defaults.js.map +1 -0
  9. package/dist/src/__fixtures__/test-sandbox.node.d.ts.map +1 -1
  10. package/dist/src/__fixtures__/test-sandbox.node.js +4 -3
  11. package/dist/src/__fixtures__/test-sandbox.node.js.map +1 -1
  12. package/dist/src/__tests__/default-slot.test.d.ts +2 -0
  13. package/dist/src/__tests__/default-slot.test.d.ts.map +1 -0
  14. package/dist/src/__tests__/default-slot.test.js +33 -0
  15. package/dist/src/__tests__/default-slot.test.js.map +1 -0
  16. package/dist/src/a2a/__tests__/async-lock.test.d.ts +2 -0
  17. package/dist/src/a2a/__tests__/async-lock.test.d.ts.map +1 -0
  18. package/dist/src/a2a/__tests__/async-lock.test.js +137 -0
  19. package/dist/src/a2a/__tests__/async-lock.test.js.map +1 -0
  20. package/dist/src/a2a/__tests__/executor.test.js +146 -8
  21. package/dist/src/a2a/__tests__/executor.test.js.map +1 -1
  22. package/dist/src/a2a/__tests__/server.test.js +20 -0
  23. package/dist/src/a2a/__tests__/server.test.js.map +1 -1
  24. package/dist/src/a2a/async-lock.d.ts +22 -0
  25. package/dist/src/a2a/async-lock.d.ts.map +1 -0
  26. package/dist/src/a2a/async-lock.js +38 -0
  27. package/dist/src/a2a/async-lock.js.map +1 -0
  28. package/dist/src/a2a/executor.d.ts +59 -24
  29. package/dist/src/a2a/executor.d.ts.map +1 -1
  30. package/dist/src/a2a/executor.js +209 -32
  31. package/dist/src/a2a/executor.js.map +1 -1
  32. package/dist/src/a2a/index.d.ts +1 -1
  33. package/dist/src/a2a/index.d.ts.map +1 -1
  34. package/dist/src/a2a/index.js +1 -1
  35. package/dist/src/a2a/index.js.map +1 -1
  36. package/dist/src/a2a/server.d.ts +18 -2
  37. package/dist/src/a2a/server.d.ts.map +1 -1
  38. package/dist/src/a2a/server.js +13 -2
  39. package/dist/src/a2a/server.js.map +1 -1
  40. package/dist/src/agent/__tests__/agent.context-manager.test.d.ts +2 -0
  41. package/dist/src/agent/__tests__/agent.context-manager.test.d.ts.map +1 -0
  42. package/dist/src/agent/__tests__/agent.context-manager.test.js +107 -0
  43. package/dist/src/agent/__tests__/agent.context-manager.test.js.map +1 -0
  44. package/dist/src/agent/__tests__/agent.stateful-model.test.js +2 -2
  45. package/dist/src/agent/__tests__/agent.stateful-model.test.js.map +1 -1
  46. package/dist/src/agent/__tests__/agent.tracer.test.node.js +14 -0
  47. package/dist/src/agent/__tests__/agent.tracer.test.node.js.map +1 -1
  48. package/dist/src/agent/agent.d.ts +135 -2
  49. package/dist/src/agent/agent.d.ts.map +1 -1
  50. package/dist/src/agent/agent.js +506 -189
  51. package/dist/src/agent/agent.js.map +1 -1
  52. package/dist/src/context-manager/modes/agentic/agentic-context.d.ts +19 -0
  53. package/dist/src/context-manager/modes/agentic/agentic-context.d.ts.map +1 -0
  54. package/dist/src/context-manager/modes/agentic/agentic-context.js +245 -0
  55. package/dist/src/context-manager/modes/agentic/agentic-context.js.map +1 -0
  56. package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts +2 -0
  57. package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts.map +1 -0
  58. package/dist/src/conversation-manager/__tests__/agentic-context.test.js +332 -0
  59. package/dist/src/conversation-manager/__tests__/agentic-context.test.js.map +1 -0
  60. package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts +2 -0
  61. package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts.map +1 -0
  62. package/dist/src/conversation-manager/__tests__/context-compression.test.js +176 -0
  63. package/dist/src/conversation-manager/__tests__/context-compression.test.js.map +1 -0
  64. package/dist/src/conversation-manager/__tests__/pin.test.d.ts +2 -0
  65. package/dist/src/conversation-manager/__tests__/pin.test.d.ts.map +1 -0
  66. package/dist/src/conversation-manager/__tests__/pin.test.js +119 -0
  67. package/dist/src/conversation-manager/__tests__/pin.test.js.map +1 -0
  68. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js +49 -0
  69. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js.map +1 -1
  70. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js +58 -0
  71. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js.map +1 -1
  72. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.d.ts +2 -0
  73. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.d.ts.map +1 -0
  74. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js +138 -0
  75. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js.map +1 -0
  76. package/dist/src/conversation-manager/compression/context-compression.d.ts +39 -0
  77. package/dist/src/conversation-manager/compression/context-compression.d.ts.map +1 -0
  78. package/dist/src/conversation-manager/compression/context-compression.js +150 -0
  79. package/dist/src/conversation-manager/compression/context-compression.js.map +1 -0
  80. package/dist/src/conversation-manager/compression/pin-message.d.ts +45 -0
  81. package/dist/src/conversation-manager/compression/pin-message.d.ts.map +1 -0
  82. package/dist/src/conversation-manager/compression/pin-message.js +106 -0
  83. package/dist/src/conversation-manager/compression/pin-message.js.map +1 -0
  84. package/dist/src/conversation-manager/conversation-manager.d.ts +2 -0
  85. package/dist/src/conversation-manager/conversation-manager.d.ts.map +1 -1
  86. package/dist/src/conversation-manager/conversation-manager.js +2 -2
  87. package/dist/src/conversation-manager/conversation-manager.js.map +1 -1
  88. package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts +7 -0
  89. package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts.map +1 -1
  90. package/dist/src/conversation-manager/sliding-window-conversation-manager.js +30 -38
  91. package/dist/src/conversation-manager/sliding-window-conversation-manager.js.map +1 -1
  92. package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts +7 -19
  93. package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts.map +1 -1
  94. package/dist/src/conversation-manager/summarizing-conversation-manager.js +20 -109
  95. package/dist/src/conversation-manager/summarizing-conversation-manager.js.map +1 -1
  96. package/dist/src/default-slot.d.ts +6 -0
  97. package/dist/src/default-slot.d.ts.map +1 -0
  98. package/dist/src/default-slot.js +18 -0
  99. package/dist/src/default-slot.js.map +1 -0
  100. package/dist/src/errors.d.ts +8 -0
  101. package/dist/src/errors.d.ts.map +1 -1
  102. package/dist/src/errors.js +11 -0
  103. package/dist/src/errors.js.map +1 -1
  104. package/dist/src/index.d.ts +8 -1
  105. package/dist/src/index.d.ts.map +1 -1
  106. package/dist/src/index.js +7 -1
  107. package/dist/src/index.js.map +1 -1
  108. package/dist/src/index.node.d.ts +2 -0
  109. package/dist/src/index.node.d.ts.map +1 -0
  110. package/dist/src/index.node.js +9 -0
  111. package/dist/src/index.node.js.map +1 -0
  112. package/dist/src/injection/__tests__/message-injection.test.d.ts +2 -0
  113. package/dist/src/injection/__tests__/message-injection.test.d.ts.map +1 -0
  114. package/dist/src/injection/__tests__/message-injection.test.js +200 -0
  115. package/dist/src/injection/__tests__/message-injection.test.js.map +1 -0
  116. package/dist/src/injection/index.d.ts +6 -0
  117. package/dist/src/injection/index.d.ts.map +1 -0
  118. package/dist/src/injection/index.js +2 -0
  119. package/dist/src/injection/index.js.map +1 -0
  120. package/dist/src/injection/message-injection.d.ts +65 -0
  121. package/dist/src/injection/message-injection.d.ts.map +1 -0
  122. package/dist/src/injection/message-injection.js +134 -0
  123. package/dist/src/injection/message-injection.js.map +1 -0
  124. package/dist/src/injection/types.d.ts +63 -0
  125. package/dist/src/injection/types.d.ts.map +1 -0
  126. package/dist/src/injection/types.js +2 -0
  127. package/dist/src/injection/types.js.map +1 -0
  128. package/dist/src/injection/xml.d.ts +27 -0
  129. package/dist/src/injection/xml.d.ts.map +1 -0
  130. package/dist/src/injection/xml.js +31 -0
  131. package/dist/src/injection/xml.js.map +1 -0
  132. package/dist/src/interrupt.d.ts +5 -1
  133. package/dist/src/interrupt.d.ts.map +1 -1
  134. package/dist/src/interrupt.js +6 -0
  135. package/dist/src/interrupt.js.map +1 -1
  136. package/dist/src/memory/__tests__/memory-manager.test.d.ts +2 -0
  137. package/dist/src/memory/__tests__/memory-manager.test.d.ts.map +1 -0
  138. package/dist/src/memory/__tests__/memory-manager.test.js +679 -0
  139. package/dist/src/memory/__tests__/memory-manager.test.js.map +1 -0
  140. package/dist/src/memory/extraction/__tests__/extraction.test.d.ts +2 -0
  141. package/dist/src/memory/extraction/__tests__/extraction.test.d.ts.map +1 -0
  142. package/dist/src/memory/extraction/__tests__/extraction.test.js +637 -0
  143. package/dist/src/memory/extraction/__tests__/extraction.test.js.map +1 -0
  144. package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts +2 -0
  145. package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts.map +1 -0
  146. package/dist/src/memory/extraction/__tests__/model-extractor.test.js +68 -0
  147. package/dist/src/memory/extraction/__tests__/model-extractor.test.js.map +1 -0
  148. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts +2 -0
  149. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts.map +1 -0
  150. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js +81 -0
  151. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js.map +1 -0
  152. package/dist/src/memory/extraction/coordinator.d.ts +128 -0
  153. package/dist/src/memory/extraction/coordinator.d.ts.map +1 -0
  154. package/dist/src/memory/extraction/coordinator.js +245 -0
  155. package/dist/src/memory/extraction/coordinator.js.map +1 -0
  156. package/dist/src/memory/extraction/model-extractor.d.ts +32 -0
  157. package/dist/src/memory/extraction/model-extractor.d.ts.map +1 -0
  158. package/dist/src/memory/extraction/model-extractor.js +118 -0
  159. package/dist/src/memory/extraction/model-extractor.js.map +1 -0
  160. package/dist/src/memory/extraction/resolve-extraction-config.d.ts +46 -0
  161. package/dist/src/memory/extraction/resolve-extraction-config.d.ts.map +1 -0
  162. package/dist/src/memory/extraction/resolve-extraction-config.js +59 -0
  163. package/dist/src/memory/extraction/resolve-extraction-config.js.map +1 -0
  164. package/dist/src/memory/extraction/triggers.d.ts +41 -0
  165. package/dist/src/memory/extraction/triggers.d.ts.map +1 -0
  166. package/dist/src/memory/extraction/triggers.js +59 -0
  167. package/dist/src/memory/extraction/triggers.js.map +1 -0
  168. package/dist/src/memory/extraction/types.d.ts +133 -0
  169. package/dist/src/memory/extraction/types.d.ts.map +1 -0
  170. package/dist/src/memory/extraction/types.js +19 -0
  171. package/dist/src/memory/extraction/types.js.map +1 -0
  172. package/dist/src/memory/index.d.ts +10 -0
  173. package/dist/src/memory/index.d.ts.map +1 -0
  174. package/dist/src/memory/index.js +5 -0
  175. package/dist/src/memory/index.js.map +1 -0
  176. package/dist/src/memory/memory-manager.d.ts +178 -0
  177. package/dist/src/memory/memory-manager.d.ts.map +1 -0
  178. package/dist/src/memory/memory-manager.js +526 -0
  179. package/dist/src/memory/memory-manager.js.map +1 -0
  180. package/dist/src/memory/types.d.ts +278 -0
  181. package/dist/src/memory/types.d.ts.map +1 -0
  182. package/dist/src/memory/types.js +2 -0
  183. package/dist/src/memory/types.js.map +1 -0
  184. package/dist/src/middleware/__tests__/agent-middleware.test.d.ts +2 -0
  185. package/dist/src/middleware/__tests__/agent-middleware.test.d.ts.map +1 -0
  186. package/dist/src/middleware/__tests__/agent-middleware.test.js +1206 -0
  187. package/dist/src/middleware/__tests__/agent-middleware.test.js.map +1 -0
  188. package/dist/src/middleware/__tests__/copy-on-input.test.d.ts +2 -0
  189. package/dist/src/middleware/__tests__/copy-on-input.test.d.ts.map +1 -0
  190. package/dist/src/middleware/__tests__/copy-on-input.test.js +379 -0
  191. package/dist/src/middleware/__tests__/copy-on-input.test.js.map +1 -0
  192. package/dist/src/middleware/__tests__/custom-stages.test.d.ts +2 -0
  193. package/dist/src/middleware/__tests__/custom-stages.test.d.ts.map +1 -0
  194. package/dist/src/middleware/__tests__/custom-stages.test.js +97 -0
  195. package/dist/src/middleware/__tests__/custom-stages.test.js.map +1 -0
  196. package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts +2 -0
  197. package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts.map +1 -0
  198. package/dist/src/middleware/__tests__/middleware-interrupts.test.js +267 -0
  199. package/dist/src/middleware/__tests__/middleware-interrupts.test.js.map +1 -0
  200. package/dist/src/middleware/__tests__/registry.test.d.ts +2 -0
  201. package/dist/src/middleware/__tests__/registry.test.d.ts.map +1 -0
  202. package/dist/src/middleware/__tests__/registry.test.js +525 -0
  203. package/dist/src/middleware/__tests__/registry.test.js.map +1 -0
  204. package/dist/src/middleware/index.d.ts +5 -0
  205. package/dist/src/middleware/index.d.ts.map +1 -0
  206. package/dist/src/middleware/index.js +3 -0
  207. package/dist/src/middleware/index.js.map +1 -0
  208. package/dist/src/middleware/registry.d.ts +58 -0
  209. package/dist/src/middleware/registry.d.ts.map +1 -0
  210. package/dist/src/middleware/registry.js +107 -0
  211. package/dist/src/middleware/registry.js.map +1 -0
  212. package/dist/src/middleware/stages.d.ts +145 -0
  213. package/dist/src/middleware/stages.d.ts.map +1 -0
  214. package/dist/src/middleware/stages.js +34 -0
  215. package/dist/src/middleware/stages.js.map +1 -0
  216. package/dist/src/middleware/types.d.ts +88 -0
  217. package/dist/src/middleware/types.d.ts.map +1 -0
  218. package/dist/src/middleware/types.js +2 -0
  219. package/dist/src/middleware/types.js.map +1 -0
  220. package/dist/src/models/__tests__/anthropic.test.js +16 -1
  221. package/dist/src/models/__tests__/anthropic.test.js.map +1 -1
  222. package/dist/src/models/__tests__/bedrock.test.js +39 -0
  223. package/dist/src/models/__tests__/bedrock.test.js.map +1 -1
  224. package/dist/src/models/__tests__/model.test.js +46 -3
  225. package/dist/src/models/__tests__/model.test.js.map +1 -1
  226. package/dist/src/models/anthropic.js +2 -2
  227. package/dist/src/models/anthropic.js.map +1 -1
  228. package/dist/src/models/bedrock.d.ts.map +1 -1
  229. package/dist/src/models/bedrock.js +12 -5
  230. package/dist/src/models/bedrock.js.map +1 -1
  231. package/dist/src/models/defaults.d.ts.map +1 -1
  232. package/dist/src/models/defaults.js +2 -0
  233. package/dist/src/models/defaults.js.map +1 -1
  234. package/dist/src/models/model.d.ts.map +1 -1
  235. package/dist/src/models/model.js +7 -3
  236. package/dist/src/models/model.js.map +1 -1
  237. package/dist/src/models/openai/__tests__/responses.test.js +8 -14
  238. package/dist/src/models/openai/__tests__/responses.test.js.map +1 -1
  239. package/dist/src/sandbox/__tests__/default.test.browser.d.ts +2 -0
  240. package/dist/src/sandbox/__tests__/default.test.browser.d.ts.map +1 -0
  241. package/dist/src/sandbox/__tests__/default.test.browser.js +11 -0
  242. package/dist/src/sandbox/__tests__/default.test.browser.js.map +1 -0
  243. package/dist/src/sandbox/__tests__/default.test.node.d.ts +2 -0
  244. package/dist/src/sandbox/__tests__/default.test.node.d.ts.map +1 -0
  245. package/dist/src/sandbox/__tests__/default.test.node.js +23 -0
  246. package/dist/src/sandbox/__tests__/default.test.node.js.map +1 -0
  247. package/dist/src/sandbox/__tests__/docker.test.node.d.ts +2 -0
  248. package/dist/src/sandbox/__tests__/docker.test.node.d.ts.map +1 -0
  249. package/dist/src/sandbox/__tests__/docker.test.node.js +89 -0
  250. package/dist/src/sandbox/__tests__/docker.test.node.js.map +1 -0
  251. package/dist/src/sandbox/__tests__/errors.test.node.d.ts +2 -0
  252. package/dist/src/sandbox/__tests__/errors.test.node.d.ts.map +1 -0
  253. package/dist/src/sandbox/__tests__/errors.test.node.js +33 -0
  254. package/dist/src/sandbox/__tests__/errors.test.node.js.map +1 -0
  255. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts +2 -0
  256. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts.map +1 -0
  257. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js +124 -0
  258. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js.map +1 -0
  259. package/dist/src/sandbox/__tests__/posix-shell.test.node.js +50 -4
  260. package/dist/src/sandbox/__tests__/posix-shell.test.node.js.map +1 -1
  261. package/dist/src/sandbox/__tests__/ssh.test.node.d.ts +2 -0
  262. package/dist/src/sandbox/__tests__/ssh.test.node.d.ts.map +1 -0
  263. package/dist/src/sandbox/__tests__/ssh.test.node.js +262 -0
  264. package/dist/src/sandbox/__tests__/ssh.test.node.js.map +1 -0
  265. package/dist/src/sandbox/base.d.ts +17 -4
  266. package/dist/src/sandbox/base.d.ts.map +1 -1
  267. package/dist/src/sandbox/base.js +10 -2
  268. package/dist/src/sandbox/base.js.map +1 -1
  269. package/dist/src/sandbox/constants.d.ts +18 -0
  270. package/dist/src/sandbox/constants.d.ts.map +1 -1
  271. package/dist/src/sandbox/constants.js +20 -0
  272. package/dist/src/sandbox/constants.js.map +1 -1
  273. package/dist/src/sandbox/default.d.ts +3 -0
  274. package/dist/src/sandbox/default.d.ts.map +1 -0
  275. package/dist/src/sandbox/default.js +3 -0
  276. package/dist/src/sandbox/default.js.map +1 -0
  277. package/dist/src/sandbox/docker.d.ts +38 -0
  278. package/dist/src/sandbox/docker.d.ts.map +1 -0
  279. package/dist/src/sandbox/docker.js +61 -0
  280. package/dist/src/sandbox/docker.js.map +1 -0
  281. package/dist/src/sandbox/errors.d.ts +26 -0
  282. package/dist/src/sandbox/errors.d.ts.map +1 -0
  283. package/dist/src/sandbox/errors.js +35 -0
  284. package/dist/src/sandbox/errors.js.map +1 -0
  285. package/dist/src/sandbox/index.d.ts +5 -0
  286. package/dist/src/sandbox/index.d.ts.map +1 -0
  287. package/dist/src/sandbox/index.js +4 -0
  288. package/dist/src/sandbox/index.js.map +1 -0
  289. package/dist/src/sandbox/not-a-sandbox-local-environment.d.ts +16 -0
  290. package/dist/src/sandbox/not-a-sandbox-local-environment.d.ts.map +1 -0
  291. package/dist/src/sandbox/not-a-sandbox-local-environment.js +83 -0
  292. package/dist/src/sandbox/not-a-sandbox-local-environment.js.map +1 -0
  293. package/dist/src/sandbox/posix-shell.d.ts +21 -0
  294. package/dist/src/sandbox/posix-shell.d.ts.map +1 -1
  295. package/dist/src/sandbox/posix-shell.js +41 -3
  296. package/dist/src/sandbox/posix-shell.js.map +1 -1
  297. package/dist/src/sandbox/ssh.d.ts +56 -0
  298. package/dist/src/sandbox/ssh.d.ts.map +1 -0
  299. package/dist/src/sandbox/ssh.js +121 -0
  300. package/dist/src/sandbox/ssh.js.map +1 -0
  301. package/dist/src/sandbox/stream-process.d.ts.map +1 -1
  302. package/dist/src/sandbox/stream-process.js +3 -2
  303. package/dist/src/sandbox/stream-process.js.map +1 -1
  304. package/dist/src/tsconfig.tsbuildinfo +1 -1
  305. package/dist/src/types/agent.d.ts +21 -0
  306. package/dist/src/types/agent.d.ts.map +1 -1
  307. package/dist/src/types/agent.js.map +1 -1
  308. package/dist/src/types/messages.d.ts +9 -1
  309. package/dist/src/types/messages.d.ts.map +1 -1
  310. package/dist/src/types/messages.js +13 -1
  311. package/dist/src/types/messages.js.map +1 -1
  312. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts +2 -0
  313. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts.map +1 -0
  314. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js +675 -0
  315. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js.map +1 -0
  316. package/dist/src/vended-interventions/cedar/cedar.d.ts +102 -0
  317. package/dist/src/vended-interventions/cedar/cedar.d.ts.map +1 -0
  318. package/dist/src/vended-interventions/cedar/cedar.js +228 -0
  319. package/dist/src/vended-interventions/cedar/cedar.js.map +1 -0
  320. package/dist/src/vended-interventions/cedar/index.d.ts +3 -0
  321. package/dist/src/vended-interventions/cedar/index.d.ts.map +1 -0
  322. package/dist/src/vended-interventions/cedar/index.js +2 -0
  323. package/dist/src/vended-interventions/cedar/index.js.map +1 -0
  324. package/dist/src/vended-interventions/cedar/schema-generator.d.ts +10 -0
  325. package/dist/src/vended-interventions/cedar/schema-generator.d.ts.map +1 -0
  326. package/dist/src/vended-interventions/cedar/schema-generator.js +33 -0
  327. package/dist/src/vended-interventions/cedar/schema-generator.js.map +1 -0
  328. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.d.ts +2 -0
  329. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.d.ts.map +1 -0
  330. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.js +611 -0
  331. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.js.map +1 -0
  332. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.d.ts +2 -0
  333. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.d.ts.map +1 -0
  334. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.js +2 -0
  335. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.js.map +1 -0
  336. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts +230 -0
  337. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts.map +1 -0
  338. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js +370 -0
  339. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js.map +1 -0
  340. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.d.ts +2 -0
  341. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.d.ts.map +1 -0
  342. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js +96 -0
  343. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js.map +1 -0
  344. package/dist/src/vended-plugins/context-injector/index.d.ts +25 -0
  345. package/dist/src/vended-plugins/context-injector/index.d.ts.map +1 -0
  346. package/dist/src/vended-plugins/context-injector/index.js +23 -0
  347. package/dist/src/vended-plugins/context-injector/index.js.map +1 -0
  348. package/dist/src/vended-plugins/context-injector/plugin.d.ts +55 -0
  349. package/dist/src/vended-plugins/context-injector/plugin.d.ts.map +1 -0
  350. package/dist/src/vended-plugins/context-injector/plugin.js +41 -0
  351. package/dist/src/vended-plugins/context-injector/plugin.js.map +1 -0
  352. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts +2 -0
  353. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts.map +1 -0
  354. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js +68 -0
  355. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js.map +1 -0
  356. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js +43 -4
  357. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js.map +1 -1
  358. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts +2 -0
  359. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts.map +1 -0
  360. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js +93 -0
  361. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js.map +1 -0
  362. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js +68 -0
  363. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js.map +1 -1
  364. package/dist/src/vended-plugins/context-offloader/index.d.ts +1 -1
  365. package/dist/src/vended-plugins/context-offloader/index.d.ts.map +1 -1
  366. package/dist/src/vended-plugins/context-offloader/plugin.d.ts +4 -1
  367. package/dist/src/vended-plugins/context-offloader/plugin.d.ts.map +1 -1
  368. package/dist/src/vended-plugins/context-offloader/plugin.js +40 -8
  369. package/dist/src/vended-plugins/context-offloader/plugin.js.map +1 -1
  370. package/dist/src/vended-plugins/context-offloader/search.d.ts.map +1 -1
  371. package/dist/src/vended-plugins/context-offloader/search.js +3 -5
  372. package/dist/src/vended-plugins/context-offloader/search.js.map +1 -1
  373. package/dist/src/vended-plugins/context-offloader/storage.d.ts +58 -6
  374. package/dist/src/vended-plugins/context-offloader/storage.d.ts.map +1 -1
  375. package/dist/src/vended-plugins/context-offloader/storage.js +136 -14
  376. package/dist/src/vended-plugins/context-offloader/storage.js.map +1 -1
  377. package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts +2 -0
  378. package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts.map +1 -0
  379. package/dist/src/vended-plugins/goal/__tests__/plugin.test.js +736 -0
  380. package/dist/src/vended-plugins/goal/__tests__/plugin.test.js.map +1 -0
  381. package/dist/src/vended-plugins/goal/index.d.ts +21 -0
  382. package/dist/src/vended-plugins/goal/index.d.ts.map +1 -0
  383. package/dist/src/vended-plugins/goal/index.js +20 -0
  384. package/dist/src/vended-plugins/goal/index.js.map +1 -0
  385. package/dist/src/vended-plugins/goal/judge.d.ts +41 -0
  386. package/dist/src/vended-plugins/goal/judge.d.ts.map +1 -0
  387. package/dist/src/vended-plugins/goal/judge.js +92 -0
  388. package/dist/src/vended-plugins/goal/judge.js.map +1 -0
  389. package/dist/src/vended-plugins/goal/plugin.d.ts +214 -0
  390. package/dist/src/vended-plugins/goal/plugin.d.ts.map +1 -0
  391. package/dist/src/vended-plugins/goal/plugin.js +287 -0
  392. package/dist/src/vended-plugins/goal/plugin.js.map +1 -0
  393. package/dist/src/vended-plugins/index.d.ts +3 -1
  394. package/dist/src/vended-plugins/index.d.ts.map +1 -1
  395. package/dist/src/vended-plugins/index.js +3 -1
  396. package/dist/src/vended-plugins/index.js.map +1 -1
  397. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js +17 -7
  398. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js.map +1 -1
  399. package/dist/src/vended-plugins/skills/agent-skills.d.ts +21 -7
  400. package/dist/src/vended-plugins/skills/agent-skills.d.ts.map +1 -1
  401. package/dist/src/vended-plugins/skills/agent-skills.js +144 -77
  402. package/dist/src/vended-plugins/skills/agent-skills.js.map +1 -1
  403. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js +44 -4
  404. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js.map +1 -1
  405. package/dist/src/vended-tools/bash/bash.d.ts +3 -24
  406. package/dist/src/vended-tools/bash/bash.d.ts.map +1 -1
  407. package/dist/src/vended-tools/bash/bash.js +9 -9
  408. package/dist/src/vended-tools/bash/bash.js.map +1 -1
  409. package/dist/src/vended-tools/bash/index.d.ts +3 -1
  410. package/dist/src/vended-tools/bash/index.d.ts.map +1 -1
  411. package/dist/src/vended-tools/bash/index.js +2 -1
  412. package/dist/src/vended-tools/bash/index.js.map +1 -1
  413. package/dist/src/vended-tools/bash/make-bash.d.ts +22 -0
  414. package/dist/src/vended-tools/bash/make-bash.d.ts.map +1 -0
  415. package/dist/src/vended-tools/bash/make-bash.js +40 -0
  416. package/dist/src/vended-tools/bash/make-bash.js.map +1 -0
  417. package/dist/src/vended-tools/bash/types.d.ts +1 -0
  418. package/dist/src/vended-tools/bash/types.d.ts.map +1 -1
  419. package/dist/src/vended-tools/bash/types.js +2 -0
  420. package/dist/src/vended-tools/bash/types.js.map +1 -1
  421. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js +83 -1
  422. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js.map +1 -1
  423. package/dist/src/vended-tools/file-editor/file-editor.d.ts +19 -10
  424. package/dist/src/vended-tools/file-editor/file-editor.d.ts.map +1 -1
  425. package/dist/src/vended-tools/file-editor/file-editor.js +188 -218
  426. package/dist/src/vended-tools/file-editor/file-editor.js.map +1 -1
  427. package/dist/src/vended-tools/file-editor/index.d.ts +2 -1
  428. package/dist/src/vended-tools/file-editor/index.d.ts.map +1 -1
  429. package/dist/src/vended-tools/file-editor/index.js +1 -1
  430. package/dist/src/vended-tools/file-editor/index.js.map +1 -1
  431. package/package.json +59 -6
  432. package/dist/src/utils/shell-quote.d.ts +0 -12
  433. package/dist/src/utils/shell-quote.d.ts.map +0 -1
  434. package/dist/src/utils/shell-quote.js +0 -14
  435. package/dist/src/utils/shell-quote.js.map +0 -1
@@ -1,26 +1,33 @@
1
1
  import { AgentResult, } from '../types/agent.js';
2
2
  import { BedrockModel } from '../models/bedrock.js';
3
3
  import { contentBlockFromData, Message, TextBlock, ToolResultBlock, ToolUseBlock, } from '../types/messages.js';
4
+ import { deepCopy } from '../types/json.js';
4
5
  import { McpClient } from '../mcp.js';
5
6
  import { isValidToolName } from '../tools/tool.js';
6
- import { systemPromptFromData } from '../types/messages.js';
7
+ import { cloneSystemPrompt, systemPromptFromData } from '../types/messages.js';
7
8
  import { normalizeError, ConcurrentInvocationError, StructuredOutputError } from '../errors.js';
8
9
  import { Model } from '../models/model.js';
9
10
  import { ModelPlugin } from '../plugins/model-plugin.js';
10
11
  import { isModelStreamEvent } from '../models/streaming.js';
11
12
  import { ToolRegistry } from '../registry/tool-registry.js';
12
13
  import { StateStore } from '../state-store.js';
14
+ import { serializeStateSerializable, loadStateSerializable } from '../types/serializable.js';
13
15
  import { AgentPrinter, getDefaultAppender } from './printer.js';
14
16
  import { InterventionRegistry } from '../interventions/registry.js';
15
17
  import { PluginRegistry } from '../plugins/registry.js';
16
18
  import { SlidingWindowConversationManager } from '../conversation-manager/sliding-window-conversation-manager.js';
19
+ import { SummarizingConversationManager } from '../conversation-manager/summarizing-conversation-manager.js';
17
20
  import { NullConversationManager } from '../conversation-manager/null-conversation-manager.js';
18
21
  import { ConversationManager } from '../conversation-manager/conversation-manager.js';
22
+ import { ContextOffloader } from '../vended-plugins/context-offloader/plugin.js';
23
+ import { InMemoryStorage } from '../vended-plugins/context-offloader/storage.js';
19
24
  import { HookRegistryImplementation } from '../hooks/registry.js';
25
+ import { MiddlewareRegistry, InvokeModelStage, ExecuteToolStage, AgentStreamStage } from '../middleware/index.js';
20
26
  import { InitializedEvent, AfterInvocationEvent, AfterModelCallEvent, AfterToolCallEvent, AfterToolsEvent, BeforeInvocationEvent, BeforeModelCallEvent, BeforeToolCallEvent, BeforeToolsEvent, HookableEvent, MessageAddedEvent, ModelStreamUpdateEvent, ContentBlockEvent, ModelMessageEvent, ToolResultEvent, AgentResultEvent, ToolStreamUpdateEvent, InterruptEvent, } from '../hooks/events.js';
21
27
  import { StructuredOutputTool, STRUCTURED_OUTPUT_TOOL_NAME } from '../tools/structured-output-tool.js';
22
28
  import { AgentAsTool } from './agent-as-tool.js';
23
29
  import { ToolCaller } from './tool-caller.js';
30
+ import { MemoryManager } from '../memory/memory-manager.js';
24
31
  import { SessionManager } from '../session/session-manager.js';
25
32
  import { Tracer } from '../telemetry/tracer.js';
26
33
  import { Meter } from '../telemetry/meter.js';
@@ -28,13 +35,83 @@ import { logger } from '../logging/logger.js';
28
35
  import { CancelledError } from '../errors.js';
29
36
  import { DefaultModelRetryStrategy } from '../retry/default-model-retry-strategy.js';
30
37
  import { warnOnDuplicateRetryStrategyTypes } from '../retry/retry-strategy.js';
31
- import { InterruptError, InterruptState, interruptFromAgent } from '../interrupt.js';
38
+ import { Interrupt, InterruptError, InterruptState, interruptFromAgent } from '../interrupt.js';
32
39
  import { isInterruptResponseContent } from '../types/interrupt.js';
33
40
  import { takeSnapshot as takeSnapshotInternal, loadSnapshot as loadSnapshotInternal } from './snapshot.js';
41
+ import { defaultSandbox } from '../sandbox/default.js';
42
+ import { summarizeContextTool, truncateContextTool, pinContextTool, createTokenUsageMiddleware, } from '../context-manager/modes/agentic/agentic-context.js';
43
+ /**
44
+ * Supported values for the `contextManager` parameter.
45
+ */
46
+ export const CONTEXT_MANAGER_STRATEGIES = ['auto', 'agentic'];
47
+ /** Benchmark-validated token threshold for offloading tool results. */
48
+ const CONTEXT_MANAGER_MAX_RESULT_TOKENS = 1_500;
49
+ /** Higher offload threshold for agentic mode — the model manages its own context, so we preserve more inline. */
50
+ const AGENTIC_CONTEXT_MANAGER_MAX_RESULT_TOKENS = 8_000;
51
+ /** Benchmark-validated preview token count for offloaded results. */
52
+ const CONTEXT_MANAGER_PREVIEW_TOKENS = 750;
53
+ /** Benchmark-validated ratio of messages to summarize on overflow. */
54
+ const CONTEXT_MANAGER_SUMMARY_RATIO = 0.3;
55
+ /** Benchmark-validated context window ratio that triggers proactive compression. */
56
+ const CONTEXT_MANAGER_COMPRESSION_THRESHOLD = 0.85;
57
+ /**
58
+ * Resolve the contextManager facade into a concrete ConversationManager.
59
+ *
60
+ * When contextManager is undefined, falls back to the default SlidingWindowConversationManager.
61
+ * When "auto", uses SummarizingConversationManager with proactive compression.
62
+ * When "agentic", uses SummarizingConversationManager without proactive compression
63
+ * (the agent manages its context via tools; the context manager is only a reactive safety net).
64
+ */
65
+ function resolveConversationManager(contextManager, conversationManager) {
66
+ if (contextManager === 'agentic') {
67
+ return (conversationManager ??
68
+ new SummarizingConversationManager({
69
+ summaryRatio: CONTEXT_MANAGER_SUMMARY_RATIO,
70
+ }));
71
+ }
72
+ if (contextManager === 'auto') {
73
+ return (conversationManager ??
74
+ new SummarizingConversationManager({
75
+ summaryRatio: CONTEXT_MANAGER_SUMMARY_RATIO,
76
+ proactiveCompression: { compressionThreshold: CONTEXT_MANAGER_COMPRESSION_THRESHOLD },
77
+ }));
78
+ }
79
+ if (contextManager !== undefined) {
80
+ throw new Error(`Unsupported contextManager value: "${contextManager}". Supported values: ${CONTEXT_MANAGER_STRATEGIES.map((s) => `"${s}"`).join(', ')}`);
81
+ }
82
+ return conversationManager ?? new SlidingWindowConversationManager({ windowSize: 40 });
83
+ }
34
84
  /** Default name assigned to agents when none is provided. */
35
85
  const DEFAULT_AGENT_NAME = 'Strands Agent';
36
86
  /** Default identifier assigned to agents when none is provided. */
37
87
  const DEFAULT_AGENT_ID = 'agent';
88
+ /**
89
+ * Creates a non-mutating interrupt function for middleware contexts.
90
+ * Reads existing responses from state (resume case) but never writes to it.
91
+ * On first run (no response), throws InterruptError with a locally-created Interrupt.
92
+ *
93
+ * @param interruptState - The agent's interrupt state (read-only access)
94
+ * @param idPrefix - Prefix for the interrupt ID (e.g., 'middleware:agentStream')
95
+ */
96
+ function createMiddlewareInterrupt(interruptState, idPrefix) {
97
+ return (params) => {
98
+ const interruptId = `${idPrefix}:${params.name}`;
99
+ const existing = interruptState.interrupts[interruptId];
100
+ if (existing?.response !== undefined) {
101
+ return { response: existing.response };
102
+ }
103
+ if (params.response !== undefined) {
104
+ return { response: params.response };
105
+ }
106
+ const interrupt = new Interrupt({
107
+ id: interruptId,
108
+ name: params.name,
109
+ ...(params.reason !== undefined && { reason: params.reason }),
110
+ source: 'middleware',
111
+ });
112
+ throw new InterruptError(interrupt);
113
+ };
114
+ }
38
115
  /**
39
116
  * Orchestrates the interaction between a model, a set of tools, and MCP clients.
40
117
  * The Agent is responsible for managing the lifecycle of tools and clients
@@ -81,7 +158,22 @@ export class Agent {
81
158
  * The session manager for saving and restoring agent sessions, if configured.
82
159
  */
83
160
  sessionManager;
161
+ /**
162
+ * The memory manager for cross-session memory retrieval and storage, if configured.
163
+ */
164
+ memoryManager;
165
+ _sandbox;
166
+ /**
167
+ * Execution environment for running commands, code, and file operations.
168
+ *
169
+ * @throws DefaultNotConfiguredError if no sandbox is configured for this
170
+ * environment (e.g. browsers, where no host default is registered).
171
+ */
172
+ get sandbox() {
173
+ return this._sandbox || defaultSandbox.get();
174
+ }
84
175
  _hooksRegistry;
176
+ _middlewareRegistry;
85
177
  _pluginRegistry;
86
178
  _interventionRegistry;
87
179
  _toolRegistry;
@@ -116,6 +208,13 @@ export class Agent {
116
208
  if (config?.description !== undefined)
117
209
  this.description = config.description;
118
210
  this.sessionManager = config?.sessionManager;
211
+ this.memoryManager =
212
+ config?.memoryManager instanceof MemoryManager
213
+ ? config.memoryManager
214
+ : config?.memoryManager
215
+ ? new MemoryManager(config.memoryManager)
216
+ : undefined;
217
+ this._sandbox = config?.sandbox;
119
218
  if (typeof config?.model === 'string') {
120
219
  this.model = new BedrockModel({ modelId: config.model });
121
220
  }
@@ -124,21 +223,28 @@ export class Agent {
124
223
  }
125
224
  // Validate and assign conversation manager
126
225
  if (this.model.stateful) {
127
- if (config?.conversationManager) {
128
- throw new Error('Cannot use a conversationManager with a stateful model. The model manages conversation state server-side.');
226
+ if (config?.conversationManager || config?.contextManager) {
227
+ throw new Error('contextManager and conversationManager cannot be used with a stateful model. The model manages conversation state server-side.');
129
228
  }
130
229
  this._conversationManager = new NullConversationManager();
131
230
  }
132
231
  else {
133
- this._conversationManager =
134
- config?.conversationManager ?? new SlidingWindowConversationManager({ windowSize: 40 });
232
+ this._conversationManager = resolveConversationManager(config?.contextManager, config?.conversationManager);
135
233
  }
136
234
  const { tools, mcpClients } = flattenTools(config?.tools ?? []);
235
+ if (config?.contextManager === 'agentic') {
236
+ tools.push(summarizeContextTool, truncateContextTool, pinContextTool);
237
+ }
137
238
  this._toolRegistry = new ToolRegistry(tools);
138
239
  this._mcpClients = mcpClients;
139
240
  // Initialize hooks registry
140
241
  this._hooksRegistry = new HookRegistryImplementation();
141
242
  this._interventionRegistry = new InterventionRegistry(config?.interventions ?? [], this._hooksRegistry);
243
+ // Initialize middleware registry
244
+ this._middlewareRegistry = new MiddlewareRegistry();
245
+ if (config?.contextManager === 'agentic') {
246
+ this._middlewareRegistry.addInput(InvokeModelStage.Input, createTokenUsageMiddleware(this.model));
247
+ }
142
248
  // `undefined` (omitted) → install the default; `null`/`[]` → explicit opt-out.
143
249
  const retryStrategies = config?.retryStrategy === null
144
250
  ? []
@@ -156,10 +262,23 @@ export class Agent {
156
262
  // - Retry-strategy ordering is not load-bearing for correctness: `DefaultModelRetryStrategy`
157
263
  // guards on `event.retry`, so a user hook that already set it short-circuits
158
264
  // the strategy regardless of registration order.
265
+ const hasOffloader = (config?.plugins ?? []).some((p) => p.name === 'strands:context-offloader');
159
266
  this._pluginRegistry = new PluginRegistry([
160
267
  this._conversationManager,
161
268
  ...retryStrategies,
162
269
  ...(config?.plugins ?? []),
270
+ ...((config?.contextManager === 'auto' || config?.contextManager === 'agentic') && !hasOffloader
271
+ ? [
272
+ new ContextOffloader({
273
+ storage: new InMemoryStorage(),
274
+ maxResultTokens: config?.contextManager === 'agentic'
275
+ ? AGENTIC_CONTEXT_MANAGER_MAX_RESULT_TOKENS
276
+ : CONTEXT_MANAGER_MAX_RESULT_TOKENS,
277
+ previewTokens: CONTEXT_MANAGER_PREVIEW_TOKENS,
278
+ }),
279
+ ]
280
+ : []),
281
+ ...(this.memoryManager ? [this.memoryManager] : []),
163
282
  ...(config?.sessionManager ? [config.sessionManager] : []),
164
283
  new ModelPlugin(this.model),
165
284
  ]);
@@ -208,6 +327,33 @@ export class Agent {
208
327
  addHook(eventType, callback, options) {
209
328
  return this._hooksRegistry.addCallback(eventType, callback, options);
210
329
  }
330
+ addMiddleware(stageOrPhase, handler) {
331
+ if ('_phase' in stageOrPhase) {
332
+ const phase = stageOrPhase;
333
+ const stage = phase._stage;
334
+ switch (phase._phase) {
335
+ case 'input': {
336
+ const adapted = this._middlewareRegistry.addInput(stageOrPhase, handler);
337
+ return () => this._middlewareRegistry.remove(stage, adapted);
338
+ }
339
+ case 'output': {
340
+ const adapted = this._middlewareRegistry.addOutput(stageOrPhase, handler);
341
+ return () => this._middlewareRegistry.remove(stage, adapted);
342
+ }
343
+ case 'wrap': {
344
+ const wrapHandler = handler;
345
+ this._middlewareRegistry.add(stage, wrapHandler);
346
+ return () => this._middlewareRegistry.remove(stage, wrapHandler);
347
+ }
348
+ default:
349
+ throw new Error(`Unknown middleware phase: ${phase._phase}`);
350
+ }
351
+ }
352
+ const stage = stageOrPhase;
353
+ const wrapHandler = handler;
354
+ this._middlewareRegistry.add(stage, wrapHandler);
355
+ return () => this._middlewareRegistry.remove(stage, wrapHandler);
356
+ }
211
357
  async initialize() {
212
358
  if (this._initialized) {
213
359
  return;
@@ -221,6 +367,18 @@ export class Agent {
221
367
  this._toolRegistry.addOrReplace(newTools);
222
368
  };
223
369
  }));
370
+ // Register tools vended by the sandbox. The host default vends nothing. A tool
371
+ // is skipped if the user already registered one with that name.
372
+ if (this._sandbox) {
373
+ for (const sandboxTool of this._sandbox.getTools()) {
374
+ if (this._toolRegistry.get(sandboxTool.name)) {
375
+ logger.debug(`tool_name=<${sandboxTool.name}> | sandbox-vended tool skipped, user already registered a tool with this name`);
376
+ }
377
+ else {
378
+ this._toolRegistry.add(sandboxTool);
379
+ }
380
+ }
381
+ }
224
382
  await this._pluginRegistry.initialize(this);
225
383
  for (const handler of this._interventionRegistry.handlers) {
226
384
  const observer = handler;
@@ -454,90 +612,183 @@ export class Agent {
454
612
  this.acquireLock();
455
613
  try {
456
614
  await this.initialize();
615
+ // Thread the resolved invocationState so all layers share the same reference.
616
+ const invocationState = options?.invocationState ?? {};
617
+ const resolvedOptions = options?.invocationState ? options : { ...options, invocationState };
457
618
  let currentArgs = args;
458
- // Outer loop: re-enters _stream when a hook sets AfterInvocationEvent.resume.
459
- // One invocation lock spans the whole resume chain.
460
619
  while (true) {
461
- // Fresh AbortController per invocation iteration, composed with any external signal.
620
+ // Fresh AbortController per iteration, composed with any external signal.
462
621
  this._abortController = new AbortController();
463
- this._abortSignal = options?.cancelSignal
464
- ? AbortSignal.any([this._abortController.signal, options.cancelSignal])
622
+ this._abortSignal = resolvedOptions?.cancelSignal
623
+ ? AbortSignal.any([this._abortController.signal, resolvedOptions.cancelSignal])
465
624
  : this._abortController.signal;
466
- const streamGenerator = this._stream(currentArgs, options);
625
+ // Process interrupt responses before middleware runs so context.interrupt() can find them
626
+ const interruptResponses = this._extractInterruptResponses(currentArgs);
627
+ if (interruptResponses.length > 0) {
628
+ this._interruptState.resume(interruptResponses);
629
+ }
630
+ // Hooks fire outside middleware — always, even on short-circuit.
631
+ const beforeInvocationEvent = new BeforeInvocationEvent({ agent: this, invocationState });
632
+ yield await this._invokeCallbacks(beforeInvocationEvent);
633
+ if (beforeInvocationEvent.cancel) {
634
+ const cancelText = typeof beforeInvocationEvent.cancel === 'string'
635
+ ? beforeInvocationEvent.cancel
636
+ : 'invocation denied by hook';
637
+ const message = new Message({ role: 'assistant', content: [new TextBlock(cancelText)] });
638
+ yield this._appendMessage(message, invocationState);
639
+ const afterEvent = new AfterInvocationEvent({ agent: this, invocationState });
640
+ await this._invokeCallbacks(afterEvent);
641
+ yield afterEvent;
642
+ return new AgentResult({
643
+ stopReason: 'endTurn',
644
+ lastMessage: message,
645
+ traces: this._tracer.localTraces,
646
+ metrics: this._meter.metrics,
647
+ invocationState,
648
+ });
649
+ }
650
+ let result;
467
651
  let caughtError;
468
- let lastAfterInvocation;
469
- let iterationResult;
652
+ const afterInvocationEvent = new AfterInvocationEvent({ agent: this, invocationState });
470
653
  try {
471
- iterationResult = await streamGenerator.next();
472
- while (!iterationResult.done) {
473
- try {
474
- const processed = await this._invokeCallbacks(iterationResult.value);
475
- if (processed instanceof AfterInvocationEvent) {
476
- lastAfterInvocation = processed;
477
- }
478
- yield processed;
479
- iterationResult = await streamGenerator.next();
480
- }
481
- catch (error) {
482
- // Throw interrupt errors back into _stream so executeTools can store the
483
- // assistant message as pending execution state for resume.
484
- if (error instanceof InterruptError) {
485
- iterationResult = await streamGenerator.throw(error);
486
- }
487
- else {
488
- throw error;
489
- }
490
- }
491
- }
492
- // Suppress AgentResultEvent for resumed iterations — only the final
493
- // invocation in a resume chain reports an agent result.
494
- if (lastAfterInvocation?.resume === undefined) {
495
- yield await this._invokeCallbacks(new AgentResultEvent({
496
- agent: this,
497
- result: iterationResult.value,
498
- invocationState: iterationResult.value.invocationState,
499
- }));
500
- }
654
+ result = yield* this._streamWithMiddleware(currentArgs, resolvedOptions, invocationState);
501
655
  }
502
656
  catch (error) {
503
657
  caughtError = error;
504
- throw error;
505
658
  }
506
659
  finally {
507
- // Drain _stream() so cleanup hooks and printer still fire.
508
- // Yield only on error (consumer may still be iterating); on a consumer
509
- // break, yielding would suspend the generator and leak the lock.
510
- let drainResult = await streamGenerator.return(undefined);
511
- while (!drainResult.done) {
512
- try {
513
- if (caughtError) {
514
- yield await this._invokeCallbacks(drainResult.value);
515
- }
516
- else {
517
- await this._invokeCallbacks(drainResult.value);
518
- }
519
- }
520
- catch (error) {
521
- logger.warn(`event_type=<${drainResult.value.type}>, error=<${error}> | error invoking callbacks during cleanup`);
522
- }
523
- drainResult = await streamGenerator.next();
524
- }
525
- // Reset controller and signal for next iteration / invocation
526
- this._abortController = new AbortController();
527
- this._abortSignal = this._abortController.signal;
660
+ // AfterInvocationEvent always fires even on error or consumer break. Outside middleware.
661
+ // Invoke hooks (so .resume can be set) but don't yield in finally (yields in finally
662
+ // suspend the generator on consumer break instead of completing cleanup).
663
+ await this._invokeCallbacks(afterInvocationEvent);
664
+ }
665
+ // Yield outside finally — in JS, a `yield` inside `finally` suspends the generator
666
+ // mid-cleanup when the consumer breaks, preventing subsequent cleanup code from running.
667
+ // This line is only reached on normal completion or caught error, never on consumer break.
668
+ yield afterInvocationEvent;
669
+ // Re-throw after hooks have fired
670
+ if (caughtError) {
671
+ throw caughtError;
528
672
  }
529
673
  // Resume only on a clean invocation — errors propagate above.
530
- if (lastAfterInvocation?.resume !== undefined) {
531
- currentArgs = lastAfterInvocation.resume;
674
+ if (afterInvocationEvent.resume !== undefined) {
675
+ currentArgs = afterInvocationEvent.resume;
532
676
  continue;
533
677
  }
534
- return iterationResult.value;
678
+ // Only emit AgentResultEvent on the final iteration (not on resumed ones).
679
+ yield await this._invokeCallbacks(new AgentResultEvent({
680
+ agent: this,
681
+ result: result,
682
+ invocationState,
683
+ }));
684
+ return result;
535
685
  }
536
686
  }
537
687
  finally {
538
688
  this._isInvoking = false;
539
689
  }
540
690
  }
691
+ /**
692
+ * Invokes the AgentStreamStage middleware chain.
693
+ * Hooks fire outside this method (in stream()'s resume loop).
694
+ */
695
+ async *_streamWithMiddleware(args, options, invocationState) {
696
+ const context = {
697
+ agent: this,
698
+ args,
699
+ ...(options !== undefined && { options }),
700
+ interrupt: createMiddlewareInterrupt(this._interruptState, 'middleware:agentStream'),
701
+ };
702
+ // async function* doesn't bind lexical `this`; capture for the terminal callback.
703
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
704
+ const self = this;
705
+ try {
706
+ const { result } = yield* this._middlewareRegistry.invoke(AgentStreamStage, context, async function* (ctx) {
707
+ const result = yield* self._streamCore(ctx.args, ctx.options);
708
+ return { result };
709
+ });
710
+ return result;
711
+ }
712
+ catch (error) {
713
+ if (error instanceof InterruptError) {
714
+ for (const interrupt of error.interrupts) {
715
+ this._interruptState.registerInterrupt(interrupt);
716
+ }
717
+ this._interruptState.activate();
718
+ for (const interrupt of error.interrupts) {
719
+ yield new InterruptEvent({ agent: this, interrupt, invocationState });
720
+ }
721
+ return new AgentResult({
722
+ stopReason: 'interrupt',
723
+ lastMessage: this.messages.length > 0
724
+ ? this.messages[this.messages.length - 1]
725
+ : new Message({ role: 'assistant', content: [new TextBlock('Interrupted')] }),
726
+ traces: this._tracer.localTraces,
727
+ metrics: this._meter.metrics,
728
+ interrupts: this._interruptState.getUnansweredInterrupts(),
729
+ invocationState,
730
+ });
731
+ }
732
+ throw error;
733
+ }
734
+ }
735
+ /**
736
+ * Single-pass stream through _stream() with event processing.
737
+ * No resume loop, no lifecycle events — those are handled by stream()'s resume loop.
738
+ */
739
+ async *_streamCore(args, options) {
740
+ const streamGenerator = this._stream(args, options);
741
+ let caughtError;
742
+ let iterationResult;
743
+ try {
744
+ iterationResult = await streamGenerator.next();
745
+ while (!iterationResult.done) {
746
+ try {
747
+ const processed = await this._invokeCallbacks(iterationResult.value);
748
+ yield processed;
749
+ iterationResult = await streamGenerator.next();
750
+ }
751
+ catch (error) {
752
+ // Throw interrupt errors back into _stream so executeTools can store the
753
+ // assistant message as pending execution state for resume.
754
+ if (error instanceof InterruptError) {
755
+ iterationResult = await streamGenerator.throw(error);
756
+ }
757
+ else {
758
+ throw error;
759
+ }
760
+ }
761
+ }
762
+ }
763
+ catch (error) {
764
+ caughtError = error;
765
+ throw error;
766
+ }
767
+ finally {
768
+ // Drain _stream() so cleanup hooks and printer still fire.
769
+ // Yield only on error (consumer may still be iterating); on a consumer
770
+ // break, yielding would suspend the generator and leak the lock.
771
+ let drainResult = await streamGenerator.return(undefined);
772
+ while (!drainResult.done) {
773
+ try {
774
+ if (caughtError) {
775
+ yield await this._invokeCallbacks(drainResult.value);
776
+ }
777
+ else {
778
+ await this._invokeCallbacks(drainResult.value);
779
+ }
780
+ }
781
+ catch (error) {
782
+ logger.warn(`event_type=<${drainResult.value.type}>, error=<${error}> | error invoking callbacks during cleanup`);
783
+ }
784
+ drainResult = await streamGenerator.next();
785
+ }
786
+ // Reset controller and signal for next iteration / invocation
787
+ this._abortController = new AbortController();
788
+ this._abortSignal = this._abortController.signal;
789
+ }
790
+ return iterationResult.value;
791
+ }
541
792
  /**
542
793
  * Returns a {@link Tool} that wraps this agent, allowing it to be used
543
794
  * as a tool by another agent.
@@ -661,30 +912,14 @@ export class Agent {
661
912
  // AgentResult. Mutations by hooks/tools are visible across all recursive
662
913
  // agent loop cycles within this invocation.
663
914
  const invocationState = options?.invocationState ?? {};
664
- // Handle interrupt responses if present in input
915
+ // Interrupt responses are already consumed in stream() before middleware
916
+ // runs (so middleware-level interrupt() can find them). Re-extract here
917
+ // to gate the "non-interrupt input while interrupted" check below.
665
918
  const interruptResponses = this._extractInterruptResponses(args);
666
- if (interruptResponses.length > 0) {
667
- this._interruptState.resume(interruptResponses);
668
- }
669
919
  // Reject non-interrupt input while in interrupted state
670
920
  if (this._interruptState.activated && interruptResponses.length === 0) {
671
921
  throw new TypeError('Agent is in an interrupted state. Resume by invoking with interruptResponse content blocks.');
672
922
  }
673
- const beforeInvocationEvent = new BeforeInvocationEvent({ agent: this, invocationState });
674
- yield beforeInvocationEvent;
675
- if (beforeInvocationEvent.cancel) {
676
- const cancelText = typeof beforeInvocationEvent.cancel === 'string' ? beforeInvocationEvent.cancel : 'invocation denied by hook';
677
- const message = new Message({ role: 'assistant', content: [new TextBlock(cancelText)] });
678
- yield this._appendMessage(message, invocationState);
679
- yield new AfterInvocationEvent({ agent: this, invocationState });
680
- return new AgentResult({
681
- stopReason: 'endTurn',
682
- lastMessage: message,
683
- traces: this._tracer.localTraces,
684
- metrics: this._meter.metrics,
685
- invocationState,
686
- });
687
- }
688
923
  // Normalize input to get the user messages for telemetry
689
924
  const inputMessages = this._normalizeInput(args);
690
925
  // Start agent trace span
@@ -884,6 +1119,11 @@ export class Agent {
884
1119
  return result;
885
1120
  }
886
1121
  if (error instanceof InterruptError) {
1122
+ // Handles interrupts from tools/hooks that propagated up through the agent loop.
1123
+ // AgentStreamStage middleware interrupts are caught separately in _streamWithMiddleware().
1124
+ for (const interrupt of error.interrupts) {
1125
+ this._interruptState.registerInterrupt(interrupt);
1126
+ }
887
1127
  // Fan out one event per interrupt. Each event exposes `interrupt.source` so
888
1128
  // consumers can filter by origin (tool callback vs hook callback) without
889
1129
  // subscribing to separate event types.
@@ -917,8 +1157,6 @@ export class Agent {
917
1157
  if (structuredOutputTool) {
918
1158
  this._toolRegistry.remove(STRUCTURED_OUTPUT_TOOL_NAME);
919
1159
  }
920
- // Always emit final event
921
- yield new AfterInvocationEvent({ agent: this, invocationState });
922
1160
  }
923
1161
  }
924
1162
  /**
@@ -1095,26 +1333,10 @@ export class Agent {
1095
1333
  }
1096
1334
  return { message, stopReason: 'endTurn' };
1097
1335
  }
1098
- // Start model span within loop span context
1099
- const modelId = this.model.modelId;
1100
- const modelSpan = this._tracer.startModelInvokeSpan({
1101
- messages: this.messages,
1102
- ...(modelId && { modelId }),
1103
- ...(this.systemPrompt !== undefined && { systemPrompt: this.systemPrompt }),
1104
- });
1105
1336
  try {
1106
- const result = yield* this._streamFromModel(this.messages, streamOptions, invocationState);
1337
+ const result = yield* this._invokeModelWithMiddleware(invocationState, toolChoice, projectedInputTokens);
1107
1338
  // Accumulate token usage and model latency metrics
1108
1339
  this._meter.updateCycle(result.metadata);
1109
- // End model span with usage
1110
- const usage = result.metadata?.usage;
1111
- const metrics = result.metadata?.metrics;
1112
- this._tracer.endModelInvokeSpan(modelSpan, {
1113
- output: result.message,
1114
- stopReason: result.stopReason,
1115
- ...(usage && { usage }),
1116
- ...(metrics && { metrics }),
1117
- });
1118
1340
  yield new ModelMessageEvent({
1119
1341
  agent: this,
1120
1342
  message: result.message,
@@ -1146,8 +1368,6 @@ export class Agent {
1146
1368
  }
1147
1369
  catch (error) {
1148
1370
  const modelError = normalizeError(error);
1149
- // End model span with error
1150
- this._tracer.endModelInvokeSpan(modelSpan, { error: modelError });
1151
1371
  // Create error event
1152
1372
  const errorEvent = new AfterModelCallEvent({
1153
1373
  agent: this,
@@ -1173,6 +1393,80 @@ export class Agent {
1173
1393
  }
1174
1394
  }
1175
1395
  }
1396
+ /**
1397
+ * Invokes the model through the InvokeModelStage middleware chain.
1398
+ * Builds an InvokeModelContext from current agent state and composes the
1399
+ * middleware chain with a terminal function that calls _streamFromModel
1400
+ * using context fields directly (not re-derived from the agent).
1401
+ *
1402
+ * @param invocationState - Per-invocation state shared across hooks and tools
1403
+ * @param toolChoice - Optional tool choice to force specific tool usage
1404
+ * @returns StreamAggregatedResult from the model (or middleware short-circuit)
1405
+ */
1406
+ async *_invokeModelWithMiddleware(invocationState, toolChoice, projectedInputTokens) {
1407
+ const context = {
1408
+ agent: this,
1409
+ messages: this.messages.map((msg) => msg.clone()),
1410
+ ...(this.systemPrompt !== undefined && { systemPrompt: cloneSystemPrompt(this.systemPrompt) }),
1411
+ toolSpecs: deepCopy(this._toolRegistry.list().map((tool) => tool.toolSpec)),
1412
+ ...(toolChoice !== undefined && { toolChoice: deepCopy(toolChoice) }),
1413
+ invocationState,
1414
+ ...(projectedInputTokens !== undefined && { projectedInputTokens }),
1415
+ };
1416
+ // Snapshot model state before middleware runs so concurrent mutations don't leak in.
1417
+ // The writeback happens after the entire middleware chain completes, so middleware
1418
+ // cannot affect modelState at any point (before or after next()).
1419
+ const modelStateSnapshot = this.modelState.getAll();
1420
+ let tempModelState;
1421
+ // async function* doesn't bind lexical `this`; capture for the terminal callback.
1422
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
1423
+ const self = this;
1424
+ const middlewareResult = yield* this._middlewareRegistry.invoke(InvokeModelStage, context, async function* (ctx) {
1425
+ const modelId = self.model.modelId;
1426
+ const modelSpan = self._tracer.startModelInvokeSpan({
1427
+ messages: ctx.messages,
1428
+ ...(modelId && { modelId }),
1429
+ ...(ctx.systemPrompt !== undefined && { systemPrompt: ctx.systemPrompt }),
1430
+ });
1431
+ try {
1432
+ // Wrap the snapshot into a StateStore for the model provider, which expects
1433
+ // get/set methods.
1434
+ tempModelState = new StateStore(modelStateSnapshot);
1435
+ const streamOptions = {
1436
+ toolSpecs: ctx.toolSpecs,
1437
+ modelState: tempModelState,
1438
+ ...(ctx.systemPrompt !== undefined && { systemPrompt: ctx.systemPrompt }),
1439
+ ...(ctx.toolChoice && { toolChoice: ctx.toolChoice }),
1440
+ };
1441
+ const gen = self._streamFromModel(ctx.messages, streamOptions, ctx.invocationState);
1442
+ let iterResult = await gen.next();
1443
+ while (!iterResult.done) {
1444
+ yield iterResult.value;
1445
+ iterResult = await gen.next();
1446
+ }
1447
+ const usage = iterResult.value.metadata?.usage;
1448
+ const metrics = iterResult.value.metadata?.metrics;
1449
+ self._tracer.endModelInvokeSpan(modelSpan, {
1450
+ output: iterResult.value.message,
1451
+ stopReason: iterResult.value.stopReason,
1452
+ ...(usage && { usage }),
1453
+ ...(metrics && { metrics }),
1454
+ });
1455
+ return { result: iterResult.value };
1456
+ }
1457
+ catch (error) {
1458
+ self._tracer.endModelInvokeSpan(modelSpan, { error: normalizeError(error) });
1459
+ throw error;
1460
+ }
1461
+ });
1462
+ // Sync model state after the entire middleware chain has completed, so no
1463
+ // middleware mutation to agent.modelState (before or after next()) takes effect.
1464
+ // Intentionally skipped on error — partial provider writes should not persist.
1465
+ if (tempModelState) {
1466
+ loadStateSerializable(this.modelState, serializeStateSerializable(tempModelState));
1467
+ }
1468
+ return middlewareResult.result;
1469
+ }
1176
1470
  /**
1177
1471
  * Streams events from the model and dispatches appropriate events for each.
1178
1472
  *
@@ -1529,86 +1823,9 @@ export class Agent {
1529
1823
  }
1530
1824
  return afterToolCallEvent.result;
1531
1825
  }
1532
- // Start tool span within loop span context
1533
- const toolSpan = this._tracer.startToolCallSpan({
1534
- tool: toolUse,
1535
- });
1536
- // Track tool execution time for metrics
1537
- const toolStartTime = Date.now();
1538
- let toolResult;
1539
- let error;
1540
- if (!effectiveTool) {
1541
- // Tool not found
1542
- toolResult = new ToolResultBlock({
1543
- toolUseId: toolUse.toolUseId,
1544
- status: 'error',
1545
- content: [new TextBlock(`Tool '${toolUse.name}' not found in registry`)],
1546
- });
1547
- }
1548
- else {
1549
- // Execute tool within the tool span context
1550
- const toolContext = {
1551
- toolUse: {
1552
- name: toolUse.name,
1553
- toolUseId: toolUse.toolUseId,
1554
- input: toolUse.input,
1555
- },
1556
- agent: this,
1557
- invocationState,
1558
- interrupt: (params) => {
1559
- return interruptFromAgent(this, `tool:${toolUseBlock.toolUseId}:${params.name}`, params, 'tool');
1560
- },
1561
- };
1562
- try {
1563
- // Manually iterate tool stream to wrap each ToolStreamEvent in ToolStreamUpdateEvent.
1564
- // This keeps the tool authoring interface unchanged — tools construct ToolStreamEvent
1565
- // without knowledge of agents or hooks, and we wrap at the boundary.
1566
- // Tool execution is ran within the tool span's context so that
1567
- // downstream calls (e.g., MCP clients) can propagate trace context
1568
- const toolGenerator = this._tracer.withSpanContext(toolSpan, () => effectiveTool.stream(toolContext));
1569
- let toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
1570
- while (!toolNext.done) {
1571
- yield new ToolStreamUpdateEvent({ agent: this, event: toolNext.value, invocationState });
1572
- toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
1573
- }
1574
- const result = toolNext.value;
1575
- if (!result) {
1576
- // Tool didn't return a result
1577
- toolResult = new ToolResultBlock({
1578
- toolUseId: toolUse.toolUseId,
1579
- status: 'error',
1580
- content: [new TextBlock(`Tool '${toolUse.name}' did not return a result`)],
1581
- });
1582
- }
1583
- else {
1584
- toolResult = result;
1585
- error = result.error;
1586
- }
1587
- }
1588
- catch (e) {
1589
- // Re-throw InterruptError to allow interrupt handling
1590
- if (e instanceof InterruptError) {
1591
- throw e;
1592
- }
1593
- // Tool execution failed with error
1594
- error = normalizeError(e);
1595
- toolResult = new ToolResultBlock({
1596
- toolUseId: toolUse.toolUseId,
1597
- status: 'error',
1598
- content: [new TextBlock(error.message)],
1599
- error,
1600
- });
1601
- }
1602
- }
1603
- // End tool span with the raw tool result — telemetry reflects what the
1604
- // tool actually returned, independent of AfterToolCallEvent mutations.
1605
- this._tracer.endToolCallSpan(toolSpan, { toolResult, ...(error && { error }) });
1606
- // End tool metrics tracking
1607
- this._meter.endToolCall({
1608
- tool: toolUse,
1609
- duration: Date.now() - toolStartTime,
1610
- success: toolResult.status === 'success',
1611
- });
1826
+ // Execute tool core logic through middleware chain
1827
+ const toolResult = yield* this._executeToolWithMiddleware(effectiveTool, toolUse, invocationState);
1828
+ const error = toolResult.error;
1612
1829
  // Single point for AfterToolCallEvent
1613
1830
  const afterToolCallEvent = new AfterToolCallEvent({
1614
1831
  agent: this,
@@ -1627,6 +1844,106 @@ export class Agent {
1627
1844
  return afterToolCallEvent.result;
1628
1845
  }
1629
1846
  }
1847
+ async *_executeToolWithMiddleware(tool, toolUse, invocationState) {
1848
+ const context = {
1849
+ agent: this,
1850
+ tool,
1851
+ toolUse: deepCopy(toolUse),
1852
+ invocationState,
1853
+ interrupt: createMiddlewareInterrupt(this._interruptState, `middleware:executeTool:${toolUse.toolUseId}`),
1854
+ };
1855
+ // async function* doesn't bind lexical `this`; capture for the terminal callback.
1856
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
1857
+ const self = this;
1858
+ const middlewareResult = yield* this._middlewareRegistry.invoke(ExecuteToolStage, context, async function* (ctx) {
1859
+ const result = yield* self._executeToolCore(ctx.tool, ctx.toolUse, ctx.invocationState);
1860
+ return { result };
1861
+ });
1862
+ return middlewareResult.result;
1863
+ }
1864
+ async *_executeToolCore(effectiveTool, toolUse, invocationState) {
1865
+ // Start tool span within loop span context
1866
+ const toolSpan = this._tracer.startToolCallSpan({
1867
+ tool: toolUse,
1868
+ });
1869
+ // Track tool execution time for metrics
1870
+ const toolStartTime = Date.now();
1871
+ let toolResult;
1872
+ let error;
1873
+ if (!effectiveTool) {
1874
+ // Tool not found
1875
+ toolResult = new ToolResultBlock({
1876
+ toolUseId: toolUse.toolUseId,
1877
+ status: 'error',
1878
+ content: [new TextBlock(`Tool '${toolUse.name}' not found in registry`)],
1879
+ });
1880
+ }
1881
+ else {
1882
+ // Execute tool within the tool span context
1883
+ const toolContext = {
1884
+ toolUse: {
1885
+ name: toolUse.name,
1886
+ toolUseId: toolUse.toolUseId,
1887
+ input: toolUse.input,
1888
+ },
1889
+ agent: this,
1890
+ invocationState,
1891
+ interrupt: (params) => {
1892
+ return interruptFromAgent(this, `tool:${toolUse.toolUseId}:${params.name}`, params, 'tool');
1893
+ },
1894
+ };
1895
+ try {
1896
+ // Manually iterate tool stream to wrap each ToolStreamEvent in ToolStreamUpdateEvent.
1897
+ // This keeps the tool authoring interface unchanged — tools construct ToolStreamEvent
1898
+ // without knowledge of agents or hooks, and we wrap at the boundary.
1899
+ // Tool execution is ran within the tool span's context so that
1900
+ // downstream calls (e.g., MCP clients) can propagate trace context
1901
+ const toolGenerator = this._tracer.withSpanContext(toolSpan, () => effectiveTool.stream(toolContext));
1902
+ let toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
1903
+ while (!toolNext.done) {
1904
+ yield new ToolStreamUpdateEvent({ agent: this, event: toolNext.value, invocationState });
1905
+ toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
1906
+ }
1907
+ const result = toolNext.value;
1908
+ if (!result) {
1909
+ // Tool didn't return a result
1910
+ toolResult = new ToolResultBlock({
1911
+ toolUseId: toolUse.toolUseId,
1912
+ status: 'error',
1913
+ content: [new TextBlock(`Tool '${toolUse.name}' did not return a result`)],
1914
+ });
1915
+ }
1916
+ else {
1917
+ toolResult = result;
1918
+ error = result.error;
1919
+ }
1920
+ }
1921
+ catch (e) {
1922
+ // Re-throw InterruptError to allow interrupt handling
1923
+ if (e instanceof InterruptError) {
1924
+ throw e;
1925
+ }
1926
+ // Tool execution failed with error
1927
+ error = normalizeError(e);
1928
+ toolResult = new ToolResultBlock({
1929
+ toolUseId: toolUse.toolUseId,
1930
+ status: 'error',
1931
+ content: [new TextBlock(error.message)],
1932
+ error,
1933
+ });
1934
+ }
1935
+ }
1936
+ // End tool span with the raw tool result — telemetry reflects what the
1937
+ // tool actually returned, independent of AfterToolCallEvent mutations.
1938
+ this._tracer.endToolCallSpan(toolSpan, { toolResult, ...(error && { error }) });
1939
+ // End tool metrics tracking
1940
+ this._meter.endToolCall({
1941
+ tool: toolUse,
1942
+ duration: Date.now() - toolStartTime,
1943
+ success: toolResult.status === 'success',
1944
+ });
1945
+ return toolResult;
1946
+ }
1630
1947
  /**
1631
1948
  * Redacts the last message in the conversation history.
1632
1949
  * Called when guardrails block user input and redaction is enabled.