@strands-agents/sdk 1.7.0 → 1.9.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 (686) hide show
  1. package/dist/src/agent/agent.d.ts +32 -2
  2. package/dist/src/agent/agent.d.ts.map +1 -1
  3. package/dist/src/agent/agent.js +92 -4
  4. package/dist/src/agent/agent.js.map +1 -1
  5. package/dist/src/context-manager/modes/agentic/agentic-context.d.ts +3 -3
  6. package/dist/src/context-manager/modes/agentic/agentic-context.d.ts.map +1 -1
  7. package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts.map +1 -1
  8. package/dist/src/conversation-manager/sliding-window-conversation-manager.js +2 -0
  9. package/dist/src/conversation-manager/sliding-window-conversation-manager.js.map +1 -1
  10. package/dist/src/errors.d.ts +7 -0
  11. package/dist/src/errors.d.ts.map +1 -1
  12. package/dist/src/errors.js +10 -0
  13. package/dist/src/errors.js.map +1 -1
  14. package/dist/src/experimental/checkpoint.d.ts +118 -0
  15. package/dist/src/experimental/checkpoint.d.ts.map +1 -0
  16. package/dist/src/experimental/checkpoint.js +108 -0
  17. package/dist/src/experimental/checkpoint.js.map +1 -0
  18. package/dist/src/experimental/index.d.ts +10 -0
  19. package/dist/src/experimental/index.d.ts.map +1 -0
  20. package/dist/src/experimental/index.js +9 -0
  21. package/dist/src/experimental/index.js.map +1 -0
  22. package/dist/src/index.d.ts +1 -1
  23. package/dist/src/index.d.ts.map +1 -1
  24. package/dist/src/index.js +1 -1
  25. package/dist/src/index.js.map +1 -1
  26. package/dist/src/index.node.d.ts.map +1 -1
  27. package/dist/src/index.node.js +3 -0
  28. package/dist/src/index.node.js.map +1 -1
  29. package/dist/src/injection/message-injection.d.ts.map +1 -1
  30. package/dist/src/injection/message-injection.js +2 -0
  31. package/dist/src/injection/message-injection.js.map +1 -1
  32. package/dist/src/interventions/actions.d.ts.map +1 -1
  33. package/dist/src/interventions/actions.js.map +1 -1
  34. package/dist/src/{mcp.d.ts → mcp/client.d.ts} +13 -4
  35. package/dist/src/mcp/client.d.ts.map +1 -0
  36. package/dist/src/{mcp.js → mcp/client.js} +15 -3
  37. package/dist/src/mcp/client.js.map +1 -0
  38. package/dist/src/mcp/config.d.ts +52 -0
  39. package/dist/src/mcp/config.d.ts.map +1 -0
  40. package/dist/src/mcp/config.js +12 -0
  41. package/dist/src/mcp/config.js.map +1 -0
  42. package/dist/src/mcp/config.node.d.ts +16 -0
  43. package/dist/src/mcp/config.node.d.ts.map +1 -0
  44. package/dist/src/mcp/config.node.js +145 -0
  45. package/dist/src/mcp/config.node.js.map +1 -0
  46. package/dist/src/mcp/index.d.ts +3 -0
  47. package/dist/src/mcp/index.d.ts.map +1 -0
  48. package/dist/src/mcp/index.js +2 -0
  49. package/dist/src/mcp/index.js.map +1 -0
  50. package/dist/src/models/model.d.ts.map +1 -1
  51. package/dist/src/models/model.js +2 -1
  52. package/dist/src/models/model.js.map +1 -1
  53. package/dist/src/multiagent/graph.d.ts +7 -0
  54. package/dist/src/multiagent/graph.d.ts.map +1 -1
  55. package/dist/src/multiagent/graph.js +22 -1
  56. package/dist/src/multiagent/graph.js.map +1 -1
  57. package/dist/src/multiagent/multiagent.d.ts +2 -1
  58. package/dist/src/multiagent/multiagent.d.ts.map +1 -1
  59. package/dist/src/multiagent/multiagent.js.map +1 -1
  60. package/dist/src/multiagent/nodes.d.ts +5 -0
  61. package/dist/src/multiagent/nodes.d.ts.map +1 -1
  62. package/dist/src/multiagent/nodes.js +15 -0
  63. package/dist/src/multiagent/nodes.js.map +1 -1
  64. package/dist/src/multiagent/state.d.ts.map +1 -1
  65. package/dist/src/multiagent/state.js.map +1 -1
  66. package/dist/src/tools/function-tool.d.ts +1 -1
  67. package/dist/src/tools/function-tool.d.ts.map +1 -1
  68. package/dist/src/tools/function-tool.js +4 -12
  69. package/dist/src/tools/function-tool.js.map +1 -1
  70. package/dist/src/tools/mcp-tool.d.ts +2 -1
  71. package/dist/src/tools/mcp-tool.d.ts.map +1 -1
  72. package/dist/src/tools/mcp-tool.js +1 -0
  73. package/dist/src/tools/mcp-tool.js.map +1 -1
  74. package/dist/src/tools/tool-factory.d.ts +1 -1
  75. package/dist/src/tools/tool-factory.d.ts.map +1 -1
  76. package/dist/src/tools/types.d.ts +4 -0
  77. package/dist/src/tools/types.d.ts.map +1 -1
  78. package/dist/src/tools/zod-tool.d.ts +4 -2
  79. package/dist/src/tools/zod-tool.d.ts.map +1 -1
  80. package/dist/src/tools/zod-tool.js.map +1 -1
  81. package/dist/src/tsconfig.tsbuildinfo +1 -1
  82. package/dist/src/types/agent.d.ts +18 -1
  83. package/dist/src/types/agent.d.ts.map +1 -1
  84. package/dist/src/types/agent.js +12 -0
  85. package/dist/src/types/agent.js.map +1 -1
  86. package/dist/src/types/media.d.ts.map +1 -1
  87. package/dist/src/types/media.js.map +1 -1
  88. package/dist/src/types/messages.d.ts +22 -1
  89. package/dist/src/types/messages.d.ts.map +1 -1
  90. package/dist/src/types/messages.js +22 -0
  91. package/dist/src/types/messages.js.map +1 -1
  92. package/dist/src/vended-memory-stores/test-memory-store/index.d.ts +2 -0
  93. package/dist/src/vended-memory-stores/test-memory-store/index.d.ts.map +1 -0
  94. package/dist/src/vended-memory-stores/test-memory-store/index.js +2 -0
  95. package/dist/src/vended-memory-stores/test-memory-store/index.js.map +1 -0
  96. package/dist/src/vended-memory-stores/test-memory-store/store.d.ts +122 -0
  97. package/dist/src/vended-memory-stores/test-memory-store/store.d.ts.map +1 -0
  98. package/dist/src/vended-memory-stores/test-memory-store/store.js +281 -0
  99. package/dist/src/vended-memory-stores/test-memory-store/store.js.map +1 -0
  100. package/dist/src/vended-plugins/context-offloader/search.d.ts.map +1 -1
  101. package/dist/src/vended-plugins/context-offloader/search.js +4 -2
  102. package/dist/src/vended-plugins/context-offloader/search.js.map +1 -1
  103. package/dist/src/vended-plugins/context-offloader/storage.js +1 -1
  104. package/dist/src/vended-plugins/context-offloader/storage.js.map +1 -1
  105. package/dist/src/vended-plugins/skills/skill.d.ts.map +1 -1
  106. package/dist/src/vended-plugins/skills/skill.js.map +1 -1
  107. package/dist/src/vended-tools/notebook/notebook.d.ts +1 -1
  108. package/package.json +41 -30
  109. package/dist/src/__fixtures__/agent-helpers.d.ts +0 -136
  110. package/dist/src/__fixtures__/agent-helpers.d.ts.map +0 -1
  111. package/dist/src/__fixtures__/agent-helpers.js +0 -156
  112. package/dist/src/__fixtures__/agent-helpers.js.map +0 -1
  113. package/dist/src/__fixtures__/environment.d.ts +0 -12
  114. package/dist/src/__fixtures__/environment.d.ts.map +0 -1
  115. package/dist/src/__fixtures__/environment.js +0 -12
  116. package/dist/src/__fixtures__/environment.js.map +0 -1
  117. package/dist/src/__fixtures__/metrics-helpers.d.ts +0 -55
  118. package/dist/src/__fixtures__/metrics-helpers.d.ts.map +0 -1
  119. package/dist/src/__fixtures__/metrics-helpers.js +0 -57
  120. package/dist/src/__fixtures__/metrics-helpers.js.map +0 -1
  121. package/dist/src/__fixtures__/mock-message-model.d.ts +0 -103
  122. package/dist/src/__fixtures__/mock-message-model.d.ts.map +0 -1
  123. package/dist/src/__fixtures__/mock-message-model.js +0 -245
  124. package/dist/src/__fixtures__/mock-message-model.js.map +0 -1
  125. package/dist/src/__fixtures__/mock-meter.d.ts +0 -32
  126. package/dist/src/__fixtures__/mock-meter.d.ts.map +0 -1
  127. package/dist/src/__fixtures__/mock-meter.js +0 -47
  128. package/dist/src/__fixtures__/mock-meter.js.map +0 -1
  129. package/dist/src/__fixtures__/mock-plugin.d.ts +0 -13
  130. package/dist/src/__fixtures__/mock-plugin.d.ts.map +0 -1
  131. package/dist/src/__fixtures__/mock-plugin.js +0 -35
  132. package/dist/src/__fixtures__/mock-plugin.js.map +0 -1
  133. package/dist/src/__fixtures__/mock-span.d.ts +0 -78
  134. package/dist/src/__fixtures__/mock-span.d.ts.map +0 -1
  135. package/dist/src/__fixtures__/mock-span.js +0 -93
  136. package/dist/src/__fixtures__/mock-span.js.map +0 -1
  137. package/dist/src/__fixtures__/mock-storage-provider.d.ts +0 -42
  138. package/dist/src/__fixtures__/mock-storage-provider.d.ts.map +0 -1
  139. package/dist/src/__fixtures__/mock-storage-provider.js +0 -122
  140. package/dist/src/__fixtures__/mock-storage-provider.js.map +0 -1
  141. package/dist/src/__fixtures__/model-test-helpers.d.ts +0 -56
  142. package/dist/src/__fixtures__/model-test-helpers.d.ts.map +0 -1
  143. package/dist/src/__fixtures__/model-test-helpers.js +0 -85
  144. package/dist/src/__fixtures__/model-test-helpers.js.map +0 -1
  145. package/dist/src/__fixtures__/register-node-defaults.d.ts +0 -2
  146. package/dist/src/__fixtures__/register-node-defaults.d.ts.map +0 -1
  147. package/dist/src/__fixtures__/register-node-defaults.js +0 -6
  148. package/dist/src/__fixtures__/register-node-defaults.js.map +0 -1
  149. package/dist/src/__fixtures__/slim-types.d.ts +0 -51
  150. package/dist/src/__fixtures__/slim-types.d.ts.map +0 -1
  151. package/dist/src/__fixtures__/slim-types.js +0 -6
  152. package/dist/src/__fixtures__/slim-types.js.map +0 -1
  153. package/dist/src/__fixtures__/test-sandbox.node.d.ts +0 -15
  154. package/dist/src/__fixtures__/test-sandbox.node.d.ts.map +0 -1
  155. package/dist/src/__fixtures__/test-sandbox.node.js +0 -23
  156. package/dist/src/__fixtures__/test-sandbox.node.js.map +0 -1
  157. package/dist/src/__fixtures__/tool-helpers.d.ts +0 -45
  158. package/dist/src/__fixtures__/tool-helpers.d.ts.map +0 -1
  159. package/dist/src/__fixtures__/tool-helpers.js +0 -101
  160. package/dist/src/__fixtures__/tool-helpers.js.map +0 -1
  161. package/dist/src/__tests__/default-slot.test.d.ts +0 -2
  162. package/dist/src/__tests__/default-slot.test.d.ts.map +0 -1
  163. package/dist/src/__tests__/default-slot.test.js +0 -33
  164. package/dist/src/__tests__/default-slot.test.js.map +0 -1
  165. package/dist/src/__tests__/errors.test.d.ts +0 -2
  166. package/dist/src/__tests__/errors.test.d.ts.map +0 -1
  167. package/dist/src/__tests__/errors.test.js +0 -170
  168. package/dist/src/__tests__/errors.test.js.map +0 -1
  169. package/dist/src/__tests__/index.test.d.ts +0 -2
  170. package/dist/src/__tests__/index.test.d.ts.map +0 -1
  171. package/dist/src/__tests__/index.test.js +0 -48
  172. package/dist/src/__tests__/index.test.js.map +0 -1
  173. package/dist/src/__tests__/interrupt.test.d.ts +0 -2
  174. package/dist/src/__tests__/interrupt.test.d.ts.map +0 -1
  175. package/dist/src/__tests__/interrupt.test.js +0 -264
  176. package/dist/src/__tests__/interrupt.test.js.map +0 -1
  177. package/dist/src/__tests__/mcp.test.d.ts +0 -2
  178. package/dist/src/__tests__/mcp.test.d.ts.map +0 -1
  179. package/dist/src/__tests__/mcp.test.js +0 -1003
  180. package/dist/src/__tests__/mcp.test.js.map +0 -1
  181. package/dist/src/__tests__/mime.test.d.ts +0 -2
  182. package/dist/src/__tests__/mime.test.d.ts.map +0 -1
  183. package/dist/src/__tests__/mime.test.js +0 -83
  184. package/dist/src/__tests__/mime.test.js.map +0 -1
  185. package/dist/src/__tests__/state-store.test.d.ts +0 -2
  186. package/dist/src/__tests__/state-store.test.d.ts.map +0 -1
  187. package/dist/src/__tests__/state-store.test.js +0 -285
  188. package/dist/src/__tests__/state-store.test.js.map +0 -1
  189. package/dist/src/a2a/__tests__/a2a-agent.test.d.ts +0 -2
  190. package/dist/src/a2a/__tests__/a2a-agent.test.d.ts.map +0 -1
  191. package/dist/src/a2a/__tests__/a2a-agent.test.js +0 -383
  192. package/dist/src/a2a/__tests__/a2a-agent.test.js.map +0 -1
  193. package/dist/src/a2a/__tests__/adapters.test.d.ts +0 -2
  194. package/dist/src/a2a/__tests__/adapters.test.d.ts.map +0 -1
  195. package/dist/src/a2a/__tests__/adapters.test.js +0 -151
  196. package/dist/src/a2a/__tests__/adapters.test.js.map +0 -1
  197. package/dist/src/a2a/__tests__/async-lock.test.d.ts +0 -2
  198. package/dist/src/a2a/__tests__/async-lock.test.d.ts.map +0 -1
  199. package/dist/src/a2a/__tests__/async-lock.test.js +0 -137
  200. package/dist/src/a2a/__tests__/async-lock.test.js.map +0 -1
  201. package/dist/src/a2a/__tests__/events.test.d.ts +0 -2
  202. package/dist/src/a2a/__tests__/events.test.d.ts.map +0 -1
  203. package/dist/src/a2a/__tests__/events.test.js +0 -68
  204. package/dist/src/a2a/__tests__/events.test.js.map +0 -1
  205. package/dist/src/a2a/__tests__/executor.test.d.ts +0 -2
  206. package/dist/src/a2a/__tests__/executor.test.d.ts.map +0 -1
  207. package/dist/src/a2a/__tests__/executor.test.js +0 -345
  208. package/dist/src/a2a/__tests__/executor.test.js.map +0 -1
  209. package/dist/src/a2a/__tests__/server.test.d.ts +0 -2
  210. package/dist/src/a2a/__tests__/server.test.d.ts.map +0 -1
  211. package/dist/src/a2a/__tests__/server.test.js +0 -71
  212. package/dist/src/a2a/__tests__/server.test.js.map +0 -1
  213. package/dist/src/a2a/__tests__/server.test.node.d.ts +0 -2
  214. package/dist/src/a2a/__tests__/server.test.node.d.ts.map +0 -1
  215. package/dist/src/a2a/__tests__/server.test.node.js +0 -110
  216. package/dist/src/a2a/__tests__/server.test.node.js.map +0 -1
  217. package/dist/src/agent/__tests__/agent-as-tool.invocation-state.test.d.ts +0 -2
  218. package/dist/src/agent/__tests__/agent-as-tool.invocation-state.test.d.ts.map +0 -1
  219. package/dist/src/agent/__tests__/agent-as-tool.invocation-state.test.js +0 -23
  220. package/dist/src/agent/__tests__/agent-as-tool.invocation-state.test.js.map +0 -1
  221. package/dist/src/agent/__tests__/agent-as-tool.test.d.ts +0 -2
  222. package/dist/src/agent/__tests__/agent-as-tool.test.d.ts.map +0 -1
  223. package/dist/src/agent/__tests__/agent-as-tool.test.js +0 -347
  224. package/dist/src/agent/__tests__/agent-as-tool.test.js.map +0 -1
  225. package/dist/src/agent/__tests__/agent.cancel.test.d.ts +0 -2
  226. package/dist/src/agent/__tests__/agent.cancel.test.d.ts.map +0 -1
  227. package/dist/src/agent/__tests__/agent.cancel.test.js +0 -337
  228. package/dist/src/agent/__tests__/agent.cancel.test.js.map +0 -1
  229. package/dist/src/agent/__tests__/agent.concurrent.test.d.ts +0 -2
  230. package/dist/src/agent/__tests__/agent.concurrent.test.d.ts.map +0 -1
  231. package/dist/src/agent/__tests__/agent.concurrent.test.js +0 -488
  232. package/dist/src/agent/__tests__/agent.concurrent.test.js.map +0 -1
  233. package/dist/src/agent/__tests__/agent.context-manager.test.d.ts +0 -2
  234. package/dist/src/agent/__tests__/agent.context-manager.test.d.ts.map +0 -1
  235. package/dist/src/agent/__tests__/agent.context-manager.test.js +0 -106
  236. package/dist/src/agent/__tests__/agent.context-manager.test.js.map +0 -1
  237. package/dist/src/agent/__tests__/agent.hook.test.d.ts +0 -2
  238. package/dist/src/agent/__tests__/agent.hook.test.d.ts.map +0 -1
  239. package/dist/src/agent/__tests__/agent.hook.test.js +0 -1332
  240. package/dist/src/agent/__tests__/agent.hook.test.js.map +0 -1
  241. package/dist/src/agent/__tests__/agent.interrupt.test.d.ts +0 -2
  242. package/dist/src/agent/__tests__/agent.interrupt.test.d.ts.map +0 -1
  243. package/dist/src/agent/__tests__/agent.interrupt.test.js +0 -779
  244. package/dist/src/agent/__tests__/agent.interrupt.test.js.map +0 -1
  245. package/dist/src/agent/__tests__/agent.invocation-state.test.d.ts +0 -2
  246. package/dist/src/agent/__tests__/agent.invocation-state.test.d.ts.map +0 -1
  247. package/dist/src/agent/__tests__/agent.invocation-state.test.js +0 -219
  248. package/dist/src/agent/__tests__/agent.invocation-state.test.js.map +0 -1
  249. package/dist/src/agent/__tests__/agent.model-retry.test.d.ts +0 -2
  250. package/dist/src/agent/__tests__/agent.model-retry.test.d.ts.map +0 -1
  251. package/dist/src/agent/__tests__/agent.model-retry.test.js +0 -161
  252. package/dist/src/agent/__tests__/agent.model-retry.test.js.map +0 -1
  253. package/dist/src/agent/__tests__/agent.stateful-model.test.d.ts +0 -2
  254. package/dist/src/agent/__tests__/agent.stateful-model.test.d.ts.map +0 -1
  255. package/dist/src/agent/__tests__/agent.stateful-model.test.js +0 -169
  256. package/dist/src/agent/__tests__/agent.stateful-model.test.js.map +0 -1
  257. package/dist/src/agent/__tests__/agent.test.d.ts +0 -2
  258. package/dist/src/agent/__tests__/agent.test.d.ts.map +0 -1
  259. package/dist/src/agent/__tests__/agent.test.js +0 -1624
  260. package/dist/src/agent/__tests__/agent.test.js.map +0 -1
  261. package/dist/src/agent/__tests__/agent.tracer.test.node.d.ts +0 -2
  262. package/dist/src/agent/__tests__/agent.tracer.test.node.d.ts.map +0 -1
  263. package/dist/src/agent/__tests__/agent.tracer.test.node.js +0 -535
  264. package/dist/src/agent/__tests__/agent.tracer.test.node.js.map +0 -1
  265. package/dist/src/agent/__tests__/printer.test.d.ts +0 -2
  266. package/dist/src/agent/__tests__/printer.test.d.ts.map +0 -1
  267. package/dist/src/agent/__tests__/printer.test.js +0 -188
  268. package/dist/src/agent/__tests__/printer.test.js.map +0 -1
  269. package/dist/src/agent/__tests__/snapshot.test.d.ts +0 -2
  270. package/dist/src/agent/__tests__/snapshot.test.d.ts.map +0 -1
  271. package/dist/src/agent/__tests__/snapshot.test.js +0 -442
  272. package/dist/src/agent/__tests__/snapshot.test.js.map +0 -1
  273. package/dist/src/agent/__tests__/tool-caller.test.d.ts +0 -2
  274. package/dist/src/agent/__tests__/tool-caller.test.d.ts.map +0 -1
  275. package/dist/src/agent/__tests__/tool-caller.test.js +0 -459
  276. package/dist/src/agent/__tests__/tool-caller.test.js.map +0 -1
  277. package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts +0 -2
  278. package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts.map +0 -1
  279. package/dist/src/conversation-manager/__tests__/agentic-context.test.js +0 -332
  280. package/dist/src/conversation-manager/__tests__/agentic-context.test.js.map +0 -1
  281. package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts +0 -2
  282. package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts.map +0 -1
  283. package/dist/src/conversation-manager/__tests__/context-compression.test.js +0 -176
  284. package/dist/src/conversation-manager/__tests__/context-compression.test.js.map +0 -1
  285. package/dist/src/conversation-manager/__tests__/conversation-manager.test.d.ts +0 -2
  286. package/dist/src/conversation-manager/__tests__/conversation-manager.test.d.ts.map +0 -1
  287. package/dist/src/conversation-manager/__tests__/conversation-manager.test.js +0 -321
  288. package/dist/src/conversation-manager/__tests__/conversation-manager.test.js.map +0 -1
  289. package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.d.ts +0 -2
  290. package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.d.ts.map +0 -1
  291. package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.js +0 -64
  292. package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.js.map +0 -1
  293. package/dist/src/conversation-manager/__tests__/pin.test.d.ts +0 -2
  294. package/dist/src/conversation-manager/__tests__/pin.test.d.ts.map +0 -1
  295. package/dist/src/conversation-manager/__tests__/pin.test.js +0 -119
  296. package/dist/src/conversation-manager/__tests__/pin.test.js.map +0 -1
  297. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.d.ts +0 -2
  298. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.d.ts.map +0 -1
  299. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js +0 -1080
  300. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js.map +0 -1
  301. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.d.ts +0 -2
  302. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.d.ts.map +0 -1
  303. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js +0 -400
  304. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js.map +0 -1
  305. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.d.ts +0 -2
  306. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.d.ts.map +0 -1
  307. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js +0 -138
  308. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js.map +0 -1
  309. package/dist/src/hooks/__tests__/events.test.d.ts +0 -2
  310. package/dist/src/hooks/__tests__/events.test.d.ts.map +0 -1
  311. package/dist/src/hooks/__tests__/events.test.js +0 -1060
  312. package/dist/src/hooks/__tests__/events.test.js.map +0 -1
  313. package/dist/src/hooks/__tests__/registry.test.d.ts +0 -2
  314. package/dist/src/hooks/__tests__/registry.test.d.ts.map +0 -1
  315. package/dist/src/hooks/__tests__/registry.test.js +0 -325
  316. package/dist/src/hooks/__tests__/registry.test.js.map +0 -1
  317. package/dist/src/injection/__tests__/message-injection.test.d.ts +0 -2
  318. package/dist/src/injection/__tests__/message-injection.test.d.ts.map +0 -1
  319. package/dist/src/injection/__tests__/message-injection.test.js +0 -200
  320. package/dist/src/injection/__tests__/message-injection.test.js.map +0 -1
  321. package/dist/src/interventions/__tests__/handler.test.d.ts +0 -2
  322. package/dist/src/interventions/__tests__/handler.test.d.ts.map +0 -1
  323. package/dist/src/interventions/__tests__/handler.test.js +0 -35
  324. package/dist/src/interventions/__tests__/handler.test.js.map +0 -1
  325. package/dist/src/interventions/__tests__/registry.test.d.ts +0 -2
  326. package/dist/src/interventions/__tests__/registry.test.d.ts.map +0 -1
  327. package/dist/src/interventions/__tests__/registry.test.js +0 -692
  328. package/dist/src/interventions/__tests__/registry.test.js.map +0 -1
  329. package/dist/src/logging/__tests__/logger.test.d.ts +0 -2
  330. package/dist/src/logging/__tests__/logger.test.d.ts.map +0 -1
  331. package/dist/src/logging/__tests__/logger.test.js +0 -70
  332. package/dist/src/logging/__tests__/logger.test.js.map +0 -1
  333. package/dist/src/logging/__tests__/warn-once.test.d.ts +0 -2
  334. package/dist/src/logging/__tests__/warn-once.test.d.ts.map +0 -1
  335. package/dist/src/logging/__tests__/warn-once.test.js +0 -30
  336. package/dist/src/logging/__tests__/warn-once.test.js.map +0 -1
  337. package/dist/src/mcp.d.ts.map +0 -1
  338. package/dist/src/mcp.js.map +0 -1
  339. package/dist/src/memory/__tests__/memory-manager.test.d.ts +0 -2
  340. package/dist/src/memory/__tests__/memory-manager.test.d.ts.map +0 -1
  341. package/dist/src/memory/__tests__/memory-manager.test.js +0 -679
  342. package/dist/src/memory/__tests__/memory-manager.test.js.map +0 -1
  343. package/dist/src/memory/__tests__/memory-tracing.test.d.ts +0 -2
  344. package/dist/src/memory/__tests__/memory-tracing.test.d.ts.map +0 -1
  345. package/dist/src/memory/__tests__/memory-tracing.test.js +0 -250
  346. package/dist/src/memory/__tests__/memory-tracing.test.js.map +0 -1
  347. package/dist/src/memory/extraction/__tests__/extraction.test.d.ts +0 -2
  348. package/dist/src/memory/extraction/__tests__/extraction.test.d.ts.map +0 -1
  349. package/dist/src/memory/extraction/__tests__/extraction.test.js +0 -639
  350. package/dist/src/memory/extraction/__tests__/extraction.test.js.map +0 -1
  351. package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts +0 -2
  352. package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts.map +0 -1
  353. package/dist/src/memory/extraction/__tests__/model-extractor.test.js +0 -104
  354. package/dist/src/memory/extraction/__tests__/model-extractor.test.js.map +0 -1
  355. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts +0 -2
  356. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts.map +0 -1
  357. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js +0 -81
  358. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js.map +0 -1
  359. package/dist/src/middleware/__tests__/agent-middleware.test.d.ts +0 -2
  360. package/dist/src/middleware/__tests__/agent-middleware.test.d.ts.map +0 -1
  361. package/dist/src/middleware/__tests__/agent-middleware.test.js +0 -1206
  362. package/dist/src/middleware/__tests__/agent-middleware.test.js.map +0 -1
  363. package/dist/src/middleware/__tests__/copy-on-input.test.d.ts +0 -2
  364. package/dist/src/middleware/__tests__/copy-on-input.test.d.ts.map +0 -1
  365. package/dist/src/middleware/__tests__/copy-on-input.test.js +0 -379
  366. package/dist/src/middleware/__tests__/copy-on-input.test.js.map +0 -1
  367. package/dist/src/middleware/__tests__/custom-stages.test.d.ts +0 -2
  368. package/dist/src/middleware/__tests__/custom-stages.test.d.ts.map +0 -1
  369. package/dist/src/middleware/__tests__/custom-stages.test.js +0 -97
  370. package/dist/src/middleware/__tests__/custom-stages.test.js.map +0 -1
  371. package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts +0 -2
  372. package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts.map +0 -1
  373. package/dist/src/middleware/__tests__/middleware-interrupts.test.js +0 -267
  374. package/dist/src/middleware/__tests__/middleware-interrupts.test.js.map +0 -1
  375. package/dist/src/middleware/__tests__/registry.test.d.ts +0 -2
  376. package/dist/src/middleware/__tests__/registry.test.d.ts.map +0 -1
  377. package/dist/src/middleware/__tests__/registry.test.js +0 -525
  378. package/dist/src/middleware/__tests__/registry.test.js.map +0 -1
  379. package/dist/src/models/__tests__/anthropic.test.d.ts +0 -2
  380. package/dist/src/models/__tests__/anthropic.test.d.ts.map +0 -1
  381. package/dist/src/models/__tests__/anthropic.test.js +0 -793
  382. package/dist/src/models/__tests__/anthropic.test.js.map +0 -1
  383. package/dist/src/models/__tests__/bedrock.test.d.ts +0 -2
  384. package/dist/src/models/__tests__/bedrock.test.d.ts.map +0 -1
  385. package/dist/src/models/__tests__/bedrock.test.js +0 -3964
  386. package/dist/src/models/__tests__/bedrock.test.js.map +0 -1
  387. package/dist/src/models/__tests__/defaults.test.d.ts +0 -2
  388. package/dist/src/models/__tests__/defaults.test.d.ts.map +0 -1
  389. package/dist/src/models/__tests__/defaults.test.js +0 -36
  390. package/dist/src/models/__tests__/defaults.test.js.map +0 -1
  391. package/dist/src/models/__tests__/google.test.d.ts +0 -2
  392. package/dist/src/models/__tests__/google.test.d.ts.map +0 -1
  393. package/dist/src/models/__tests__/google.test.js +0 -1145
  394. package/dist/src/models/__tests__/google.test.js.map +0 -1
  395. package/dist/src/models/__tests__/model.test.d.ts +0 -2
  396. package/dist/src/models/__tests__/model.test.d.ts.map +0 -1
  397. package/dist/src/models/__tests__/model.test.js +0 -921
  398. package/dist/src/models/__tests__/model.test.js.map +0 -1
  399. package/dist/src/models/__tests__/streaming.test.d.ts +0 -2
  400. package/dist/src/models/__tests__/streaming.test.d.ts.map +0 -1
  401. package/dist/src/models/__tests__/streaming.test.js +0 -50
  402. package/dist/src/models/__tests__/streaming.test.js.map +0 -1
  403. package/dist/src/models/__tests__/test-utils.d.ts +0 -10
  404. package/dist/src/models/__tests__/test-utils.d.ts.map +0 -1
  405. package/dist/src/models/__tests__/test-utils.js +0 -17
  406. package/dist/src/models/__tests__/test-utils.js.map +0 -1
  407. package/dist/src/models/__tests__/vercel.test.d.ts +0 -2
  408. package/dist/src/models/__tests__/vercel.test.d.ts.map +0 -1
  409. package/dist/src/models/__tests__/vercel.test.js +0 -740
  410. package/dist/src/models/__tests__/vercel.test.js.map +0 -1
  411. package/dist/src/models/openai/__tests__/chat.test.d.ts +0 -2
  412. package/dist/src/models/openai/__tests__/chat.test.d.ts.map +0 -1
  413. package/dist/src/models/openai/__tests__/chat.test.js +0 -1586
  414. package/dist/src/models/openai/__tests__/chat.test.js.map +0 -1
  415. package/dist/src/models/openai/__tests__/errors.test.d.ts +0 -2
  416. package/dist/src/models/openai/__tests__/errors.test.d.ts.map +0 -1
  417. package/dist/src/models/openai/__tests__/errors.test.js +0 -39
  418. package/dist/src/models/openai/__tests__/errors.test.js.map +0 -1
  419. package/dist/src/models/openai/__tests__/mantle.test.d.ts +0 -2
  420. package/dist/src/models/openai/__tests__/mantle.test.d.ts.map +0 -1
  421. package/dist/src/models/openai/__tests__/mantle.test.js +0 -189
  422. package/dist/src/models/openai/__tests__/mantle.test.js.map +0 -1
  423. package/dist/src/models/openai/__tests__/responses.test.d.ts +0 -2
  424. package/dist/src/models/openai/__tests__/responses.test.d.ts.map +0 -1
  425. package/dist/src/models/openai/__tests__/responses.test.js +0 -709
  426. package/dist/src/models/openai/__tests__/responses.test.js.map +0 -1
  427. package/dist/src/multiagent/__tests__/events.test.d.ts +0 -2
  428. package/dist/src/multiagent/__tests__/events.test.d.ts.map +0 -1
  429. package/dist/src/multiagent/__tests__/events.test.js +0 -493
  430. package/dist/src/multiagent/__tests__/events.test.js.map +0 -1
  431. package/dist/src/multiagent/__tests__/graph.invocation-state.test.d.ts +0 -2
  432. package/dist/src/multiagent/__tests__/graph.invocation-state.test.d.ts.map +0 -1
  433. package/dist/src/multiagent/__tests__/graph.invocation-state.test.js +0 -95
  434. package/dist/src/multiagent/__tests__/graph.invocation-state.test.js.map +0 -1
  435. package/dist/src/multiagent/__tests__/graph.test.d.ts +0 -2
  436. package/dist/src/multiagent/__tests__/graph.test.d.ts.map +0 -1
  437. package/dist/src/multiagent/__tests__/graph.test.js +0 -698
  438. package/dist/src/multiagent/__tests__/graph.test.js.map +0 -1
  439. package/dist/src/multiagent/__tests__/graph.tracer.test.d.ts +0 -2
  440. package/dist/src/multiagent/__tests__/graph.tracer.test.d.ts.map +0 -1
  441. package/dist/src/multiagent/__tests__/graph.tracer.test.js +0 -218
  442. package/dist/src/multiagent/__tests__/graph.tracer.test.js.map +0 -1
  443. package/dist/src/multiagent/__tests__/interrupts.test.d.ts +0 -2
  444. package/dist/src/multiagent/__tests__/interrupts.test.d.ts.map +0 -1
  445. package/dist/src/multiagent/__tests__/interrupts.test.js +0 -390
  446. package/dist/src/multiagent/__tests__/interrupts.test.js.map +0 -1
  447. package/dist/src/multiagent/__tests__/nodes.test.d.ts +0 -2
  448. package/dist/src/multiagent/__tests__/nodes.test.d.ts.map +0 -1
  449. package/dist/src/multiagent/__tests__/nodes.test.js +0 -321
  450. package/dist/src/multiagent/__tests__/nodes.test.js.map +0 -1
  451. package/dist/src/multiagent/__tests__/queue.test.d.ts +0 -2
  452. package/dist/src/multiagent/__tests__/queue.test.d.ts.map +0 -1
  453. package/dist/src/multiagent/__tests__/queue.test.js +0 -118
  454. package/dist/src/multiagent/__tests__/queue.test.js.map +0 -1
  455. package/dist/src/multiagent/__tests__/snapshot.test.d.ts +0 -2
  456. package/dist/src/multiagent/__tests__/snapshot.test.d.ts.map +0 -1
  457. package/dist/src/multiagent/__tests__/snapshot.test.js +0 -161
  458. package/dist/src/multiagent/__tests__/snapshot.test.js.map +0 -1
  459. package/dist/src/multiagent/__tests__/state.test.d.ts +0 -2
  460. package/dist/src/multiagent/__tests__/state.test.d.ts.map +0 -1
  461. package/dist/src/multiagent/__tests__/state.test.js +0 -526
  462. package/dist/src/multiagent/__tests__/state.test.js.map +0 -1
  463. package/dist/src/multiagent/__tests__/swarm.invocation-state.test.d.ts +0 -2
  464. package/dist/src/multiagent/__tests__/swarm.invocation-state.test.d.ts.map +0 -1
  465. package/dist/src/multiagent/__tests__/swarm.invocation-state.test.js +0 -56
  466. package/dist/src/multiagent/__tests__/swarm.invocation-state.test.js.map +0 -1
  467. package/dist/src/multiagent/__tests__/swarm.test.d.ts +0 -2
  468. package/dist/src/multiagent/__tests__/swarm.test.d.ts.map +0 -1
  469. package/dist/src/multiagent/__tests__/swarm.test.js +0 -477
  470. package/dist/src/multiagent/__tests__/swarm.test.js.map +0 -1
  471. package/dist/src/multiagent/__tests__/swarm.tracer.test.d.ts +0 -2
  472. package/dist/src/multiagent/__tests__/swarm.tracer.test.d.ts.map +0 -1
  473. package/dist/src/multiagent/__tests__/swarm.tracer.test.js +0 -235
  474. package/dist/src/multiagent/__tests__/swarm.tracer.test.js.map +0 -1
  475. package/dist/src/plugins/__tests__/plugin.test.d.ts +0 -2
  476. package/dist/src/plugins/__tests__/plugin.test.d.ts.map +0 -1
  477. package/dist/src/plugins/__tests__/plugin.test.js +0 -114
  478. package/dist/src/plugins/__tests__/plugin.test.js.map +0 -1
  479. package/dist/src/plugins/__tests__/registry.test.d.ts +0 -2
  480. package/dist/src/plugins/__tests__/registry.test.d.ts.map +0 -1
  481. package/dist/src/plugins/__tests__/registry.test.js +0 -147
  482. package/dist/src/plugins/__tests__/registry.test.js.map +0 -1
  483. package/dist/src/registry/__tests__/tool-registry.test.d.ts +0 -2
  484. package/dist/src/registry/__tests__/tool-registry.test.d.ts.map +0 -1
  485. package/dist/src/registry/__tests__/tool-registry.test.js +0 -210
  486. package/dist/src/registry/__tests__/tool-registry.test.js.map +0 -1
  487. package/dist/src/retry/__tests__/backoff-strategy.test.d.ts +0 -2
  488. package/dist/src/retry/__tests__/backoff-strategy.test.d.ts.map +0 -1
  489. package/dist/src/retry/__tests__/backoff-strategy.test.js +0 -116
  490. package/dist/src/retry/__tests__/backoff-strategy.test.js.map +0 -1
  491. package/dist/src/retry/__tests__/default-model-retry-strategy.test.d.ts +0 -2
  492. package/dist/src/retry/__tests__/default-model-retry-strategy.test.d.ts.map +0 -1
  493. package/dist/src/retry/__tests__/default-model-retry-strategy.test.js +0 -225
  494. package/dist/src/retry/__tests__/default-model-retry-strategy.test.js.map +0 -1
  495. package/dist/src/sandbox/__tests__/default.test.browser.d.ts +0 -2
  496. package/dist/src/sandbox/__tests__/default.test.browser.d.ts.map +0 -1
  497. package/dist/src/sandbox/__tests__/default.test.browser.js +0 -11
  498. package/dist/src/sandbox/__tests__/default.test.browser.js.map +0 -1
  499. package/dist/src/sandbox/__tests__/default.test.node.d.ts +0 -2
  500. package/dist/src/sandbox/__tests__/default.test.node.d.ts.map +0 -1
  501. package/dist/src/sandbox/__tests__/default.test.node.js +0 -23
  502. package/dist/src/sandbox/__tests__/default.test.node.js.map +0 -1
  503. package/dist/src/sandbox/__tests__/docker.test.node.d.ts +0 -2
  504. package/dist/src/sandbox/__tests__/docker.test.node.d.ts.map +0 -1
  505. package/dist/src/sandbox/__tests__/docker.test.node.js +0 -89
  506. package/dist/src/sandbox/__tests__/docker.test.node.js.map +0 -1
  507. package/dist/src/sandbox/__tests__/errors.test.node.d.ts +0 -2
  508. package/dist/src/sandbox/__tests__/errors.test.node.d.ts.map +0 -1
  509. package/dist/src/sandbox/__tests__/errors.test.node.js +0 -33
  510. package/dist/src/sandbox/__tests__/errors.test.node.js.map +0 -1
  511. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts +0 -2
  512. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts.map +0 -1
  513. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js +0 -124
  514. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js.map +0 -1
  515. package/dist/src/sandbox/__tests__/posix-shell.test.node.d.ts +0 -2
  516. package/dist/src/sandbox/__tests__/posix-shell.test.node.d.ts.map +0 -1
  517. package/dist/src/sandbox/__tests__/posix-shell.test.node.js +0 -298
  518. package/dist/src/sandbox/__tests__/posix-shell.test.node.js.map +0 -1
  519. package/dist/src/sandbox/__tests__/ssh.test.node.d.ts +0 -2
  520. package/dist/src/sandbox/__tests__/ssh.test.node.d.ts.map +0 -1
  521. package/dist/src/sandbox/__tests__/ssh.test.node.js +0 -262
  522. package/dist/src/sandbox/__tests__/ssh.test.node.js.map +0 -1
  523. package/dist/src/session/__tests__/file-storage.test.node.d.ts +0 -2
  524. package/dist/src/session/__tests__/file-storage.test.node.d.ts.map +0 -1
  525. package/dist/src/session/__tests__/file-storage.test.node.js +0 -278
  526. package/dist/src/session/__tests__/file-storage.test.node.js.map +0 -1
  527. package/dist/src/session/__tests__/s3-storage.test.d.ts +0 -2
  528. package/dist/src/session/__tests__/s3-storage.test.d.ts.map +0 -1
  529. package/dist/src/session/__tests__/s3-storage.test.js +0 -461
  530. package/dist/src/session/__tests__/s3-storage.test.js.map +0 -1
  531. package/dist/src/session/__tests__/session-manager.test.d.ts +0 -2
  532. package/dist/src/session/__tests__/session-manager.test.d.ts.map +0 -1
  533. package/dist/src/session/__tests__/session-manager.test.js +0 -832
  534. package/dist/src/session/__tests__/session-manager.test.js.map +0 -1
  535. package/dist/src/session/__tests__/validation.test.d.ts +0 -2
  536. package/dist/src/session/__tests__/validation.test.d.ts.map +0 -1
  537. package/dist/src/session/__tests__/validation.test.js +0 -47
  538. package/dist/src/session/__tests__/validation.test.js.map +0 -1
  539. package/dist/src/telemetry/__tests__/config.test.d.ts +0 -2
  540. package/dist/src/telemetry/__tests__/config.test.d.ts.map +0 -1
  541. package/dist/src/telemetry/__tests__/config.test.js +0 -64
  542. package/dist/src/telemetry/__tests__/config.test.js.map +0 -1
  543. package/dist/src/telemetry/__tests__/config.test.node.d.ts +0 -2
  544. package/dist/src/telemetry/__tests__/config.test.node.d.ts.map +0 -1
  545. package/dist/src/telemetry/__tests__/config.test.node.js +0 -164
  546. package/dist/src/telemetry/__tests__/config.test.node.js.map +0 -1
  547. package/dist/src/telemetry/__tests__/json.test.d.ts +0 -2
  548. package/dist/src/telemetry/__tests__/json.test.d.ts.map +0 -1
  549. package/dist/src/telemetry/__tests__/json.test.js +0 -89
  550. package/dist/src/telemetry/__tests__/json.test.js.map +0 -1
  551. package/dist/src/telemetry/__tests__/local-trace.test.d.ts +0 -2
  552. package/dist/src/telemetry/__tests__/local-trace.test.d.ts.map +0 -1
  553. package/dist/src/telemetry/__tests__/local-trace.test.js +0 -158
  554. package/dist/src/telemetry/__tests__/local-trace.test.js.map +0 -1
  555. package/dist/src/telemetry/__tests__/meter.test.d.ts +0 -2
  556. package/dist/src/telemetry/__tests__/meter.test.d.ts.map +0 -1
  557. package/dist/src/telemetry/__tests__/meter.test.js +0 -695
  558. package/dist/src/telemetry/__tests__/meter.test.js.map +0 -1
  559. package/dist/src/telemetry/__tests__/tracer.test.node.d.ts +0 -2
  560. package/dist/src/telemetry/__tests__/tracer.test.node.d.ts.map +0 -1
  561. package/dist/src/telemetry/__tests__/tracer.test.node.js +0 -958
  562. package/dist/src/telemetry/__tests__/tracer.test.node.js.map +0 -1
  563. package/dist/src/tools/__tests__/structured-output-tool.test.d.ts +0 -2
  564. package/dist/src/tools/__tests__/structured-output-tool.test.d.ts.map +0 -1
  565. package/dist/src/tools/__tests__/structured-output-tool.test.js +0 -84
  566. package/dist/src/tools/__tests__/structured-output-tool.test.js.map +0 -1
  567. package/dist/src/tools/__tests__/tool-factory.test.d.ts +0 -2
  568. package/dist/src/tools/__tests__/tool-factory.test.d.ts.map +0 -1
  569. package/dist/src/tools/__tests__/tool-factory.test.js +0 -98
  570. package/dist/src/tools/__tests__/tool-factory.test.js.map +0 -1
  571. package/dist/src/tools/__tests__/tool.test.d.ts +0 -2
  572. package/dist/src/tools/__tests__/tool.test.d.ts.map +0 -1
  573. package/dist/src/tools/__tests__/tool.test.js +0 -1043
  574. package/dist/src/tools/__tests__/tool.test.js.map +0 -1
  575. package/dist/src/tools/__tests__/zod-tool.test-d.d.ts +0 -2
  576. package/dist/src/tools/__tests__/zod-tool.test-d.d.ts.map +0 -1
  577. package/dist/src/tools/__tests__/zod-tool.test-d.js +0 -227
  578. package/dist/src/tools/__tests__/zod-tool.test-d.js.map +0 -1
  579. package/dist/src/tools/__tests__/zod-tool.test.d.ts +0 -2
  580. package/dist/src/tools/__tests__/zod-tool.test.d.ts.map +0 -1
  581. package/dist/src/tools/__tests__/zod-tool.test.js +0 -563
  582. package/dist/src/tools/__tests__/zod-tool.test.js.map +0 -1
  583. package/dist/src/types/__tests__/agent.test.d.ts +0 -2
  584. package/dist/src/types/__tests__/agent.test.d.ts.map +0 -1
  585. package/dist/src/types/__tests__/agent.test.js +0 -476
  586. package/dist/src/types/__tests__/agent.test.js.map +0 -1
  587. package/dist/src/types/__tests__/citations.test.d.ts +0 -2
  588. package/dist/src/types/__tests__/citations.test.d.ts.map +0 -1
  589. package/dist/src/types/__tests__/citations.test.js +0 -104
  590. package/dist/src/types/__tests__/citations.test.js.map +0 -1
  591. package/dist/src/types/__tests__/json.test.d.ts +0 -2
  592. package/dist/src/types/__tests__/json.test.d.ts.map +0 -1
  593. package/dist/src/types/__tests__/json.test.js +0 -298
  594. package/dist/src/types/__tests__/json.test.js.map +0 -1
  595. package/dist/src/types/__tests__/media.test.d.ts +0 -2
  596. package/dist/src/types/__tests__/media.test.d.ts.map +0 -1
  597. package/dist/src/types/__tests__/media.test.js +0 -478
  598. package/dist/src/types/__tests__/media.test.js.map +0 -1
  599. package/dist/src/types/__tests__/messages.test.d.ts +0 -2
  600. package/dist/src/types/__tests__/messages.test.d.ts.map +0 -1
  601. package/dist/src/types/__tests__/messages.test.js +0 -681
  602. package/dist/src/types/__tests__/messages.test.js.map +0 -1
  603. package/dist/src/types/__tests__/validation.test.d.ts +0 -2
  604. package/dist/src/types/__tests__/validation.test.d.ts.map +0 -1
  605. package/dist/src/types/__tests__/validation.test.js +0 -30
  606. package/dist/src/types/__tests__/validation.test.js.map +0 -1
  607. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts +0 -2
  608. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts.map +0 -1
  609. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js +0 -756
  610. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js.map +0 -1
  611. package/dist/src/vended-interventions/hitl/__tests__/hitl.test.d.ts +0 -2
  612. package/dist/src/vended-interventions/hitl/__tests__/hitl.test.d.ts.map +0 -1
  613. package/dist/src/vended-interventions/hitl/__tests__/hitl.test.js +0 -358
  614. package/dist/src/vended-interventions/hitl/__tests__/hitl.test.js.map +0 -1
  615. package/dist/src/vended-interventions/steering/__tests__/handler.test.d.ts +0 -2
  616. package/dist/src/vended-interventions/steering/__tests__/handler.test.d.ts.map +0 -1
  617. package/dist/src/vended-interventions/steering/__tests__/handler.test.js +0 -163
  618. package/dist/src/vended-interventions/steering/__tests__/handler.test.js.map +0 -1
  619. package/dist/src/vended-interventions/steering/__tests__/llm.test.d.ts +0 -2
  620. package/dist/src/vended-interventions/steering/__tests__/llm.test.d.ts.map +0 -1
  621. package/dist/src/vended-interventions/steering/__tests__/llm.test.js +0 -60
  622. package/dist/src/vended-interventions/steering/__tests__/llm.test.js.map +0 -1
  623. package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.d.ts +0 -2
  624. package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.d.ts.map +0 -1
  625. package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.js +0 -94
  626. package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.js.map +0 -1
  627. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.node.d.ts +0 -2
  628. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.node.d.ts.map +0 -1
  629. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.node.js +0 -758
  630. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.node.js.map +0 -1
  631. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.d.ts +0 -2
  632. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.d.ts.map +0 -1
  633. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js +0 -96
  634. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js.map +0 -1
  635. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts +0 -2
  636. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts.map +0 -1
  637. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js +0 -68
  638. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js.map +0 -1
  639. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.d.ts +0 -2
  640. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.d.ts.map +0 -1
  641. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js +0 -539
  642. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js.map +0 -1
  643. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts +0 -2
  644. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts.map +0 -1
  645. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js +0 -97
  646. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js.map +0 -1
  647. package/dist/src/vended-plugins/context-offloader/__tests__/search.test.d.ts +0 -2
  648. package/dist/src/vended-plugins/context-offloader/__tests__/search.test.d.ts.map +0 -1
  649. package/dist/src/vended-plugins/context-offloader/__tests__/search.test.js +0 -149
  650. package/dist/src/vended-plugins/context-offloader/__tests__/search.test.js.map +0 -1
  651. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.d.ts +0 -2
  652. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.d.ts.map +0 -1
  653. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js +0 -216
  654. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js.map +0 -1
  655. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.d.ts +0 -2
  656. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.d.ts.map +0 -1
  657. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.js +0 -78
  658. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.js.map +0 -1
  659. package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts +0 -2
  660. package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts.map +0 -1
  661. package/dist/src/vended-plugins/goal/__tests__/plugin.test.js +0 -736
  662. package/dist/src/vended-plugins/goal/__tests__/plugin.test.js.map +0 -1
  663. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.d.ts +0 -2
  664. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.d.ts.map +0 -1
  665. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js +0 -482
  666. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js.map +0 -1
  667. package/dist/src/vended-plugins/skills/__tests__/skill.test.node.d.ts +0 -2
  668. package/dist/src/vended-plugins/skills/__tests__/skill.test.node.d.ts.map +0 -1
  669. package/dist/src/vended-plugins/skills/__tests__/skill.test.node.js +0 -476
  670. package/dist/src/vended-plugins/skills/__tests__/skill.test.node.js.map +0 -1
  671. package/dist/src/vended-tools/bash/__tests__/bash.test.node.d.ts +0 -2
  672. package/dist/src/vended-tools/bash/__tests__/bash.test.node.d.ts.map +0 -1
  673. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js +0 -390
  674. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js.map +0 -1
  675. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.d.ts +0 -2
  676. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.d.ts.map +0 -1
  677. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js +0 -452
  678. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js.map +0 -1
  679. package/dist/src/vended-tools/http-request/__tests__/http-request.test.d.ts +0 -2
  680. package/dist/src/vended-tools/http-request/__tests__/http-request.test.d.ts.map +0 -1
  681. package/dist/src/vended-tools/http-request/__tests__/http-request.test.js +0 -189
  682. package/dist/src/vended-tools/http-request/__tests__/http-request.test.js.map +0 -1
  683. package/dist/src/vended-tools/notebook/__tests__/notebook.test.d.ts +0 -2
  684. package/dist/src/vended-tools/notebook/__tests__/notebook.test.d.ts.map +0 -1
  685. package/dist/src/vended-tools/notebook/__tests__/notebook.test.js +0 -388
  686. package/dist/src/vended-tools/notebook/__tests__/notebook.test.js.map +0 -1
@@ -1,1624 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { z } from 'zod';
3
- import { Agent } from '../agent.js';
4
- import { McpClient } from '../../mcp.js';
5
- import { McpTool } from '../../tools/mcp-tool.js';
6
- import { MockMessageModel } from '../../__fixtures__/mock-message-model.js';
7
- import { collectGenerator } from '../../__fixtures__/model-test-helpers.js';
8
- import { createMockTool, createRandomTool } from '../../__fixtures__/tool-helpers.js';
9
- import { ConcurrentInvocationError } from '../../errors.js';
10
- import { MaxTokensError, TextBlock, CachePointBlock, Message, ToolUseBlock, ToolResultBlock, ReasoningBlock, GuardContentBlock, ImageBlock, VideoBlock, DocumentBlock, } from '../../index.js';
11
- import { AgentPrinter } from '../printer.js';
12
- import { AfterInvocationEvent, AfterToolCallEvent, AfterToolsEvent, BeforeInvocationEvent, BeforeModelCallEvent, BeforeToolsEvent, } from '../../hooks/events.js';
13
- import { BedrockModel } from '../../models/bedrock.js';
14
- import { StructuredOutputError } from '../../errors.js';
15
- import { expectLoopMetrics } from '../../__fixtures__/metrics-helpers.js';
16
- import { expectAgentResult } from '../../__fixtures__/agent-helpers.js';
17
- describe('Agent', () => {
18
- describe('stream', () => {
19
- describe('basic streaming', () => {
20
- it('returns AsyncGenerator', () => {
21
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
22
- const agent = new Agent({ model });
23
- const result = agent.stream('Test prompt');
24
- expect(result).toBeDefined();
25
- expect(typeof result[Symbol.asyncIterator]).toBe('function');
26
- });
27
- it('returns AsyncGenerator that can be iterated without type errors', async () => {
28
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
29
- const agent = new Agent({ model });
30
- // Ensures that the signature of agent.stream is correct
31
- for await (const _ of agent.stream('Test prompt')) {
32
- /* intentionally empty */
33
- }
34
- });
35
- it('yields AgentStreamEvent objects', async () => {
36
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
37
- const agent = new Agent({ model });
38
- const { items } = await collectGenerator(agent.stream('Test prompt'));
39
- expect(items.length).toBeGreaterThan(0);
40
- const firstItem = items[0];
41
- expect(firstItem).toEqual(new BeforeInvocationEvent({ agent: agent, invocationState: {} }));
42
- });
43
- it('returns AgentResult as generator return value', async () => {
44
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
45
- const agent = new Agent({ model });
46
- const { result } = await collectGenerator(agent.stream('Test prompt'));
47
- expect(result).toEqual(expectAgentResult({
48
- stopReason: 'endTurn',
49
- messageText: 'Hello',
50
- cycleCount: 1,
51
- traceCount: 1,
52
- }));
53
- // Verify trace structure
54
- expect(result.traces?.[0]?.children).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'stream_messages' })]));
55
- });
56
- });
57
- describe('with tool use', () => {
58
- it('handles tool execution flow', async () => {
59
- const model = new MockMessageModel()
60
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} })
61
- .addTurn({ type: 'textBlock', text: 'Tool result processed' });
62
- const tool = createMockTool('testTool', () => new ToolResultBlock({
63
- toolUseId: 'tool-1',
64
- status: 'success',
65
- content: [new TextBlock('Tool executed')],
66
- }));
67
- const agent = new Agent({ model, tools: [tool] });
68
- const { items, result } = await collectGenerator(agent.stream('Use the tool'));
69
- // Check that tool-related events are yielded
70
- const toolEvents = items.filter((event) => event.type === 'beforeToolsEvent' || event.type === 'afterToolsEvent');
71
- expect(toolEvents.length).toBeGreaterThan(0);
72
- // Check final result
73
- expect(result.stopReason).toBe('endTurn');
74
- });
75
- it('yields tool-related events', async () => {
76
- const model = new MockMessageModel()
77
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} })
78
- .addTurn({ type: 'textBlock', text: 'Done' });
79
- const tool = createMockTool('testTool', () => new ToolResultBlock({
80
- toolUseId: 'tool-1',
81
- status: 'success',
82
- content: [new TextBlock('Success')],
83
- }));
84
- const agent = new Agent({ model, tools: [tool] });
85
- const { items } = await collectGenerator(agent.stream('Test'));
86
- const beforeTools = items.find((e) => e.type === 'beforeToolsEvent');
87
- const afterTools = items.find((e) => e.type === 'afterToolsEvent');
88
- expect(beforeTools).toEqual(new BeforeToolsEvent({
89
- agent: agent,
90
- message: new Message({
91
- role: 'assistant',
92
- content: [new ToolUseBlock({ name: 'testTool', toolUseId: 'tool-1', input: {} })],
93
- }),
94
- invocationState: {},
95
- }));
96
- expect(afterTools).toBeDefined();
97
- expect(afterTools?.type).toBe('afterToolsEvent');
98
- expect(afterTools?.message).toEqual({
99
- type: 'message',
100
- role: 'user',
101
- content: [
102
- {
103
- type: 'toolResultBlock',
104
- toolUseId: 'tool-1',
105
- status: 'success',
106
- content: [{ type: 'textBlock', text: 'Success' }],
107
- },
108
- ],
109
- });
110
- expect(afterTools).toHaveProperty('agent', agent);
111
- });
112
- });
113
- describe('error handling', () => {
114
- it('throws MaxTokensError when model hits token limit', async () => {
115
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Partial...' }, { stopReason: 'maxTokens' });
116
- const agent = new Agent({ model });
117
- await expect(async () => {
118
- await collectGenerator(agent.stream('Test'));
119
- }).rejects.toThrow(MaxTokensError);
120
- });
121
- });
122
- describe('hook error cleanup', () => {
123
- it('fires AfterInvocationEvent when consumer breaks from stream and allows reinvocation', async () => {
124
- const model = new MockMessageModel()
125
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} })
126
- .addTurn({ type: 'textBlock', text: 'Done' });
127
- const tool = createMockTool('testTool', () => new ToolResultBlock({
128
- toolUseId: 'tool-1',
129
- status: 'success',
130
- content: [new TextBlock('ok')],
131
- }));
132
- const agent = new Agent({ model, tools: [tool], printer: false });
133
- const afterInvocationCallback = vi.fn();
134
- agent.addHook(AfterInvocationEvent, afterInvocationCallback);
135
- for await (const event of agent.stream('Test')) {
136
- if (event.type === 'beforeToolsEvent') {
137
- break;
138
- }
139
- }
140
- expect(afterInvocationCallback).toHaveBeenCalledOnce();
141
- const result = await agent.invoke('Test again');
142
- expect(result.stopReason).toBe('endTurn');
143
- expect(result.lastMessage.content[0]).toEqual(new TextBlock('Done'));
144
- });
145
- });
146
- });
147
- describe('invoke', () => {
148
- describe('basic invocation', () => {
149
- it('returns Promise<AgentResult>', async () => {
150
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
151
- const agent = new Agent({ model });
152
- const result = agent.invoke('Test prompt');
153
- expect(result).toBeInstanceOf(Promise);
154
- const awaited = await result;
155
- expect(awaited).toHaveProperty('stopReason');
156
- expect(awaited).toHaveProperty('lastMessage');
157
- });
158
- it('returns correct stopReason and lastMessage', async () => {
159
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response text' });
160
- const agent = new Agent({ model });
161
- const result = await agent.invoke('Test prompt');
162
- expect(result).toEqual(expectAgentResult({
163
- stopReason: 'endTurn',
164
- messageText: 'Response text',
165
- cycleCount: 1,
166
- traceCount: 1,
167
- }));
168
- });
169
- it('consumes stream events internally', async () => {
170
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
171
- const agent = new Agent({ model });
172
- const result = await agent.invoke('Test');
173
- expect(result).toEqual(expect.objectContaining({
174
- stopReason: 'endTurn',
175
- lastMessage: expect.objectContaining({
176
- type: 'message',
177
- role: 'assistant',
178
- content: expect.arrayContaining([expect.objectContaining({ type: 'textBlock', text: 'Hello' })]),
179
- }),
180
- metrics: expectLoopMetrics({ cycleCount: 1 }),
181
- }));
182
- });
183
- });
184
- describe('with tool use', () => {
185
- it('executes tools and returns final result', async () => {
186
- const model = new MockMessageModel()
187
- .addTurn({ type: 'toolUseBlock', name: 'calc', toolUseId: 'tool-1', input: { a: 1, b: 2 } }, {
188
- usage: { inputTokens: 100, outputTokens: 50, totalTokens: 150 },
189
- })
190
- .addTurn({ type: 'textBlock', text: 'The answer is 3' }, {
191
- usage: { inputTokens: 200, outputTokens: 30, totalTokens: 230 },
192
- });
193
- const tool = createMockTool('calc', () => new ToolResultBlock({
194
- toolUseId: 'tool-1',
195
- status: 'success',
196
- content: [new TextBlock('3')],
197
- }));
198
- const agent = new Agent({ model, tools: [tool] });
199
- const result = await agent.invoke('What is 1 + 2?');
200
- expect(result).toEqual(expectAgentResult({
201
- stopReason: 'endTurn',
202
- messageText: 'The answer is 3',
203
- cycleCount: 2,
204
- toolNames: ['calc'],
205
- traceCount: 2,
206
- usage: { inputTokens: 300, outputTokens: 80, totalTokens: 380 },
207
- }));
208
- // Verify detailed trace children structure
209
- expect(result.traces?.[0]?.children).toEqual(expect.arrayContaining([
210
- expect.objectContaining({ name: 'stream_messages' }),
211
- expect.objectContaining({ name: 'Tool: calc' }),
212
- ]));
213
- expect(result.traces?.[1]?.children).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'stream_messages' })]));
214
- });
215
- it('stores cycleId in trace metadata', async () => {
216
- const model = new MockMessageModel()
217
- .addTurn({ type: 'toolUseBlock', name: 'calc', toolUseId: 'tool-1', input: {} })
218
- .addTurn({ type: 'textBlock', text: 'Done' });
219
- const tool = createMockTool('calc', () => new ToolResultBlock({
220
- toolUseId: 'tool-1',
221
- status: 'success',
222
- content: [new TextBlock('result')],
223
- }));
224
- const agent = new Agent({ model, tools: [tool] });
225
- const result = await agent.invoke('Test');
226
- expect(result.traces).toEqual([
227
- expect.objectContaining({
228
- name: 'Cycle 1',
229
- metadata: expect.objectContaining({ cycleId: 'cycle-1' }),
230
- }),
231
- expect.objectContaining({
232
- name: 'Cycle 2',
233
- metadata: expect.objectContaining({ cycleId: 'cycle-2' }),
234
- }),
235
- ]);
236
- });
237
- it('stores tool metadata in trace children', async () => {
238
- const model = new MockMessageModel()
239
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-abc123', input: {} })
240
- .addTurn({ type: 'textBlock', text: 'Done' });
241
- const tool = createMockTool('testTool', () => new ToolResultBlock({
242
- toolUseId: 'tool-abc123',
243
- status: 'success',
244
- content: [new TextBlock('result')],
245
- }));
246
- const agent = new Agent({ model, tools: [tool] });
247
- const result = await agent.invoke('Test');
248
- expect(result.traces).toEqual(expect.arrayContaining([
249
- expect.objectContaining({
250
- name: 'Cycle 1',
251
- children: expect.arrayContaining([
252
- expect.objectContaining({
253
- name: 'Tool: testTool',
254
- metadata: expect.objectContaining({
255
- toolUseId: 'tool-abc123',
256
- toolName: 'testTool',
257
- }),
258
- }),
259
- ]),
260
- }),
261
- ]));
262
- });
263
- });
264
- describe('error handling', () => {
265
- it('propagates maxTokens error', async () => {
266
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Partial' }, { stopReason: 'maxTokens' });
267
- const agent = new Agent({ model });
268
- await expect(agent.invoke('Test')).rejects.toThrow(MaxTokensError);
269
- });
270
- });
271
- describe('metrics on errors', () => {
272
- it('tracks cycle count when maxTokens error occurs', async () => {
273
- const model = new MockMessageModel()
274
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} }, {
275
- usage: { inputTokens: 100, outputTokens: 50, totalTokens: 150 },
276
- })
277
- .addTurn({ type: 'textBlock', text: 'Partial' }, {
278
- stopReason: 'maxTokens',
279
- usage: { inputTokens: 80, outputTokens: 20, totalTokens: 100 },
280
- });
281
- const tool = createMockTool('testTool', () => new ToolResultBlock({
282
- toolUseId: 'tool-1',
283
- status: 'success',
284
- content: [new TextBlock('Done')],
285
- }));
286
- const agent = new Agent({ model, tools: [tool] });
287
- const meter = agent._meter;
288
- await expect(agent.invoke('Test')).rejects.toThrow(MaxTokensError);
289
- expect(meter.metrics.cycleCount).toBe(2);
290
- // Only the first turn's usage is accumulated; the second turn throws
291
- // MaxTokensError inside streamAggregated before metadata reaches updateCycle
292
- expect(meter.metrics.accumulatedUsage).toStrictEqual({
293
- inputTokens: 100,
294
- outputTokens: 50,
295
- totalTokens: 150,
296
- });
297
- expect(meter.metrics.accumulatedMetrics).toStrictEqual({
298
- latencyMs: expect.any(Number),
299
- });
300
- expect(meter.metrics.toolMetrics).toStrictEqual({
301
- testTool: {
302
- callCount: 1,
303
- successCount: 1,
304
- errorCount: 0,
305
- totalTime: expect.any(Number),
306
- },
307
- });
308
- });
309
- it('collects local traces for completed cycles when error occurs mid-run', async () => {
310
- const model = new MockMessageModel()
311
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} }, {
312
- usage: { inputTokens: 100, outputTokens: 50, totalTokens: 150 },
313
- })
314
- .addTurn({ type: 'textBlock', text: 'Partial' }, {
315
- stopReason: 'maxTokens',
316
- usage: { inputTokens: 80, outputTokens: 20, totalTokens: 100 },
317
- });
318
- const tool = createMockTool('testTool', () => new ToolResultBlock({
319
- toolUseId: 'tool-1',
320
- status: 'success',
321
- content: [new TextBlock('Done')],
322
- }));
323
- const agent = new Agent({ model, tools: [tool] });
324
- const tracer = agent._tracer;
325
- await expect(agent.invoke('Test')).rejects.toThrow(MaxTokensError);
326
- // Cycle 1 completed (tool use), cycle 2 errored (maxTokens)
327
- expect(tracer.localTraces).toEqual([
328
- expect.objectContaining({
329
- name: 'Cycle 1',
330
- children: [
331
- expect.objectContaining({ name: 'stream_messages' }),
332
- expect.objectContaining({ name: 'Tool: testTool' }),
333
- ],
334
- }),
335
- expect.objectContaining({
336
- name: 'Cycle 2',
337
- children: [expect.objectContaining({ name: 'stream_messages' })],
338
- }),
339
- ]);
340
- });
341
- it('tracks metrics when a hook throws an error', async () => {
342
- const model = new MockMessageModel()
343
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} }, {
344
- usage: { inputTokens: 60, outputTokens: 25, totalTokens: 85 },
345
- })
346
- .addTurn({ type: 'textBlock', text: 'Done' });
347
- const tool = createMockTool('testTool', () => new ToolResultBlock({
348
- toolUseId: 'tool-1',
349
- status: 'success',
350
- content: [new TextBlock('Result')],
351
- }));
352
- const agent = new Agent({ model, tools: [tool] });
353
- agent.addHook(BeforeToolsEvent, () => {
354
- throw new Error('Hook failure');
355
- });
356
- const meter = agent._meter;
357
- await expect(agent.invoke('Test')).rejects.toThrow('Hook failure');
358
- // The hook throws after the model returns but before tools execute,
359
- // so the first cycle's model usage is recorded but no tool metrics exist
360
- expect(meter.metrics.cycleCount).toBe(1);
361
- expect(meter.metrics.accumulatedUsage).toStrictEqual({
362
- inputTokens: 60,
363
- outputTokens: 25,
364
- totalTokens: 85,
365
- });
366
- expect(meter.metrics.accumulatedMetrics).toStrictEqual({
367
- latencyMs: expect.any(Number),
368
- });
369
- expect(meter.metrics.toolMetrics).toStrictEqual({});
370
- });
371
- });
372
- describe('hook error cleanup', () => {
373
- it('fires AfterInvocationEvent when a mid-stream hook throws', async () => {
374
- const model = new MockMessageModel()
375
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} })
376
- .addTurn({ type: 'textBlock', text: 'Done' });
377
- const tool = createMockTool('testTool', () => new ToolResultBlock({
378
- toolUseId: 'tool-1',
379
- status: 'success',
380
- content: [new TextBlock('ok')],
381
- }));
382
- const agent = new Agent({ model, tools: [tool], printer: false });
383
- agent.addHook(AfterToolCallEvent, () => {
384
- throw new Error('hook error');
385
- });
386
- const afterInvocationCallback = vi.fn();
387
- agent.addHook(AfterInvocationEvent, afterInvocationCallback);
388
- await expect(agent.invoke('Test')).rejects.toThrow('hook error');
389
- expect(afterInvocationCallback).toHaveBeenCalledOnce();
390
- });
391
- it('fires AfterToolsEvent when a mid-stream hook throws', async () => {
392
- const model = new MockMessageModel()
393
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} })
394
- .addTurn({ type: 'textBlock', text: 'Done' });
395
- const tool = createMockTool('testTool', () => new ToolResultBlock({
396
- toolUseId: 'tool-1',
397
- status: 'success',
398
- content: [new TextBlock('ok')],
399
- }));
400
- const agent = new Agent({ model, tools: [tool], printer: false });
401
- agent.addHook(AfterToolCallEvent, () => {
402
- throw new Error('hook error');
403
- });
404
- const afterToolsCallback = vi.fn();
405
- agent.addHook(AfterToolsEvent, afterToolsCallback);
406
- await expect(agent.invoke('Test')).rejects.toThrow('hook error');
407
- expect(afterToolsCallback).toHaveBeenCalledOnce();
408
- });
409
- it('does not fire AfterInvocationEvent when BeforeInvocationEvent hook throws', async () => {
410
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
411
- const agent = new Agent({ model, printer: false });
412
- agent.addHook(BeforeInvocationEvent, () => {
413
- throw new Error('before hook error');
414
- });
415
- const afterInvocationCallback = vi.fn();
416
- agent.addHook(AfterInvocationEvent, afterInvocationCallback);
417
- await expect(agent.invoke('Test')).rejects.toThrow('before hook error');
418
- expect(afterInvocationCallback).not.toHaveBeenCalled();
419
- });
420
- it('does not fire AfterToolsEvent when BeforeToolsEvent hook throws', async () => {
421
- const model = new MockMessageModel()
422
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'tool-1', input: {} })
423
- .addTurn({ type: 'textBlock', text: 'Done' });
424
- const tool = createMockTool('testTool', () => new ToolResultBlock({
425
- toolUseId: 'tool-1',
426
- status: 'success',
427
- content: [new TextBlock('ok')],
428
- }));
429
- const agent = new Agent({ model, tools: [tool], printer: false });
430
- agent.addHook(BeforeToolsEvent, () => {
431
- throw new Error('before tools hook error');
432
- });
433
- const afterToolsCallback = vi.fn();
434
- agent.addHook(AfterToolsEvent, afterToolsCallback);
435
- await expect(agent.invoke('Test')).rejects.toThrow('before tools hook error');
436
- expect(afterToolsCallback).not.toHaveBeenCalled();
437
- });
438
- });
439
- });
440
- describe('API consistency', () => {
441
- it('invoke() and stream() produce same final result', async () => {
442
- const model1 = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Consistent response' });
443
- const model2 = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Consistent response' });
444
- const agent1 = new Agent({ model: model1 });
445
- const agent2 = new Agent({ model: model2 });
446
- const invokeResult = await agent1.invoke('Test');
447
- const { result: streamResult } = await collectGenerator(agent2.stream('Test'));
448
- expect(invokeResult.stopReason).toBe(streamResult.stopReason);
449
- expect(invokeResult.lastMessage.content).toEqual(streamResult.lastMessage.content);
450
- });
451
- it('both methods produce same result with tool use', async () => {
452
- const createToolAndModels = () => {
453
- const model = new MockMessageModel()
454
- .addTurn({ type: 'toolUseBlock', name: 'testTool', toolUseId: 'id', input: {} })
455
- .addTurn({ type: 'textBlock', text: 'Final' });
456
- const tool = createMockTool('testTool', () => new ToolResultBlock({
457
- toolUseId: 'id',
458
- status: 'success',
459
- content: [new TextBlock('Tool ran')],
460
- }));
461
- return { model, tool };
462
- };
463
- const { model: model1, tool: tool1 } = createToolAndModels();
464
- const { model: model2, tool: tool2 } = createToolAndModels();
465
- const agent1 = new Agent({ model: model1, tools: [tool1] });
466
- const agent2 = new Agent({ model: model2, tools: [tool2] });
467
- const invokeResult = await agent1.invoke('Use tool');
468
- const { result: streamResult } = await collectGenerator(agent2.stream('Use tool'));
469
- expect(invokeResult).toEqual(expect.objectContaining({
470
- stopReason: streamResult.stopReason,
471
- lastMessage: streamResult.lastMessage,
472
- traces: streamResult.traces?.map((t) => expect.objectContaining({
473
- name: t.name,
474
- children: expect.arrayContaining(Array(t.children.length).fill(expect.objectContaining({ name: expect.any(String) }))),
475
- })),
476
- }));
477
- });
478
- });
479
- describe('messages', () => {
480
- it('returns array of messages', () => {
481
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
482
- const agent = new Agent({ model });
483
- expect(agent.messages).toEqual([]);
484
- });
485
- it('reflects conversation history after invoke', async () => {
486
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response' });
487
- const agent = new Agent({ model });
488
- await agent.invoke('Hello');
489
- expect(agent.messages).toEqual([
490
- expect.objectContaining({
491
- role: 'user',
492
- content: [{ type: 'textBlock', text: 'Hello' }],
493
- }),
494
- expect.objectContaining({
495
- role: 'assistant',
496
- content: [{ type: 'textBlock', text: 'Response' }],
497
- }),
498
- ]);
499
- });
500
- });
501
- describe('printer configuration', () => {
502
- it('validates output when printer is enabled', async () => {
503
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello world' });
504
- // Capture output
505
- const outputs = [];
506
- const mockAppender = (text) => outputs.push(text);
507
- // Create agent with custom printer for testing
508
- const agent = new Agent({ model, printer: false });
509
- agent._printer = new AgentPrinter(mockAppender);
510
- await collectGenerator(agent.stream('Test'));
511
- // Validate that text was output
512
- const allOutput = outputs.join('');
513
- expect(allOutput).toContain('Hello world');
514
- });
515
- it('does not create printer when printer is false', () => {
516
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
517
- const agent = new Agent({ model, printer: false });
518
- expect(agent).toBeDefined();
519
- expect(agent._printer).toBeUndefined();
520
- });
521
- it('defaults to printer=true when not specified', () => {
522
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
523
- const agent = new Agent({ model });
524
- expect(agent).toBeDefined();
525
- expect(agent._printer).toBeDefined();
526
- });
527
- it('agent works correctly with printer disabled', async () => {
528
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
529
- const agent = new Agent({ model, printer: false });
530
- const { result } = await collectGenerator(agent.stream('Test'));
531
- expect(result).toBeDefined();
532
- expect(result.lastMessage.content).toEqual([{ type: 'textBlock', text: 'Hello' }]);
533
- });
534
- });
535
- describe('concurrency guards', () => {
536
- it('prevents parallel invocations', async () => {
537
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response' });
538
- const agent = new Agent({ model });
539
- // Test parallel invoke() calls
540
- const invokePromise1 = agent.invoke('First');
541
- const invokePromise2 = agent.invoke('Second');
542
- await expect(invokePromise2).rejects.toThrow(ConcurrentInvocationError);
543
- await expect(invokePromise1).resolves.toBeDefined();
544
- });
545
- it('allows sequential invocations after lock is released', async () => {
546
- const model = new MockMessageModel()
547
- .addTurn({ type: 'textBlock', text: 'First response' })
548
- .addTurn({ type: 'textBlock', text: 'Second response' });
549
- const agent = new Agent({ model });
550
- const result1 = await agent.invoke('First');
551
- expect(result1.lastMessage.content).toEqual([{ type: 'textBlock', text: 'First response' }]);
552
- const result2 = await agent.invoke('Second');
553
- expect(result2.lastMessage.content).toEqual([{ type: 'textBlock', text: 'Second response' }]);
554
- });
555
- it('releases lock after errors and abandoned streams', async () => {
556
- // Test error case
557
- const model = new MockMessageModel()
558
- .addTurn({ type: 'textBlock', text: 'Partial' }, { stopReason: 'maxTokens' })
559
- .addTurn({ type: 'textBlock', text: 'Success' });
560
- const agent = new Agent({ model });
561
- await expect(agent.invoke('First')).rejects.toThrow(MaxTokensError);
562
- const result = await agent.invoke('Second');
563
- expect(result.lastMessage.content).toEqual([{ type: 'textBlock', text: 'Success' }]);
564
- });
565
- });
566
- describe('nested tool arrays', () => {
567
- describe('flattens nested arrays at any depth', () => {
568
- const tool1 = createRandomTool();
569
- const tool2 = createRandomTool();
570
- const tool3 = createRandomTool();
571
- it.for([
572
- ['flat array', [tool1, tool2, tool3], [tool1, tool2, tool3]],
573
- ['single tool', [tool1], [tool1]],
574
- ['empty array', [], []],
575
- ['single level nesting', [[tool1, tool2], tool3], [tool1, tool2, tool3]],
576
- ['empty nested arrays', [[], tool1, []], [tool1]],
577
- ['deeply nested', [[[tool1]], [tool2], tool3], [tool1, tool2, tool3]],
578
- ['mixed nesting', [[tool1, [tool2]], tool3], [tool1, tool2, tool3]],
579
- ['very deep nesting', [[[[tool1]]]], [tool1]],
580
- ])('%i', ([, input, expected]) => {
581
- const agent = new Agent({ tools: input });
582
- expect(agent.tools).toEqual(expected);
583
- });
584
- });
585
- it('accepts undefined tools', () => {
586
- const agent = new Agent({});
587
- expect(agent.tools).toEqual([]);
588
- });
589
- it('catches duplicate tool names across nested arrays', () => {
590
- const tool1 = createRandomTool('duplicate');
591
- const tool2 = createRandomTool('duplicate');
592
- expect(() => new Agent({ tools: [[tool1], [tool2]] })).toThrow("Tool with name 'duplicate' already registered");
593
- });
594
- });
595
- describe('systemPrompt configuration', () => {
596
- describe('when provided as string SystemPromptData', () => {
597
- it('accepts and stores string system prompt', () => {
598
- const agent = new Agent({ systemPrompt: 'You are a helpful assistant' });
599
- expect(agent).toBeDefined();
600
- });
601
- });
602
- describe('when provided as array SystemPromptData', () => {
603
- it('converts TextBlockData to TextBlock', () => {
604
- const agent = new Agent({ systemPrompt: [{ text: 'System prompt text' }] });
605
- expect(agent).toBeDefined();
606
- });
607
- it('converts mixed block data types', () => {
608
- const agent = new Agent({
609
- systemPrompt: [{ text: 'First block' }, { cachePoint: { cacheType: 'default' } }, { text: 'Second block' }],
610
- });
611
- expect(agent).toBeDefined();
612
- });
613
- });
614
- describe('when provided as SystemPrompt (class instances)', () => {
615
- it('accepts array of class instances', () => {
616
- const systemPrompt = [new TextBlock('System prompt'), new CachePointBlock({ cacheType: 'default' })];
617
- const agent = new Agent({ systemPrompt });
618
- expect(agent).toBeDefined();
619
- });
620
- });
621
- describe('when modifying systemPrompt', () => {
622
- it('allows systemPrompt to be set after initialization', () => {
623
- const agent = new Agent({ systemPrompt: 'Initial prompt' });
624
- agent.systemPrompt = 'Updated prompt';
625
- expect(agent.systemPrompt).toEqual('Updated prompt');
626
- });
627
- it('allows systemPrompt to be changed between turns', async () => {
628
- const firstModel = new MockMessageModel().addTurn({ type: 'textBlock', text: 'First response' });
629
- const streamSpy = vi.spyOn(firstModel, 'stream');
630
- const agent = new Agent({ model: firstModel, systemPrompt: [new TextBlock('You are a helpful assistant')] });
631
- // First invocation with initial system prompt
632
- await agent.invoke('First prompt');
633
- expect(agent.systemPrompt).toEqual([new TextBlock('You are a helpful assistant')]);
634
- // Should have been called with the given promp
635
- expect(streamSpy).toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({
636
- systemPrompt: [new TextBlock('You are a helpful assistant')],
637
- toolSpecs: [],
638
- }));
639
- // Change system prompt and model
640
- agent.systemPrompt = 'You are a coding expert';
641
- // Second invocation should use new system prompt
642
- streamSpy.mockReset();
643
- await agent.invoke('Second prompt');
644
- expect(agent.systemPrompt).toEqual('You are a coding expert');
645
- expect(streamSpy).toHaveBeenCalledWith(expect.any(Array), expect.objectContaining({
646
- systemPrompt: 'You are a coding expert',
647
- toolSpecs: [],
648
- }));
649
- });
650
- });
651
- });
652
- describe('model property', () => {
653
- describe('when accessing the model field', () => {
654
- it('returns the configured model instance', () => {
655
- const model = new MockMessageModel();
656
- const agent = new Agent({ model });
657
- expect(agent.model).toBe(model);
658
- });
659
- it('returns default BedrockModel when no model provided', () => {
660
- const agent = new Agent();
661
- expect(agent.model).toBeDefined();
662
- expect(agent.model.constructor.name).toBe('BedrockModel');
663
- });
664
- });
665
- describe('when modifying the model field', () => {
666
- it('updates the model instance', () => {
667
- const initialModel = new MockMessageModel();
668
- const newModel = new MockMessageModel();
669
- const agent = new Agent({ model: initialModel });
670
- agent.model = newModel;
671
- expect(agent.model).toBe(newModel);
672
- expect(agent.model).not.toBe(initialModel);
673
- });
674
- it('allows model change to persist across invocations', async () => {
675
- const firstModel = new MockMessageModel().addTurn({ type: 'textBlock', text: 'First response' });
676
- const secondModel = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Second response' });
677
- const agent = new Agent({ model: firstModel });
678
- // First invocation with initial model
679
- const firstResult = await agent.invoke('First prompt');
680
- expect(firstResult.lastMessage?.content[0]).toEqual(new TextBlock('First response'));
681
- // Change model
682
- agent.model = secondModel;
683
- // Second invocation should use new model
684
- const secondResult = await agent.invoke('Second prompt');
685
- expect(secondResult.lastMessage?.content[0]).toEqual(new TextBlock('Second response'));
686
- });
687
- it('successfully switches between different model providers', async () => {
688
- const bedrockModel = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Bedrock response' });
689
- const openaiModel = new MockMessageModel().addTurn({ type: 'textBlock', text: 'OpenAI response' });
690
- const agent = new Agent({ model: bedrockModel });
691
- // First invocation
692
- const firstResult = await agent.invoke('First prompt');
693
- expect(firstResult.lastMessage?.content[0]).toEqual(new TextBlock('Bedrock response'));
694
- // Switch to different provider
695
- agent.model = openaiModel;
696
- // Second invocation with new provider
697
- const secondResult = await agent.invoke('Second prompt');
698
- expect(secondResult.lastMessage?.content[0]).toEqual(new TextBlock('OpenAI response'));
699
- });
700
- });
701
- });
702
- describe('multimodal input', () => {
703
- describe('with string input', () => {
704
- it('creates user message with single TextBlock', async () => {
705
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
706
- const agent = new Agent({ model });
707
- await agent.invoke('Hello');
708
- expect(agent.messages).toHaveLength(2);
709
- expect(agent.messages[0]).toEqual(new Message({
710
- role: 'user',
711
- content: [new TextBlock('Hello')],
712
- }));
713
- });
714
- });
715
- describe('with ContentBlock[] input', () => {
716
- it('creates single user message with single TextBlock', async () => {
717
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
718
- const agent = new Agent({ model });
719
- await agent.invoke([new TextBlock('Hello')]);
720
- expect(agent.messages).toHaveLength(2);
721
- expect(agent.messages[0]).toEqual(new Message({
722
- role: 'user',
723
- content: [new TextBlock('Hello')],
724
- }));
725
- });
726
- it('creates single user message with multiple blocks', async () => {
727
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
728
- const agent = new Agent({ model });
729
- const contentBlocks = [new TextBlock('Analyze this'), new TextBlock('and this')];
730
- await agent.invoke(contentBlocks);
731
- expect(agent.messages).toHaveLength(2);
732
- expect(agent.messages[0]).toEqual(new Message({
733
- role: 'user',
734
- content: contentBlocks,
735
- }));
736
- });
737
- it('supports all ContentBlock types', async () => {
738
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
739
- const agent = new Agent({ model });
740
- const contentBlocks = [
741
- new TextBlock('Text content'),
742
- new ToolUseBlock({ name: 'tool1', toolUseId: 'id-1', input: { key: 'value' } }),
743
- new ToolResultBlock({
744
- toolUseId: 'id-1',
745
- status: 'success',
746
- content: [new TextBlock('Result')],
747
- }),
748
- new ReasoningBlock({ text: 'My reasoning' }),
749
- new CachePointBlock({ cacheType: 'default' }),
750
- new GuardContentBlock({ text: { text: 'Guard content', qualifiers: ['grounding_source'] } }),
751
- new ImageBlock({
752
- format: 'png',
753
- source: { url: 'https://example.com/image.png' },
754
- }),
755
- new VideoBlock({
756
- format: 'mp4',
757
- source: { location: { type: 's3', uri: 's3://bucket/video.mp4' } },
758
- }),
759
- new DocumentBlock({
760
- format: 'pdf',
761
- name: 'doc.pdf',
762
- source: { bytes: new Uint8Array([1, 2, 3]) },
763
- }),
764
- ];
765
- await agent.invoke(contentBlocks);
766
- expect(agent.messages).toHaveLength(2);
767
- expect(agent.messages[0]).toEqual(new Message({
768
- role: 'user',
769
- content: contentBlocks,
770
- }));
771
- });
772
- it('handles empty ContentBlock array', async () => {
773
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
774
- const agent = new Agent({ model });
775
- await agent.invoke([]);
776
- expect(agent.messages).toHaveLength(1); // Only response message added
777
- });
778
- it('accepts ContentBlockData[] and converts to ContentBlock[]', async () => {
779
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
780
- const agent = new Agent({ model });
781
- await agent.invoke([
782
- { text: 'Hello from data format' },
783
- {
784
- toolUse: {
785
- name: 'testTool',
786
- toolUseId: 'id-1',
787
- input: { key: 'value' },
788
- },
789
- },
790
- {
791
- toolResult: {
792
- toolUseId: 'id-1',
793
- status: 'success',
794
- content: [{ text: 'Tool result' }, { json: { result: 42 } }],
795
- },
796
- },
797
- { reasoning: { text: 'My reasoning' } },
798
- { cachePoint: { cacheType: 'default' } },
799
- { guardContent: { text: { text: 'Guard text', qualifiers: ['query'] } } },
800
- {
801
- image: {
802
- format: 'png',
803
- source: { url: 'https://example.com/image.png' },
804
- },
805
- },
806
- {
807
- video: {
808
- format: 'mp4',
809
- source: { location: { type: 's3', uri: 's3://bucket/video.mp4' } },
810
- },
811
- },
812
- {
813
- document: {
814
- format: 'pdf',
815
- name: 'doc.pdf',
816
- source: { bytes: new Uint8Array([1, 2, 3]) },
817
- },
818
- },
819
- ]);
820
- expect(agent.messages).toHaveLength(2);
821
- const userMessage = agent.messages[0];
822
- expect(userMessage.role).toBe('user');
823
- expect(userMessage.content).toHaveLength(9);
824
- expect(userMessage.content[0]).toEqual(new TextBlock('Hello from data format'));
825
- expect(userMessage.content[1]).toEqual(new ToolUseBlock({ name: 'testTool', toolUseId: 'id-1', input: { key: 'value' } }));
826
- });
827
- });
828
- describe('with Message[] input', () => {
829
- it('appends single message to conversation', async () => {
830
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
831
- const agent = new Agent({ model });
832
- const userMessage = new Message({
833
- role: 'user',
834
- content: [new TextBlock('Hello')],
835
- });
836
- await agent.invoke([userMessage]);
837
- expect(agent.messages).toHaveLength(2);
838
- expect(agent.messages[0]).toEqual(userMessage);
839
- });
840
- it('appends multiple messages in order', async () => {
841
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
842
- const agent = new Agent({ model });
843
- const messages = [
844
- new Message({
845
- role: 'user',
846
- content: [new TextBlock('First message')],
847
- }),
848
- new Message({
849
- role: 'assistant',
850
- content: [new TextBlock('Second message')],
851
- }),
852
- new Message({
853
- role: 'user',
854
- content: [new TextBlock('Third message')],
855
- }),
856
- ];
857
- await agent.invoke(messages);
858
- expect(agent.messages).toHaveLength(4); // 3 input + 1 response
859
- expect(agent.messages[0]).toEqual(messages[0]);
860
- expect(agent.messages[1]).toEqual(messages[1]);
861
- expect(agent.messages[2]).toEqual(messages[2]);
862
- });
863
- it('handles empty Message array', async () => {
864
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
865
- const agent = new Agent({ model });
866
- await agent.invoke([]);
867
- expect(agent.messages).toHaveLength(1); // Only response message added
868
- });
869
- it('accepts MessageData[] and converts to Message[]', async () => {
870
- const model = new MockMessageModel().addTurn(new TextBlock('Response'));
871
- const agent = new Agent({ model });
872
- const messageDataArray = [
873
- {
874
- role: 'user',
875
- content: [{ text: 'First message' }],
876
- },
877
- {
878
- role: 'assistant',
879
- content: [{ text: 'Second message' }],
880
- },
881
- ];
882
- await agent.invoke(messageDataArray);
883
- expect(agent.messages).toHaveLength(3); // 2 input + 1 response
884
- expect(agent.messages[0]).toEqual(new Message({
885
- role: 'user',
886
- content: [new TextBlock('First message')],
887
- }));
888
- expect(agent.messages[1]).toEqual(new Message({
889
- role: 'assistant',
890
- content: [new TextBlock('Second message')],
891
- }));
892
- });
893
- });
894
- });
895
- describe('model initialization', () => {
896
- describe('when model is a string', () => {
897
- it('creates BedrockModel with specified modelId', () => {
898
- const agent = new Agent({ model: 'anthropic.claude-3-5-sonnet-20240620-v1:0' });
899
- expect(agent.model).toBeDefined();
900
- expect(agent.model.constructor.name).toBe('BedrockModel');
901
- expect(agent.model.getConfig().modelId).toBe('anthropic.claude-3-5-sonnet-20240620-v1:0');
902
- });
903
- it('creates BedrockModel with custom model ID', () => {
904
- const customModelId = 'custom.model.id';
905
- const agent = new Agent({ model: customModelId });
906
- expect(agent.model.getConfig().modelId).toBe(customModelId);
907
- });
908
- });
909
- describe('when model is explicit BedrockModel', () => {
910
- it('uses provided BedrockModel instance', () => {
911
- const explicitModel = new BedrockModel({ modelId: 'explicit-model-id' });
912
- const agent = new Agent({ model: explicitModel });
913
- expect(agent.model).toBe(explicitModel);
914
- expect(agent.model.getConfig().modelId).toBe('explicit-model-id');
915
- });
916
- });
917
- describe('when no model is provided', () => {
918
- it('creates default BedrockModel', () => {
919
- const agent = new Agent();
920
- expect(agent.model).toBeDefined();
921
- expect(agent.model.constructor.name).toBe('BedrockModel');
922
- });
923
- });
924
- describe('behavior parity', () => {
925
- it('string model behaves identically to explicit BedrockModel with same modelId', () => {
926
- const modelId = 'anthropic.claude-3-5-sonnet-20240620-v1:0';
927
- // Create agent with string model ID
928
- const agentWithString = new Agent({ model: modelId });
929
- // Create agent with explicit BedrockModel
930
- const explicitModel = new BedrockModel({ modelId });
931
- const agentWithExplicit = new Agent({ model: explicitModel });
932
- // Both should have same modelId
933
- expect(agentWithString.model.getConfig().modelId).toBe(agentWithExplicit.model.getConfig().modelId);
934
- expect(agentWithString.model.getConfig().modelId).toBe(modelId);
935
- });
936
- });
937
- });
938
- describe('structured output', () => {
939
- it('returns structured output when schema provided and tool used', async () => {
940
- const schema = z.object({ name: z.string(), age: z.number() });
941
- const model = new MockMessageModel()
942
- .addTurn({
943
- type: 'toolUseBlock',
944
- name: 'strands_structured_output',
945
- toolUseId: 'tool-1',
946
- input: { name: 'John', age: 30 },
947
- })
948
- .addTurn({ type: 'textBlock', text: 'Done' });
949
- const agent = new Agent({ model, structuredOutputSchema: schema });
950
- const result = await agent.invoke('Test');
951
- expect(result.structuredOutput).toEqual({ name: 'John', age: 30 });
952
- expect(model.callCount).toBe(1);
953
- });
954
- it('forces structured output tool when model does not use it', async () => {
955
- const schema = z.object({ value: z.number() });
956
- const model = new MockMessageModel()
957
- .addTurn({ type: 'textBlock', text: 'First response' })
958
- .addTurn({ type: 'toolUseBlock', name: 'strands_structured_output', toolUseId: 'tool-1', input: { value: 42 } })
959
- .addTurn({ type: 'textBlock', text: 'Done' });
960
- const agent = new Agent({ model, structuredOutputSchema: schema });
961
- const result = await agent.invoke('Test');
962
- expect(result.structuredOutput).toEqual({ value: 42 });
963
- });
964
- it('does not send assistant-ended conversation when forcing structured output retry', async () => {
965
- // Regression for https://github.com/strands-agents/sdk-typescript/issues/1039
966
- // When the model responds with plain text instead of calling the structured output tool,
967
- // the forced-retry model call must not see a conversation ending with an assistant message.
968
- // Bedrock/Anthropic-family models reject assistant message prefill.
969
- const schema = z.object({ value: z.number() });
970
- const model = new MockMessageModel()
971
- .addTurn({ type: 'textBlock', text: 'Plain text, no tool call' })
972
- .addTurn({ type: 'toolUseBlock', name: 'strands_structured_output', toolUseId: 'tool-1', input: { value: 42 } })
973
- .addTurn({ type: 'textBlock', text: 'Done' });
974
- // Snapshot the role sequence at each model call, since `messages` is passed by reference
975
- // and mutates during the agent loop.
976
- const roleSnapshots = [];
977
- const originalStream = model.stream.bind(model);
978
- vi.spyOn(model, 'stream').mockImplementation((messages, options) => {
979
- roleSnapshots.push(messages.map((m) => m.role));
980
- return originalStream(messages, options);
981
- });
982
- const agent = new Agent({ model, structuredOutputSchema: schema });
983
- await agent.invoke('Test');
984
- expect(roleSnapshots.length).toBeGreaterThanOrEqual(2);
985
- // The forced-retry (second) call must not see a conversation ending with an assistant turn.
986
- const secondCallRoles = roleSnapshots[1];
987
- expect(secondCallRoles[secondCallRoles.length - 1]).toBe('user');
988
- });
989
- it('throws StructuredOutputError when model refuses to use tool after forcing', async () => {
990
- const schema = z.object({ value: z.number() });
991
- // Model returns text twice - once normally, once when forced
992
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response' });
993
- const agent = new Agent({ model, structuredOutputSchema: schema });
994
- await expect(agent.invoke('Test')).rejects.toThrow(StructuredOutputError);
995
- });
996
- it('throws MaxTokensError when maxTokens reached before structured output', async () => {
997
- const schema = z.object({ value: z.number() });
998
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Partial...' }, { stopReason: 'maxTokens' });
999
- const agent = new Agent({ model, structuredOutputSchema: schema });
1000
- await expect(agent.invoke('Test')).rejects.toThrow(MaxTokensError);
1001
- });
1002
- it('retries with validation feedback when structured output tool returns error', async () => {
1003
- const schema = z.object({ name: z.string(), age: z.number() });
1004
- const model = new MockMessageModel()
1005
- .addTurn({
1006
- type: 'toolUseBlock',
1007
- name: 'strands_structured_output',
1008
- toolUseId: 'tool-1',
1009
- input: { name: 'John', age: 'invalid' },
1010
- })
1011
- .addTurn({
1012
- type: 'toolUseBlock',
1013
- name: 'strands_structured_output',
1014
- toolUseId: 'tool-2',
1015
- input: { name: 'John', age: 30 },
1016
- })
1017
- .addTurn({ type: 'textBlock', text: 'Done' });
1018
- const agent = new Agent({ model, structuredOutputSchema: schema });
1019
- const result = await agent.invoke('Test');
1020
- expect(result.structuredOutput).toEqual({ name: 'John', age: 30 });
1021
- });
1022
- it('works without structured output schema', async () => {
1023
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Hello' });
1024
- const agent = new Agent({ model });
1025
- const result = await agent.invoke('Test');
1026
- expect(result.structuredOutput).toBeUndefined();
1027
- });
1028
- it('cleans up structured output tool after invocation', async () => {
1029
- const schema = z.object({ value: z.number() });
1030
- const model = new MockMessageModel()
1031
- .addTurn({ type: 'toolUseBlock', name: 'strands_structured_output', toolUseId: 'tool-1', input: { value: 42 } })
1032
- .addTurn({ type: 'textBlock', text: 'Done' });
1033
- const agent = new Agent({ model, structuredOutputSchema: schema });
1034
- await agent.invoke('Test');
1035
- const toolNames = agent.tools.map((t) => t.name);
1036
- expect(toolNames).not.toContain('strands_structured_output');
1037
- });
1038
- it('cleans up structured output tool even when error occurs', async () => {
1039
- const schema = z.object({ value: z.number() });
1040
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Partial...' }, { stopReason: 'maxTokens' });
1041
- const agent = new Agent({ model, structuredOutputSchema: schema });
1042
- await expect(agent.invoke('Test')).rejects.toThrow();
1043
- const toolNames = agent.tools.map((t) => t.name);
1044
- expect(toolNames).not.toContain('strands_structured_output');
1045
- });
1046
- it('validates nested objects in structured output', async () => {
1047
- const schema = z.object({
1048
- user: z.object({
1049
- name: z.string(),
1050
- age: z.number(),
1051
- }),
1052
- });
1053
- const model = new MockMessageModel()
1054
- .addTurn({
1055
- type: 'toolUseBlock',
1056
- name: 'strands_structured_output',
1057
- toolUseId: 'tool-1',
1058
- input: { user: { name: 'Alice', age: 25 } },
1059
- })
1060
- .addTurn({ type: 'textBlock', text: 'Done' });
1061
- const agent = new Agent({ model, structuredOutputSchema: schema });
1062
- const result = await agent.invoke('Test');
1063
- expect(result.structuredOutput).toEqual({ user: { name: 'Alice', age: 25 } });
1064
- });
1065
- it('validates arrays in structured output', async () => {
1066
- const schema = z.object({
1067
- items: z.array(z.string()),
1068
- });
1069
- const model = new MockMessageModel()
1070
- .addTurn({
1071
- type: 'toolUseBlock',
1072
- name: 'strands_structured_output',
1073
- toolUseId: 'tool-1',
1074
- input: { items: ['a', 'b', 'c'] },
1075
- })
1076
- .addTurn({ type: 'textBlock', text: 'Done' });
1077
- const agent = new Agent({ model, structuredOutputSchema: schema });
1078
- const result = await agent.invoke('Test');
1079
- expect(result.structuredOutput).toEqual({ items: ['a', 'b', 'c'] });
1080
- });
1081
- it('uses per-invocation override schema and restores constructor schema on next call', async () => {
1082
- const constructorSchema = z.object({ name: z.string() });
1083
- const overrideSchema = z.object({ value: z.number() });
1084
- const model = new MockMessageModel()
1085
- .addTurn({
1086
- type: 'toolUseBlock',
1087
- name: 'strands_structured_output',
1088
- toolUseId: 'tool-1',
1089
- input: { value: 99 },
1090
- })
1091
- .addTurn({ type: 'textBlock', text: 'Done' })
1092
- .addTurn({
1093
- type: 'toolUseBlock',
1094
- name: 'strands_structured_output',
1095
- toolUseId: 'tool-2',
1096
- input: { name: 'Bob' },
1097
- })
1098
- .addTurn({ type: 'textBlock', text: 'Done' });
1099
- const agent = new Agent({ model, structuredOutputSchema: constructorSchema });
1100
- const first = await agent.invoke('First', { structuredOutputSchema: overrideSchema });
1101
- expect(first.structuredOutput).toEqual({ value: 99 });
1102
- const second = await agent.invoke('Second');
1103
- expect(second.structuredOutput).toEqual({ name: 'Bob' });
1104
- });
1105
- it('skips structured output extraction when AfterToolsEvent.endTurn halts the loop', async () => {
1106
- const schema = z.object({ name: z.string() });
1107
- const model = new MockMessageModel()
1108
- .addTurn({
1109
- type: 'toolUseBlock',
1110
- name: 'strands_structured_output',
1111
- toolUseId: 'tool-1',
1112
- input: { name: 'John' },
1113
- })
1114
- .addTurn({ type: 'textBlock', text: 'Done' });
1115
- const agent = new Agent({ model, structuredOutputSchema: schema });
1116
- agent.addHook(AfterToolsEvent, (event) => {
1117
- event.endTurn = true;
1118
- });
1119
- const result = await agent.invoke('Test');
1120
- expect(result.stopReason).toBe('endTurn');
1121
- expect(result.structuredOutput).toBeUndefined();
1122
- expect(model.callCount).toBe(1);
1123
- });
1124
- });
1125
- });
1126
- describe('Agent._redactLastMessage', () => {
1127
- const redactMessage = '[REDACTED]';
1128
- it('redacts last user message with only text blocks', () => {
1129
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response' });
1130
- const agent = new Agent({ model });
1131
- // Add a user message
1132
- agent['messages'].push(new Message({
1133
- role: 'user',
1134
- content: [new TextBlock('sensitive content')],
1135
- }));
1136
- agent['_redactLastMessage'](redactMessage);
1137
- const lastMessage = agent['messages'][agent['messages'].length - 1];
1138
- expect(lastMessage.role).toBe('user');
1139
- expect(lastMessage.content).toHaveLength(1);
1140
- expect(lastMessage.content[0].type).toBe('textBlock');
1141
- expect(lastMessage.content[0].text).toBe(redactMessage);
1142
- });
1143
- it('preserves tool result blocks with redacted content', () => {
1144
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response' });
1145
- const agent = new Agent({ model });
1146
- // Add a user message with tool result and text blocks
1147
- agent['messages'].push(new Message({
1148
- role: 'user',
1149
- content: [
1150
- new TextBlock('some text'),
1151
- new ToolResultBlock({
1152
- toolUseId: 'tool-1',
1153
- status: 'success',
1154
- content: [new TextBlock('tool result content')],
1155
- }),
1156
- new TextBlock('more text'),
1157
- new ToolResultBlock({
1158
- toolUseId: 'tool-2',
1159
- status: 'error',
1160
- content: [new TextBlock('error content')],
1161
- }),
1162
- ],
1163
- }));
1164
- agent['_redactLastMessage'](redactMessage);
1165
- const lastMessage = agent['messages'][agent['messages'].length - 1];
1166
- expect(lastMessage.role).toBe('user');
1167
- expect(lastMessage.content).toHaveLength(2);
1168
- // Only tool result blocks should remain
1169
- expect(lastMessage.content[0].type).toBe('toolResultBlock');
1170
- expect(lastMessage.content[1].type).toBe('toolResultBlock');
1171
- // Tool result blocks should have redacted content but preserve structure
1172
- const toolResult1 = lastMessage.content[0];
1173
- expect(toolResult1.toolUseId).toBe('tool-1');
1174
- expect(toolResult1.status).toBe('success');
1175
- expect(toolResult1.content).toHaveLength(1);
1176
- expect(toolResult1.content[0].text).toBe(redactMessage);
1177
- const toolResult2 = lastMessage.content[1];
1178
- expect(toolResult2.toolUseId).toBe('tool-2');
1179
- expect(toolResult2.status).toBe('error');
1180
- expect(toolResult2.content).toHaveLength(1);
1181
- expect(toolResult2.content[0].text).toBe(redactMessage);
1182
- });
1183
- it('does not redact when last message is not from user', () => {
1184
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response' });
1185
- const agent = new Agent({ model });
1186
- // Add an assistant message
1187
- const assistantMessage = new Message({
1188
- role: 'assistant',
1189
- content: [new TextBlock('assistant response')],
1190
- });
1191
- agent['messages'].push(assistantMessage);
1192
- const originalContent = assistantMessage.content;
1193
- agent['_redactLastMessage'](redactMessage);
1194
- const lastMessage = agent['messages'][agent['messages'].length - 1];
1195
- expect(lastMessage.role).toBe('assistant');
1196
- expect(lastMessage.content).toBe(originalContent);
1197
- });
1198
- it('handles empty messages array gracefully', () => {
1199
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'Response' });
1200
- const agent = new Agent({ model });
1201
- expect(() => agent['_redactLastMessage'](redactMessage)).not.toThrow();
1202
- expect(agent['messages']).toHaveLength(0);
1203
- });
1204
- });
1205
- describe('_estimateInputTokens', () => {
1206
- function captureProjectedTokens(agent) {
1207
- return new Promise((resolve) => {
1208
- agent.addHook(BeforeModelCallEvent, (event) => {
1209
- resolve(event.projectedInputTokens);
1210
- });
1211
- });
1212
- }
1213
- it('uses full estimation on cold start (no prior usage metadata)', async () => {
1214
- const model = new MockMessageModel();
1215
- model.addTurn({ type: 'textBlock', text: 'Hello' });
1216
- const countTokensSpy = vi.spyOn(model, 'countTokens');
1217
- countTokensSpy.mockResolvedValue(42);
1218
- const agent = new Agent({ model, printer: false });
1219
- const tokenPromise = captureProjectedTokens(agent);
1220
- await agent.invoke('Hi');
1221
- expect(await tokenPromise).toBe(42);
1222
- expect(countTokensSpy).toHaveBeenCalledWith(expect.any(Array), expect.any(Object));
1223
- });
1224
- it('uses known baseline when no new messages after last assistant', async () => {
1225
- const model = new MockMessageModel();
1226
- model.addTurn({ type: 'textBlock', text: 'Hello' });
1227
- const agent = new Agent({
1228
- model,
1229
- printer: false,
1230
- messages: [
1231
- new Message({ role: 'user', content: [new TextBlock('Hi')] }),
1232
- new Message({
1233
- role: 'assistant',
1234
- content: [new TextBlock('Hello')],
1235
- metadata: { usage: { inputTokens: 100, outputTokens: 20, totalTokens: 120 } },
1236
- }),
1237
- ],
1238
- });
1239
- // Invoke with no args — no new user message appended, so the last assistant
1240
- // message is still the final message and newMessages.length === 0
1241
- const tokenPromise = captureProjectedTokens(agent);
1242
- await agent.invoke([]);
1243
- // baseline = inputTokens(100) + outputTokens(20) = 120
1244
- expect(await tokenPromise).toBe(120);
1245
- });
1246
- it('returns undefined projectedInputTokens when estimation fails', async () => {
1247
- const model = new MockMessageModel();
1248
- model.addTurn({ type: 'textBlock', text: 'Hello' });
1249
- vi.spyOn(model, 'countTokens').mockRejectedValue(new Error('API unavailable'));
1250
- const agent = new Agent({ model, printer: false });
1251
- const tokenPromise = captureProjectedTokens(agent);
1252
- await agent.invoke('Hi');
1253
- expect(await tokenPromise).toBeUndefined();
1254
- });
1255
- it('estimates delta for new messages after last assistant', async () => {
1256
- const model = new MockMessageModel();
1257
- model
1258
- .addTurn([{ type: 'toolUseBlock', name: 'test', toolUseId: 'id-1', input: {} }], {
1259
- usage: { inputTokens: 100, outputTokens: 30, totalTokens: 130 },
1260
- })
1261
- .addTurn({ type: 'textBlock', text: 'Done' });
1262
- const countTokensSpy = vi.spyOn(model, 'countTokens');
1263
- countTokensSpy.mockResolvedValue(50);
1264
- const tool = createMockTool('test', () => new ToolResultBlock({
1265
- toolUseId: 'id-1',
1266
- status: 'success',
1267
- content: [new TextBlock('result')],
1268
- }));
1269
- const agent = new Agent({ model, tools: [tool], printer: false });
1270
- // Capture the second BeforeModelCallEvent (after tool execution)
1271
- let callCount = 0;
1272
- const tokenPromise = new Promise((resolve) => {
1273
- agent.addHook(BeforeModelCallEvent, (event) => {
1274
- callCount++;
1275
- if (callCount === 2)
1276
- resolve(event.projectedInputTokens);
1277
- });
1278
- });
1279
- await agent.invoke('Use the tool');
1280
- // baseline (100+30) + estimated delta (50) = 180
1281
- expect(await tokenPromise).toBe(180);
1282
- expect(countTokensSpy).toHaveBeenCalled();
1283
- });
1284
- it('uses baseline from prior invocation on second invoke', async () => {
1285
- const model = new MockMessageModel();
1286
- model
1287
- .addTurn({ type: 'textBlock', text: 'First response' }, { usage: { inputTokens: 200, outputTokens: 50, totalTokens: 250 } })
1288
- .addTurn({ type: 'textBlock', text: 'Second response' });
1289
- const countTokensSpy = vi.spyOn(model, 'countTokens');
1290
- countTokensSpy.mockResolvedValue(15);
1291
- const agent = new Agent({ model, printer: false });
1292
- await agent.invoke('First question');
1293
- // Second invocation — the user message "Second question" is appended after
1294
- // the assistant message with usage metadata, so it hits the baseline + delta path
1295
- const tokenPromise = captureProjectedTokens(agent);
1296
- await agent.invoke('Second question');
1297
- // baseline (200+50) + estimated delta for new user message (15) = 265
1298
- expect(await tokenPromise).toBe(265);
1299
- });
1300
- });
1301
- describe('normalizeToolUseNames', () => {
1302
- it('replaces invalid tool-use names with INVALID_TOOL_NAME before calling model', async () => {
1303
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'ok' });
1304
- const streamSpy = vi.spyOn(model, 'stream');
1305
- const agent = new Agent({
1306
- model,
1307
- printer: false,
1308
- messages: [
1309
- new Message({ role: 'user', content: [new TextBlock('do thing')] }),
1310
- new Message({
1311
- role: 'assistant',
1312
- content: [new ToolUseBlock({ name: 'bad name!', toolUseId: 'tu-1', input: {} })],
1313
- }),
1314
- new Message({
1315
- role: 'user',
1316
- content: [
1317
- new ToolResultBlock({
1318
- toolUseId: 'tu-1',
1319
- status: 'success',
1320
- content: [new TextBlock('result')],
1321
- }),
1322
- ],
1323
- }),
1324
- ],
1325
- });
1326
- await agent.invoke('continue');
1327
- const sentMessages = streamSpy.mock.calls[0]?.[0];
1328
- const sentToolUse = sentMessages
1329
- .find((m) => m.role === 'assistant')
1330
- .content.find((b) => b.type === 'toolUseBlock');
1331
- expect(sentToolUse).toStrictEqual(new ToolUseBlock({ name: 'INVALID_TOOL_NAME', toolUseId: 'tu-1', input: {} }));
1332
- // Agent's stored history is not mutated.
1333
- const storedToolUse = agent.messages
1334
- .find((m) => m.role === 'assistant')
1335
- .content.find((b) => b.type === 'toolUseBlock');
1336
- expect(storedToolUse).toStrictEqual(new ToolUseBlock({ name: 'bad name!', toolUseId: 'tu-1', input: {} }));
1337
- });
1338
- it('preserves reasoningSignature on replaced tool-use blocks', async () => {
1339
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'ok' });
1340
- const streamSpy = vi.spyOn(model, 'stream');
1341
- const agent = new Agent({
1342
- model,
1343
- printer: false,
1344
- messages: [
1345
- new Message({ role: 'user', content: [new TextBlock('do thing')] }),
1346
- new Message({
1347
- role: 'assistant',
1348
- content: [new ToolUseBlock({ name: 'bad!', toolUseId: 'tu-1', input: {}, reasoningSignature: 'sig-abc' })],
1349
- }),
1350
- new Message({
1351
- role: 'user',
1352
- content: [new ToolResultBlock({ toolUseId: 'tu-1', status: 'success', content: [new TextBlock('ok')] })],
1353
- }),
1354
- ],
1355
- });
1356
- await agent.invoke('continue');
1357
- const sentMessages = streamSpy.mock.calls[0]?.[0];
1358
- const sentToolUse = sentMessages
1359
- .find((m) => m.role === 'assistant')
1360
- .content.find((b) => b.type === 'toolUseBlock');
1361
- expect(sentToolUse).toStrictEqual(new ToolUseBlock({
1362
- name: 'INVALID_TOOL_NAME',
1363
- toolUseId: 'tu-1',
1364
- input: {},
1365
- reasoningSignature: 'sig-abc',
1366
- }));
1367
- });
1368
- it('leaves valid names untouched', async () => {
1369
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'ok' });
1370
- const streamSpy = vi.spyOn(model, 'stream');
1371
- const agent = new Agent({
1372
- model,
1373
- printer: false,
1374
- messages: [
1375
- new Message({ role: 'user', content: [new TextBlock('do thing')] }),
1376
- new Message({
1377
- role: 'assistant',
1378
- content: [new ToolUseBlock({ name: 'good_tool-1', toolUseId: 'tu-1', input: {} })],
1379
- }),
1380
- new Message({
1381
- role: 'user',
1382
- content: [
1383
- new ToolResultBlock({
1384
- toolUseId: 'tu-1',
1385
- status: 'success',
1386
- content: [new TextBlock('result')],
1387
- }),
1388
- ],
1389
- }),
1390
- ],
1391
- });
1392
- await agent.invoke('continue');
1393
- const sentMessages = streamSpy.mock.calls[0]?.[0];
1394
- const sentToolUse = sentMessages
1395
- .find((m) => m.role === 'assistant')
1396
- .content.find((b) => b.type === 'toolUseBlock');
1397
- expect(sentToolUse).toStrictEqual(new ToolUseBlock({ name: 'good_tool-1', toolUseId: 'tu-1', input: {} }));
1398
- });
1399
- describe('MCP toolsChanged integration', () => {
1400
- it('removes old tools and adds new tools when onToolsChanged fires', async () => {
1401
- const mcpClient = new McpClient({
1402
- transport: { start: vi.fn(), send: vi.fn(), close: vi.fn() },
1403
- });
1404
- const initialTools = [
1405
- new McpTool({ name: 'tool_a', description: 'A', inputSchema: {}, client: mcpClient }),
1406
- new McpTool({ name: 'tool_b', description: 'B', inputSchema: {}, client: mcpClient }),
1407
- ];
1408
- vi.spyOn(mcpClient, 'listTools').mockResolvedValue(initialTools);
1409
- let capturedCallback;
1410
- const setterSpy = vi.spyOn(McpClient.prototype, 'onToolsChanged', 'set').mockImplementation((cb) => {
1411
- capturedCallback = cb;
1412
- });
1413
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'done' });
1414
- const agent = new Agent({ model, tools: [mcpClient] });
1415
- await agent.initialize();
1416
- expect(agent.tools.map((t) => t.name)).toEqual(['tool_a', 'tool_b']);
1417
- expect(capturedCallback).toBeDefined();
1418
- const newTools = [
1419
- new McpTool({ name: 'tool_b', description: 'B-updated', inputSchema: {}, client: mcpClient }),
1420
- new McpTool({ name: 'tool_c', description: 'C', inputSchema: {}, client: mcpClient }),
1421
- ];
1422
- capturedCallback(['tool_a', 'tool_b'], newTools);
1423
- expect(agent.tools.map((t) => t.name)).toEqual(['tool_b', 'tool_c']);
1424
- expect(agent.tools.find((t) => t.name === 'tool_b').description).toBe('B-updated');
1425
- setterSpy.mockRestore();
1426
- });
1427
- });
1428
- describe('limits', () => {
1429
- const toolUseTurn = (toolUseId, usage) => [
1430
- { type: 'toolUseBlock', name: 'loop', toolUseId, input: {} },
1431
- { usage },
1432
- ];
1433
- const passthroughTool = () => createMockTool('loop', (context) => new ToolResultBlock({
1434
- toolUseId: context.toolUse.toolUseId,
1435
- status: 'success',
1436
- content: [new TextBlock('ok')],
1437
- }));
1438
- describe('when limits.turns is reached', () => {
1439
- it('runs the cycle to completion and bails at top of next iteration', async () => {
1440
- const model = new MockMessageModel()
1441
- .addTurn(...toolUseTurn('tool-1', { inputTokens: 10, outputTokens: 5, totalTokens: 15 }))
1442
- .addTurn(...toolUseTurn('tool-2', { inputTokens: 20, outputTokens: 5, totalTokens: 25 }));
1443
- const agent = new Agent({ model, tools: [passthroughTool()] });
1444
- const result = await agent.invoke('go', { limits: { turns: 1 } });
1445
- // Bail after tools — lastMessage is the user toolResult, so we don't
1446
- // use expectAgentResult (which assumes role 'assistant').
1447
- expect(result).toEqual(expect.objectContaining({
1448
- type: 'agentResult',
1449
- stopReason: 'limitTurns',
1450
- lastMessage: expect.objectContaining({
1451
- role: 'user',
1452
- content: expect.arrayContaining([expect.any(ToolResultBlock)]),
1453
- }),
1454
- metrics: expectLoopMetrics({
1455
- cycleCount: 1,
1456
- toolNames: ['loop'],
1457
- usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
1458
- }),
1459
- }));
1460
- });
1461
- });
1462
- describe('when limits is generous', () => {
1463
- it('does not trip and the model ends naturally', async () => {
1464
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'done' }, { usage: { inputTokens: 5, outputTokens: 5, totalTokens: 10 } });
1465
- const agent = new Agent({ model });
1466
- const result = await agent.invoke('go', { limits: { turns: 5, outputTokens: 1000, totalTokens: 1000 } });
1467
- expect(result).toEqual(expectAgentResult({
1468
- stopReason: 'endTurn',
1469
- messageText: 'done',
1470
- cycleCount: 1,
1471
- usage: { inputTokens: 5, outputTokens: 5, totalTokens: 10 },
1472
- }));
1473
- });
1474
- });
1475
- describe('when limits.outputTokens is reached', () => {
1476
- it('returns limitOutputTokens once cumulative outputTokens hits the cap', async () => {
1477
- const model = new MockMessageModel()
1478
- .addTurn(...toolUseTurn('tool-1', { inputTokens: 10, outputTokens: 60, totalTokens: 70 }))
1479
- .addTurn(...toolUseTurn('tool-2', { inputTokens: 10, outputTokens: 60, totalTokens: 70 }));
1480
- const agent = new Agent({ model, tools: [passthroughTool()] });
1481
- const result = await agent.invoke('go', { limits: { outputTokens: 100 } });
1482
- expect(result).toEqual(expect.objectContaining({
1483
- type: 'agentResult',
1484
- stopReason: 'limitOutputTokens',
1485
- lastMessage: expect.objectContaining({
1486
- role: 'user',
1487
- content: expect.arrayContaining([expect.any(ToolResultBlock)]),
1488
- }),
1489
- metrics: expectLoopMetrics({
1490
- cycleCount: 2,
1491
- toolNames: ['loop'],
1492
- usage: { inputTokens: 20, outputTokens: 120, totalTokens: 140 },
1493
- }),
1494
- }));
1495
- });
1496
- it('uses at-most (>=) semantics: stops when count exactly equals the cap', async () => {
1497
- const model = new MockMessageModel()
1498
- .addTurn(...toolUseTurn('tool-1', { inputTokens: 10, outputTokens: 100, totalTokens: 110 }))
1499
- .addTurn(...toolUseTurn('tool-2', { inputTokens: 10, outputTokens: 100, totalTokens: 110 }));
1500
- const agent = new Agent({ model, tools: [passthroughTool()] });
1501
- const result = await agent.invoke('go', { limits: { outputTokens: 100 } });
1502
- expect(result).toEqual(expect.objectContaining({
1503
- type: 'agentResult',
1504
- stopReason: 'limitOutputTokens',
1505
- metrics: expectLoopMetrics({
1506
- cycleCount: 1,
1507
- toolNames: ['loop'],
1508
- usage: { inputTokens: 10, outputTokens: 100, totalTokens: 110 },
1509
- }),
1510
- }));
1511
- });
1512
- });
1513
- describe('when limits.totalTokens is reached', () => {
1514
- it('returns limitTotalTokens once cumulative totalTokens hits the cap', async () => {
1515
- const model = new MockMessageModel()
1516
- .addTurn(...toolUseTurn('tool-1', { inputTokens: 200, outputTokens: 100, totalTokens: 300 }))
1517
- .addTurn(...toolUseTurn('tool-2', { inputTokens: 200, outputTokens: 100, totalTokens: 300 }));
1518
- const agent = new Agent({ model, tools: [passthroughTool()] });
1519
- const result = await agent.invoke('go', { limits: { totalTokens: 500 } });
1520
- expect(result).toEqual(expect.objectContaining({
1521
- type: 'agentResult',
1522
- stopReason: 'limitTotalTokens',
1523
- lastMessage: expect.objectContaining({
1524
- role: 'user',
1525
- content: expect.arrayContaining([expect.any(ToolResultBlock)]),
1526
- }),
1527
- metrics: expectLoopMetrics({
1528
- cycleCount: 2,
1529
- toolNames: ['loop'],
1530
- usage: { inputTokens: 400, outputTokens: 200, totalTokens: 600 },
1531
- }),
1532
- }));
1533
- });
1534
- });
1535
- describe('when the model ends naturally on the same turn the limit would trip', () => {
1536
- it('returns endTurn — the model answer wins', async () => {
1537
- const model = new MockMessageModel().addTurn({ type: 'textBlock', text: 'final answer' }, { usage: { inputTokens: 300, outputTokens: 300, totalTokens: 600 } });
1538
- const agent = new Agent({ model });
1539
- const result = await agent.invoke('go', { limits: { totalTokens: 500 } });
1540
- expect(result).toEqual(expectAgentResult({
1541
- stopReason: 'endTurn',
1542
- messageText: 'final answer',
1543
- cycleCount: 1,
1544
- usage: { inputTokens: 300, outputTokens: 300, totalTokens: 600 },
1545
- }));
1546
- });
1547
- });
1548
- describe('when multiple limits trip simultaneously', () => {
1549
- const heavyUsage = { inputTokens: 100, outputTokens: 100, totalTokens: 200 };
1550
- const buildAgent = () => {
1551
- const model = new MockMessageModel()
1552
- .addTurn(...toolUseTurn('tool-1', heavyUsage))
1553
- .addTurn(...toolUseTurn('tool-2', heavyUsage));
1554
- return new Agent({ model, tools: [passthroughTool()] });
1555
- };
1556
- it('prefers turns when all three trip', async () => {
1557
- const result = await buildAgent().invoke('go', {
1558
- limits: { turns: 1, totalTokens: 1, outputTokens: 1 },
1559
- });
1560
- expect(result).toEqual(expect.objectContaining({
1561
- type: 'agentResult',
1562
- stopReason: 'limitTurns',
1563
- metrics: expectLoopMetrics({ cycleCount: 1, toolNames: ['loop'] }),
1564
- }));
1565
- });
1566
- it('prefers totalTokens over outputTokens', async () => {
1567
- const result = await buildAgent().invoke('go', { limits: { totalTokens: 1, outputTokens: 1 } });
1568
- expect(result).toEqual(expect.objectContaining({
1569
- type: 'agentResult',
1570
- stopReason: 'limitTotalTokens',
1571
- metrics: expectLoopMetrics({ cycleCount: 1, toolNames: ['loop'] }),
1572
- }));
1573
- });
1574
- it('falls back to outputTokens when no higher-priority cap is set', async () => {
1575
- const result = await buildAgent().invoke('go', { limits: { outputTokens: 1 } });
1576
- expect(result).toEqual(expect.objectContaining({
1577
- type: 'agentResult',
1578
- stopReason: 'limitOutputTokens',
1579
- metrics: expectLoopMetrics({ cycleCount: 1, toolNames: ['loop'] }),
1580
- }));
1581
- });
1582
- });
1583
- describe('when the same agent is reused across invocations', () => {
1584
- it('scopes the limit to the current invocation, not lifetime', async () => {
1585
- // Each turn uses 50 output tokens. With limits.outputTokens: 75, a single
1586
- // invocation tolerates one turn but trips on the second. If the cap
1587
- // were lifetime-scoped, the second `invoke()` would trip on its first
1588
- // turn (75 cumulative across both calls).
1589
- const model = new MockMessageModel()
1590
- .addTurn({ type: 'textBlock', text: 'first' }, { usage: { inputTokens: 10, outputTokens: 50, totalTokens: 60 } })
1591
- .addTurn({ type: 'textBlock', text: 'second' }, { usage: { inputTokens: 10, outputTokens: 50, totalTokens: 60 } });
1592
- const agent = new Agent({ model });
1593
- const r1 = await agent.invoke('go', { limits: { outputTokens: 75 } });
1594
- expect(r1.stopReason).toBe('endTurn');
1595
- expect(r1.metrics?.latestAgentInvocation?.cycles.length).toBe(1);
1596
- const r2 = await agent.invoke('go again', { limits: { outputTokens: 75 } });
1597
- expect(r2.stopReason).toBe('endTurn');
1598
- expect(r2.metrics?.latestAgentInvocation?.cycles.length).toBe(1);
1599
- });
1600
- });
1601
- describe('when a limit is invalid', () => {
1602
- it.each([
1603
- ['negative', { limits: { turns: -1 } }],
1604
- ['zero', { limits: { turns: 0 } }],
1605
- ['NaN', { limits: { outputTokens: NaN } }],
1606
- ['Infinity', { limits: { totalTokens: Infinity } }],
1607
- ])('rejects %s with TypeError', async (_label, options) => {
1608
- const agent = new Agent({ model: new MockMessageModel().addTurn({ type: 'textBlock', text: 'never reached' }) });
1609
- await expect(agent.invoke('go', options)).rejects.toThrow(TypeError);
1610
- });
1611
- });
1612
- describe('when invoked via stream()', () => {
1613
- it('returns limitTurns as the generator return value', async () => {
1614
- const model = new MockMessageModel()
1615
- .addTurn(...toolUseTurn('tool-1', { inputTokens: 10, outputTokens: 5, totalTokens: 15 }))
1616
- .addTurn(...toolUseTurn('tool-2', { inputTokens: 10, outputTokens: 5, totalTokens: 15 }));
1617
- const agent = new Agent({ model, tools: [passthroughTool()] });
1618
- const { result } = await collectGenerator(agent.stream('go', { limits: { turns: 1 } }));
1619
- expect(result).toEqual(expect.objectContaining({ type: 'agentResult', stopReason: 'limitTurns' }));
1620
- });
1621
- });
1622
- });
1623
- });
1624
- //# sourceMappingURL=agent.test.js.map