@strands-agents/sdk 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (435) hide show
  1. package/README.md +11 -11
  2. package/dist/src/__fixtures__/agent-helpers.d.ts.map +1 -1
  3. package/dist/src/__fixtures__/agent-helpers.js +9 -0
  4. package/dist/src/__fixtures__/agent-helpers.js.map +1 -1
  5. package/dist/src/__fixtures__/register-node-defaults.d.ts +2 -0
  6. package/dist/src/__fixtures__/register-node-defaults.d.ts.map +1 -0
  7. package/dist/src/__fixtures__/register-node-defaults.js +6 -0
  8. package/dist/src/__fixtures__/register-node-defaults.js.map +1 -0
  9. package/dist/src/__fixtures__/test-sandbox.node.d.ts.map +1 -1
  10. package/dist/src/__fixtures__/test-sandbox.node.js +4 -3
  11. package/dist/src/__fixtures__/test-sandbox.node.js.map +1 -1
  12. package/dist/src/__tests__/default-slot.test.d.ts +2 -0
  13. package/dist/src/__tests__/default-slot.test.d.ts.map +1 -0
  14. package/dist/src/__tests__/default-slot.test.js +33 -0
  15. package/dist/src/__tests__/default-slot.test.js.map +1 -0
  16. package/dist/src/a2a/__tests__/async-lock.test.d.ts +2 -0
  17. package/dist/src/a2a/__tests__/async-lock.test.d.ts.map +1 -0
  18. package/dist/src/a2a/__tests__/async-lock.test.js +137 -0
  19. package/dist/src/a2a/__tests__/async-lock.test.js.map +1 -0
  20. package/dist/src/a2a/__tests__/executor.test.js +146 -8
  21. package/dist/src/a2a/__tests__/executor.test.js.map +1 -1
  22. package/dist/src/a2a/__tests__/server.test.js +20 -0
  23. package/dist/src/a2a/__tests__/server.test.js.map +1 -1
  24. package/dist/src/a2a/async-lock.d.ts +22 -0
  25. package/dist/src/a2a/async-lock.d.ts.map +1 -0
  26. package/dist/src/a2a/async-lock.js +38 -0
  27. package/dist/src/a2a/async-lock.js.map +1 -0
  28. package/dist/src/a2a/executor.d.ts +59 -24
  29. package/dist/src/a2a/executor.d.ts.map +1 -1
  30. package/dist/src/a2a/executor.js +209 -32
  31. package/dist/src/a2a/executor.js.map +1 -1
  32. package/dist/src/a2a/index.d.ts +1 -1
  33. package/dist/src/a2a/index.d.ts.map +1 -1
  34. package/dist/src/a2a/index.js +1 -1
  35. package/dist/src/a2a/index.js.map +1 -1
  36. package/dist/src/a2a/server.d.ts +18 -2
  37. package/dist/src/a2a/server.d.ts.map +1 -1
  38. package/dist/src/a2a/server.js +13 -2
  39. package/dist/src/a2a/server.js.map +1 -1
  40. package/dist/src/agent/__tests__/agent.context-manager.test.d.ts +2 -0
  41. package/dist/src/agent/__tests__/agent.context-manager.test.d.ts.map +1 -0
  42. package/dist/src/agent/__tests__/agent.context-manager.test.js +107 -0
  43. package/dist/src/agent/__tests__/agent.context-manager.test.js.map +1 -0
  44. package/dist/src/agent/__tests__/agent.stateful-model.test.js +2 -2
  45. package/dist/src/agent/__tests__/agent.stateful-model.test.js.map +1 -1
  46. package/dist/src/agent/__tests__/agent.tracer.test.node.js +14 -0
  47. package/dist/src/agent/__tests__/agent.tracer.test.node.js.map +1 -1
  48. package/dist/src/agent/agent.d.ts +135 -2
  49. package/dist/src/agent/agent.d.ts.map +1 -1
  50. package/dist/src/agent/agent.js +506 -189
  51. package/dist/src/agent/agent.js.map +1 -1
  52. package/dist/src/context-manager/modes/agentic/agentic-context.d.ts +19 -0
  53. package/dist/src/context-manager/modes/agentic/agentic-context.d.ts.map +1 -0
  54. package/dist/src/context-manager/modes/agentic/agentic-context.js +245 -0
  55. package/dist/src/context-manager/modes/agentic/agentic-context.js.map +1 -0
  56. package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts +2 -0
  57. package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts.map +1 -0
  58. package/dist/src/conversation-manager/__tests__/agentic-context.test.js +332 -0
  59. package/dist/src/conversation-manager/__tests__/agentic-context.test.js.map +1 -0
  60. package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts +2 -0
  61. package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts.map +1 -0
  62. package/dist/src/conversation-manager/__tests__/context-compression.test.js +176 -0
  63. package/dist/src/conversation-manager/__tests__/context-compression.test.js.map +1 -0
  64. package/dist/src/conversation-manager/__tests__/pin.test.d.ts +2 -0
  65. package/dist/src/conversation-manager/__tests__/pin.test.d.ts.map +1 -0
  66. package/dist/src/conversation-manager/__tests__/pin.test.js +119 -0
  67. package/dist/src/conversation-manager/__tests__/pin.test.js.map +1 -0
  68. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js +49 -0
  69. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js.map +1 -1
  70. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js +58 -0
  71. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js.map +1 -1
  72. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.d.ts +2 -0
  73. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.d.ts.map +1 -0
  74. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js +138 -0
  75. package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js.map +1 -0
  76. package/dist/src/conversation-manager/compression/context-compression.d.ts +39 -0
  77. package/dist/src/conversation-manager/compression/context-compression.d.ts.map +1 -0
  78. package/dist/src/conversation-manager/compression/context-compression.js +150 -0
  79. package/dist/src/conversation-manager/compression/context-compression.js.map +1 -0
  80. package/dist/src/conversation-manager/compression/pin-message.d.ts +45 -0
  81. package/dist/src/conversation-manager/compression/pin-message.d.ts.map +1 -0
  82. package/dist/src/conversation-manager/compression/pin-message.js +106 -0
  83. package/dist/src/conversation-manager/compression/pin-message.js.map +1 -0
  84. package/dist/src/conversation-manager/conversation-manager.d.ts +2 -0
  85. package/dist/src/conversation-manager/conversation-manager.d.ts.map +1 -1
  86. package/dist/src/conversation-manager/conversation-manager.js +2 -2
  87. package/dist/src/conversation-manager/conversation-manager.js.map +1 -1
  88. package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts +7 -0
  89. package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts.map +1 -1
  90. package/dist/src/conversation-manager/sliding-window-conversation-manager.js +30 -38
  91. package/dist/src/conversation-manager/sliding-window-conversation-manager.js.map +1 -1
  92. package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts +7 -19
  93. package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts.map +1 -1
  94. package/dist/src/conversation-manager/summarizing-conversation-manager.js +20 -109
  95. package/dist/src/conversation-manager/summarizing-conversation-manager.js.map +1 -1
  96. package/dist/src/default-slot.d.ts +6 -0
  97. package/dist/src/default-slot.d.ts.map +1 -0
  98. package/dist/src/default-slot.js +18 -0
  99. package/dist/src/default-slot.js.map +1 -0
  100. package/dist/src/errors.d.ts +8 -0
  101. package/dist/src/errors.d.ts.map +1 -1
  102. package/dist/src/errors.js +11 -0
  103. package/dist/src/errors.js.map +1 -1
  104. package/dist/src/index.d.ts +8 -1
  105. package/dist/src/index.d.ts.map +1 -1
  106. package/dist/src/index.js +7 -1
  107. package/dist/src/index.js.map +1 -1
  108. package/dist/src/index.node.d.ts +2 -0
  109. package/dist/src/index.node.d.ts.map +1 -0
  110. package/dist/src/index.node.js +9 -0
  111. package/dist/src/index.node.js.map +1 -0
  112. package/dist/src/injection/__tests__/message-injection.test.d.ts +2 -0
  113. package/dist/src/injection/__tests__/message-injection.test.d.ts.map +1 -0
  114. package/dist/src/injection/__tests__/message-injection.test.js +200 -0
  115. package/dist/src/injection/__tests__/message-injection.test.js.map +1 -0
  116. package/dist/src/injection/index.d.ts +6 -0
  117. package/dist/src/injection/index.d.ts.map +1 -0
  118. package/dist/src/injection/index.js +2 -0
  119. package/dist/src/injection/index.js.map +1 -0
  120. package/dist/src/injection/message-injection.d.ts +65 -0
  121. package/dist/src/injection/message-injection.d.ts.map +1 -0
  122. package/dist/src/injection/message-injection.js +134 -0
  123. package/dist/src/injection/message-injection.js.map +1 -0
  124. package/dist/src/injection/types.d.ts +63 -0
  125. package/dist/src/injection/types.d.ts.map +1 -0
  126. package/dist/src/injection/types.js +2 -0
  127. package/dist/src/injection/types.js.map +1 -0
  128. package/dist/src/injection/xml.d.ts +27 -0
  129. package/dist/src/injection/xml.d.ts.map +1 -0
  130. package/dist/src/injection/xml.js +31 -0
  131. package/dist/src/injection/xml.js.map +1 -0
  132. package/dist/src/interrupt.d.ts +5 -1
  133. package/dist/src/interrupt.d.ts.map +1 -1
  134. package/dist/src/interrupt.js +6 -0
  135. package/dist/src/interrupt.js.map +1 -1
  136. package/dist/src/memory/__tests__/memory-manager.test.d.ts +2 -0
  137. package/dist/src/memory/__tests__/memory-manager.test.d.ts.map +1 -0
  138. package/dist/src/memory/__tests__/memory-manager.test.js +679 -0
  139. package/dist/src/memory/__tests__/memory-manager.test.js.map +1 -0
  140. package/dist/src/memory/extraction/__tests__/extraction.test.d.ts +2 -0
  141. package/dist/src/memory/extraction/__tests__/extraction.test.d.ts.map +1 -0
  142. package/dist/src/memory/extraction/__tests__/extraction.test.js +637 -0
  143. package/dist/src/memory/extraction/__tests__/extraction.test.js.map +1 -0
  144. package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts +2 -0
  145. package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts.map +1 -0
  146. package/dist/src/memory/extraction/__tests__/model-extractor.test.js +68 -0
  147. package/dist/src/memory/extraction/__tests__/model-extractor.test.js.map +1 -0
  148. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts +2 -0
  149. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts.map +1 -0
  150. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js +81 -0
  151. package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js.map +1 -0
  152. package/dist/src/memory/extraction/coordinator.d.ts +128 -0
  153. package/dist/src/memory/extraction/coordinator.d.ts.map +1 -0
  154. package/dist/src/memory/extraction/coordinator.js +245 -0
  155. package/dist/src/memory/extraction/coordinator.js.map +1 -0
  156. package/dist/src/memory/extraction/model-extractor.d.ts +32 -0
  157. package/dist/src/memory/extraction/model-extractor.d.ts.map +1 -0
  158. package/dist/src/memory/extraction/model-extractor.js +118 -0
  159. package/dist/src/memory/extraction/model-extractor.js.map +1 -0
  160. package/dist/src/memory/extraction/resolve-extraction-config.d.ts +46 -0
  161. package/dist/src/memory/extraction/resolve-extraction-config.d.ts.map +1 -0
  162. package/dist/src/memory/extraction/resolve-extraction-config.js +59 -0
  163. package/dist/src/memory/extraction/resolve-extraction-config.js.map +1 -0
  164. package/dist/src/memory/extraction/triggers.d.ts +41 -0
  165. package/dist/src/memory/extraction/triggers.d.ts.map +1 -0
  166. package/dist/src/memory/extraction/triggers.js +59 -0
  167. package/dist/src/memory/extraction/triggers.js.map +1 -0
  168. package/dist/src/memory/extraction/types.d.ts +133 -0
  169. package/dist/src/memory/extraction/types.d.ts.map +1 -0
  170. package/dist/src/memory/extraction/types.js +19 -0
  171. package/dist/src/memory/extraction/types.js.map +1 -0
  172. package/dist/src/memory/index.d.ts +10 -0
  173. package/dist/src/memory/index.d.ts.map +1 -0
  174. package/dist/src/memory/index.js +5 -0
  175. package/dist/src/memory/index.js.map +1 -0
  176. package/dist/src/memory/memory-manager.d.ts +178 -0
  177. package/dist/src/memory/memory-manager.d.ts.map +1 -0
  178. package/dist/src/memory/memory-manager.js +526 -0
  179. package/dist/src/memory/memory-manager.js.map +1 -0
  180. package/dist/src/memory/types.d.ts +278 -0
  181. package/dist/src/memory/types.d.ts.map +1 -0
  182. package/dist/src/memory/types.js +2 -0
  183. package/dist/src/memory/types.js.map +1 -0
  184. package/dist/src/middleware/__tests__/agent-middleware.test.d.ts +2 -0
  185. package/dist/src/middleware/__tests__/agent-middleware.test.d.ts.map +1 -0
  186. package/dist/src/middleware/__tests__/agent-middleware.test.js +1206 -0
  187. package/dist/src/middleware/__tests__/agent-middleware.test.js.map +1 -0
  188. package/dist/src/middleware/__tests__/copy-on-input.test.d.ts +2 -0
  189. package/dist/src/middleware/__tests__/copy-on-input.test.d.ts.map +1 -0
  190. package/dist/src/middleware/__tests__/copy-on-input.test.js +379 -0
  191. package/dist/src/middleware/__tests__/copy-on-input.test.js.map +1 -0
  192. package/dist/src/middleware/__tests__/custom-stages.test.d.ts +2 -0
  193. package/dist/src/middleware/__tests__/custom-stages.test.d.ts.map +1 -0
  194. package/dist/src/middleware/__tests__/custom-stages.test.js +97 -0
  195. package/dist/src/middleware/__tests__/custom-stages.test.js.map +1 -0
  196. package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts +2 -0
  197. package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts.map +1 -0
  198. package/dist/src/middleware/__tests__/middleware-interrupts.test.js +267 -0
  199. package/dist/src/middleware/__tests__/middleware-interrupts.test.js.map +1 -0
  200. package/dist/src/middleware/__tests__/registry.test.d.ts +2 -0
  201. package/dist/src/middleware/__tests__/registry.test.d.ts.map +1 -0
  202. package/dist/src/middleware/__tests__/registry.test.js +525 -0
  203. package/dist/src/middleware/__tests__/registry.test.js.map +1 -0
  204. package/dist/src/middleware/index.d.ts +5 -0
  205. package/dist/src/middleware/index.d.ts.map +1 -0
  206. package/dist/src/middleware/index.js +3 -0
  207. package/dist/src/middleware/index.js.map +1 -0
  208. package/dist/src/middleware/registry.d.ts +58 -0
  209. package/dist/src/middleware/registry.d.ts.map +1 -0
  210. package/dist/src/middleware/registry.js +107 -0
  211. package/dist/src/middleware/registry.js.map +1 -0
  212. package/dist/src/middleware/stages.d.ts +145 -0
  213. package/dist/src/middleware/stages.d.ts.map +1 -0
  214. package/dist/src/middleware/stages.js +34 -0
  215. package/dist/src/middleware/stages.js.map +1 -0
  216. package/dist/src/middleware/types.d.ts +88 -0
  217. package/dist/src/middleware/types.d.ts.map +1 -0
  218. package/dist/src/middleware/types.js +2 -0
  219. package/dist/src/middleware/types.js.map +1 -0
  220. package/dist/src/models/__tests__/anthropic.test.js +16 -1
  221. package/dist/src/models/__tests__/anthropic.test.js.map +1 -1
  222. package/dist/src/models/__tests__/bedrock.test.js +39 -0
  223. package/dist/src/models/__tests__/bedrock.test.js.map +1 -1
  224. package/dist/src/models/__tests__/model.test.js +46 -3
  225. package/dist/src/models/__tests__/model.test.js.map +1 -1
  226. package/dist/src/models/anthropic.js +2 -2
  227. package/dist/src/models/anthropic.js.map +1 -1
  228. package/dist/src/models/bedrock.d.ts.map +1 -1
  229. package/dist/src/models/bedrock.js +12 -5
  230. package/dist/src/models/bedrock.js.map +1 -1
  231. package/dist/src/models/defaults.d.ts.map +1 -1
  232. package/dist/src/models/defaults.js +2 -0
  233. package/dist/src/models/defaults.js.map +1 -1
  234. package/dist/src/models/model.d.ts.map +1 -1
  235. package/dist/src/models/model.js +7 -3
  236. package/dist/src/models/model.js.map +1 -1
  237. package/dist/src/models/openai/__tests__/responses.test.js +8 -14
  238. package/dist/src/models/openai/__tests__/responses.test.js.map +1 -1
  239. package/dist/src/sandbox/__tests__/default.test.browser.d.ts +2 -0
  240. package/dist/src/sandbox/__tests__/default.test.browser.d.ts.map +1 -0
  241. package/dist/src/sandbox/__tests__/default.test.browser.js +11 -0
  242. package/dist/src/sandbox/__tests__/default.test.browser.js.map +1 -0
  243. package/dist/src/sandbox/__tests__/default.test.node.d.ts +2 -0
  244. package/dist/src/sandbox/__tests__/default.test.node.d.ts.map +1 -0
  245. package/dist/src/sandbox/__tests__/default.test.node.js +23 -0
  246. package/dist/src/sandbox/__tests__/default.test.node.js.map +1 -0
  247. package/dist/src/sandbox/__tests__/docker.test.node.d.ts +2 -0
  248. package/dist/src/sandbox/__tests__/docker.test.node.d.ts.map +1 -0
  249. package/dist/src/sandbox/__tests__/docker.test.node.js +89 -0
  250. package/dist/src/sandbox/__tests__/docker.test.node.js.map +1 -0
  251. package/dist/src/sandbox/__tests__/errors.test.node.d.ts +2 -0
  252. package/dist/src/sandbox/__tests__/errors.test.node.d.ts.map +1 -0
  253. package/dist/src/sandbox/__tests__/errors.test.node.js +33 -0
  254. package/dist/src/sandbox/__tests__/errors.test.node.js.map +1 -0
  255. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts +2 -0
  256. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts.map +1 -0
  257. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js +124 -0
  258. package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js.map +1 -0
  259. package/dist/src/sandbox/__tests__/posix-shell.test.node.js +50 -4
  260. package/dist/src/sandbox/__tests__/posix-shell.test.node.js.map +1 -1
  261. package/dist/src/sandbox/__tests__/ssh.test.node.d.ts +2 -0
  262. package/dist/src/sandbox/__tests__/ssh.test.node.d.ts.map +1 -0
  263. package/dist/src/sandbox/__tests__/ssh.test.node.js +262 -0
  264. package/dist/src/sandbox/__tests__/ssh.test.node.js.map +1 -0
  265. package/dist/src/sandbox/base.d.ts +17 -4
  266. package/dist/src/sandbox/base.d.ts.map +1 -1
  267. package/dist/src/sandbox/base.js +10 -2
  268. package/dist/src/sandbox/base.js.map +1 -1
  269. package/dist/src/sandbox/constants.d.ts +18 -0
  270. package/dist/src/sandbox/constants.d.ts.map +1 -1
  271. package/dist/src/sandbox/constants.js +20 -0
  272. package/dist/src/sandbox/constants.js.map +1 -1
  273. package/dist/src/sandbox/default.d.ts +3 -0
  274. package/dist/src/sandbox/default.d.ts.map +1 -0
  275. package/dist/src/sandbox/default.js +3 -0
  276. package/dist/src/sandbox/default.js.map +1 -0
  277. package/dist/src/sandbox/docker.d.ts +38 -0
  278. package/dist/src/sandbox/docker.d.ts.map +1 -0
  279. package/dist/src/sandbox/docker.js +61 -0
  280. package/dist/src/sandbox/docker.js.map +1 -0
  281. package/dist/src/sandbox/errors.d.ts +26 -0
  282. package/dist/src/sandbox/errors.d.ts.map +1 -0
  283. package/dist/src/sandbox/errors.js +35 -0
  284. package/dist/src/sandbox/errors.js.map +1 -0
  285. package/dist/src/sandbox/index.d.ts +5 -0
  286. package/dist/src/sandbox/index.d.ts.map +1 -0
  287. package/dist/src/sandbox/index.js +4 -0
  288. package/dist/src/sandbox/index.js.map +1 -0
  289. package/dist/src/sandbox/not-a-sandbox-local-environment.d.ts +16 -0
  290. package/dist/src/sandbox/not-a-sandbox-local-environment.d.ts.map +1 -0
  291. package/dist/src/sandbox/not-a-sandbox-local-environment.js +83 -0
  292. package/dist/src/sandbox/not-a-sandbox-local-environment.js.map +1 -0
  293. package/dist/src/sandbox/posix-shell.d.ts +21 -0
  294. package/dist/src/sandbox/posix-shell.d.ts.map +1 -1
  295. package/dist/src/sandbox/posix-shell.js +41 -3
  296. package/dist/src/sandbox/posix-shell.js.map +1 -1
  297. package/dist/src/sandbox/ssh.d.ts +56 -0
  298. package/dist/src/sandbox/ssh.d.ts.map +1 -0
  299. package/dist/src/sandbox/ssh.js +121 -0
  300. package/dist/src/sandbox/ssh.js.map +1 -0
  301. package/dist/src/sandbox/stream-process.d.ts.map +1 -1
  302. package/dist/src/sandbox/stream-process.js +3 -2
  303. package/dist/src/sandbox/stream-process.js.map +1 -1
  304. package/dist/src/tsconfig.tsbuildinfo +1 -1
  305. package/dist/src/types/agent.d.ts +21 -0
  306. package/dist/src/types/agent.d.ts.map +1 -1
  307. package/dist/src/types/agent.js.map +1 -1
  308. package/dist/src/types/messages.d.ts +9 -1
  309. package/dist/src/types/messages.d.ts.map +1 -1
  310. package/dist/src/types/messages.js +13 -1
  311. package/dist/src/types/messages.js.map +1 -1
  312. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts +2 -0
  313. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts.map +1 -0
  314. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js +675 -0
  315. package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js.map +1 -0
  316. package/dist/src/vended-interventions/cedar/cedar.d.ts +102 -0
  317. package/dist/src/vended-interventions/cedar/cedar.d.ts.map +1 -0
  318. package/dist/src/vended-interventions/cedar/cedar.js +228 -0
  319. package/dist/src/vended-interventions/cedar/cedar.js.map +1 -0
  320. package/dist/src/vended-interventions/cedar/index.d.ts +3 -0
  321. package/dist/src/vended-interventions/cedar/index.d.ts.map +1 -0
  322. package/dist/src/vended-interventions/cedar/index.js +2 -0
  323. package/dist/src/vended-interventions/cedar/index.js.map +1 -0
  324. package/dist/src/vended-interventions/cedar/schema-generator.d.ts +10 -0
  325. package/dist/src/vended-interventions/cedar/schema-generator.d.ts.map +1 -0
  326. package/dist/src/vended-interventions/cedar/schema-generator.js +33 -0
  327. package/dist/src/vended-interventions/cedar/schema-generator.js.map +1 -0
  328. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.d.ts +2 -0
  329. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.d.ts.map +1 -0
  330. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.js +611 -0
  331. package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.js.map +1 -0
  332. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.d.ts +2 -0
  333. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.d.ts.map +1 -0
  334. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.js +2 -0
  335. package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.js.map +1 -0
  336. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts +230 -0
  337. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts.map +1 -0
  338. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js +370 -0
  339. package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js.map +1 -0
  340. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.d.ts +2 -0
  341. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.d.ts.map +1 -0
  342. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js +96 -0
  343. package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js.map +1 -0
  344. package/dist/src/vended-plugins/context-injector/index.d.ts +25 -0
  345. package/dist/src/vended-plugins/context-injector/index.d.ts.map +1 -0
  346. package/dist/src/vended-plugins/context-injector/index.js +23 -0
  347. package/dist/src/vended-plugins/context-injector/index.js.map +1 -0
  348. package/dist/src/vended-plugins/context-injector/plugin.d.ts +55 -0
  349. package/dist/src/vended-plugins/context-injector/plugin.d.ts.map +1 -0
  350. package/dist/src/vended-plugins/context-injector/plugin.js +41 -0
  351. package/dist/src/vended-plugins/context-injector/plugin.js.map +1 -0
  352. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts +2 -0
  353. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts.map +1 -0
  354. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js +68 -0
  355. package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js.map +1 -0
  356. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js +43 -4
  357. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js.map +1 -1
  358. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts +2 -0
  359. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts.map +1 -0
  360. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js +93 -0
  361. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js.map +1 -0
  362. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js +68 -0
  363. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js.map +1 -1
  364. package/dist/src/vended-plugins/context-offloader/index.d.ts +1 -1
  365. package/dist/src/vended-plugins/context-offloader/index.d.ts.map +1 -1
  366. package/dist/src/vended-plugins/context-offloader/plugin.d.ts +4 -1
  367. package/dist/src/vended-plugins/context-offloader/plugin.d.ts.map +1 -1
  368. package/dist/src/vended-plugins/context-offloader/plugin.js +40 -8
  369. package/dist/src/vended-plugins/context-offloader/plugin.js.map +1 -1
  370. package/dist/src/vended-plugins/context-offloader/search.d.ts.map +1 -1
  371. package/dist/src/vended-plugins/context-offloader/search.js +3 -5
  372. package/dist/src/vended-plugins/context-offloader/search.js.map +1 -1
  373. package/dist/src/vended-plugins/context-offloader/storage.d.ts +58 -6
  374. package/dist/src/vended-plugins/context-offloader/storage.d.ts.map +1 -1
  375. package/dist/src/vended-plugins/context-offloader/storage.js +136 -14
  376. package/dist/src/vended-plugins/context-offloader/storage.js.map +1 -1
  377. package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts +2 -0
  378. package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts.map +1 -0
  379. package/dist/src/vended-plugins/goal/__tests__/plugin.test.js +736 -0
  380. package/dist/src/vended-plugins/goal/__tests__/plugin.test.js.map +1 -0
  381. package/dist/src/vended-plugins/goal/index.d.ts +21 -0
  382. package/dist/src/vended-plugins/goal/index.d.ts.map +1 -0
  383. package/dist/src/vended-plugins/goal/index.js +20 -0
  384. package/dist/src/vended-plugins/goal/index.js.map +1 -0
  385. package/dist/src/vended-plugins/goal/judge.d.ts +41 -0
  386. package/dist/src/vended-plugins/goal/judge.d.ts.map +1 -0
  387. package/dist/src/vended-plugins/goal/judge.js +92 -0
  388. package/dist/src/vended-plugins/goal/judge.js.map +1 -0
  389. package/dist/src/vended-plugins/goal/plugin.d.ts +214 -0
  390. package/dist/src/vended-plugins/goal/plugin.d.ts.map +1 -0
  391. package/dist/src/vended-plugins/goal/plugin.js +287 -0
  392. package/dist/src/vended-plugins/goal/plugin.js.map +1 -0
  393. package/dist/src/vended-plugins/index.d.ts +3 -1
  394. package/dist/src/vended-plugins/index.d.ts.map +1 -1
  395. package/dist/src/vended-plugins/index.js +3 -1
  396. package/dist/src/vended-plugins/index.js.map +1 -1
  397. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js +17 -7
  398. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js.map +1 -1
  399. package/dist/src/vended-plugins/skills/agent-skills.d.ts +21 -7
  400. package/dist/src/vended-plugins/skills/agent-skills.d.ts.map +1 -1
  401. package/dist/src/vended-plugins/skills/agent-skills.js +144 -77
  402. package/dist/src/vended-plugins/skills/agent-skills.js.map +1 -1
  403. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js +44 -4
  404. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js.map +1 -1
  405. package/dist/src/vended-tools/bash/bash.d.ts +3 -24
  406. package/dist/src/vended-tools/bash/bash.d.ts.map +1 -1
  407. package/dist/src/vended-tools/bash/bash.js +9 -9
  408. package/dist/src/vended-tools/bash/bash.js.map +1 -1
  409. package/dist/src/vended-tools/bash/index.d.ts +3 -1
  410. package/dist/src/vended-tools/bash/index.d.ts.map +1 -1
  411. package/dist/src/vended-tools/bash/index.js +2 -1
  412. package/dist/src/vended-tools/bash/index.js.map +1 -1
  413. package/dist/src/vended-tools/bash/make-bash.d.ts +22 -0
  414. package/dist/src/vended-tools/bash/make-bash.d.ts.map +1 -0
  415. package/dist/src/vended-tools/bash/make-bash.js +40 -0
  416. package/dist/src/vended-tools/bash/make-bash.js.map +1 -0
  417. package/dist/src/vended-tools/bash/types.d.ts +1 -0
  418. package/dist/src/vended-tools/bash/types.d.ts.map +1 -1
  419. package/dist/src/vended-tools/bash/types.js +2 -0
  420. package/dist/src/vended-tools/bash/types.js.map +1 -1
  421. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js +83 -1
  422. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js.map +1 -1
  423. package/dist/src/vended-tools/file-editor/file-editor.d.ts +19 -10
  424. package/dist/src/vended-tools/file-editor/file-editor.d.ts.map +1 -1
  425. package/dist/src/vended-tools/file-editor/file-editor.js +188 -218
  426. package/dist/src/vended-tools/file-editor/file-editor.js.map +1 -1
  427. package/dist/src/vended-tools/file-editor/index.d.ts +2 -1
  428. package/dist/src/vended-tools/file-editor/index.d.ts.map +1 -1
  429. package/dist/src/vended-tools/file-editor/index.js +1 -1
  430. package/dist/src/vended-tools/file-editor/index.js.map +1 -1
  431. package/package.json +59 -6
  432. package/dist/src/utils/shell-quote.d.ts +0 -12
  433. package/dist/src/utils/shell-quote.d.ts.map +0 -1
  434. package/dist/src/utils/shell-quote.js +0 -14
  435. package/dist/src/utils/shell-quote.js.map +0 -1
@@ -0,0 +1,679 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { z } from 'zod';
3
+ import { Agent } from '../../agent/agent.js';
4
+ import { MemoryManager } from '../memory-manager.js';
5
+ import { tool } from '../../tools/tool-factory.js';
6
+ import { logger } from '../../logging/logger.js';
7
+ import { Message, TextBlock, ToolUseBlock, ToolResultBlock } from '../../types/messages.js';
8
+ import { InvokeModelStage } from '../../middleware/index.js';
9
+ import { createMockAgent } from '../../__fixtures__/agent-helpers.js';
10
+ function createMockStore(name, options) {
11
+ const store = {
12
+ name,
13
+ writable: !!options?.writable,
14
+ ...(options?.description && { description: options.description }),
15
+ ...(options?.maxSearchResults != null && { maxSearchResults: options.maxSearchResults }),
16
+ search: vi.fn().mockResolvedValue(options?.entries ?? []),
17
+ };
18
+ if (options?.writable) {
19
+ store.add = vi.fn().mockResolvedValue(undefined);
20
+ }
21
+ if (options?.tools) {
22
+ store.getTools = vi.fn().mockReturnValue(options.tools);
23
+ }
24
+ return store;
25
+ }
26
+ function createNamedTool(name) {
27
+ return tool({
28
+ name,
29
+ description: `test tool ${name}`,
30
+ inputSchema: z.object({}),
31
+ callback: () => 'ok',
32
+ });
33
+ }
34
+ describe('MemoryManager', () => {
35
+ describe('constructor', () => {
36
+ it('throws when stores array is empty', () => {
37
+ expect(() => new MemoryManager({ stores: [] })).toThrow('at least one store is required');
38
+ });
39
+ it('creates instance with valid config', () => {
40
+ const mm = new MemoryManager({ stores: [createMockStore('test')] });
41
+ expect(mm.name).toBe('strands:memory-manager');
42
+ });
43
+ it('throws when two stores share a name', () => {
44
+ expect(() => new MemoryManager({ stores: [createMockStore('dup'), createMockStore('dup')] })).toThrow("duplicate store name 'dup'");
45
+ });
46
+ it('throws when a store is writable but has no add method', () => {
47
+ const broken = { name: 'broken', writable: true, search: vi.fn().mockResolvedValue([]) };
48
+ expect(() => new MemoryManager({ stores: [broken] })).toThrow("store 'broken' is writable but has no add or addMessages method");
49
+ });
50
+ it('throws when addToolConfig is enabled but no stores are writable', () => {
51
+ expect(() => new MemoryManager({
52
+ stores: [createMockStore('a')],
53
+ addToolConfig: true,
54
+ })).toThrow('addToolConfig is enabled but no writable stores implement add');
55
+ });
56
+ it('allows addToolConfig true with a single writable store', () => {
57
+ const mm = new MemoryManager({
58
+ stores: [createMockStore('a', { writable: true })],
59
+ addToolConfig: true,
60
+ });
61
+ expect(mm.getTools().map((t) => t.name)).toContain('add_memory');
62
+ });
63
+ it('allows addToolConfig true with multiple writable stores', () => {
64
+ const mm = new MemoryManager({
65
+ stores: [createMockStore('a', { writable: true }), createMockStore('b', { writable: true })],
66
+ addToolConfig: true,
67
+ });
68
+ expect(mm.getTools().map((t) => t.name)).toContain('add_memory');
69
+ });
70
+ it('throws when addToolConfig.stores names a non-existent store', () => {
71
+ expect(() => new MemoryManager({
72
+ stores: [createMockStore('a', { writable: true })],
73
+ addToolConfig: { stores: ['nonexistent'] },
74
+ })).toThrow("addToolConfig store 'nonexistent' not found");
75
+ });
76
+ it('throws when addToolConfig.stores names a non-writable store', () => {
77
+ expect(() => new MemoryManager({
78
+ stores: [createMockStore('a', { writable: true }), createMockStore('readonly')],
79
+ addToolConfig: { stores: ['readonly'] },
80
+ })).toThrow("addToolConfig store 'readonly' is not writable");
81
+ });
82
+ it('accepts MemoryStore instances (not just names) in addToolConfig.stores', async () => {
83
+ const personal = createMockStore('personal', { writable: true });
84
+ const team = createMockStore('team', { writable: true });
85
+ // Pass the store instance instead of its name; resolves by name to scope the tool to it.
86
+ const mm = new MemoryManager({ stores: [personal, team], addToolConfig: { stores: [personal] } });
87
+ const addTool = mm.getTools().find((t) => t.name === 'add_memory');
88
+ await addTool.invoke({ entries: ['fact'] });
89
+ expect(personal.add).toHaveBeenCalledWith('fact', undefined);
90
+ expect(team.add).not.toHaveBeenCalled();
91
+ });
92
+ it('throws when an addToolConfig.stores instance is not a configured store', () => {
93
+ const configured = createMockStore('configured', { writable: true });
94
+ const stray = createMockStore('stray', { writable: true });
95
+ expect(() => new MemoryManager({
96
+ stores: [configured],
97
+ addToolConfig: { stores: [stray] },
98
+ })).toThrow("addToolConfig store 'stray' not found");
99
+ });
100
+ });
101
+ describe('getTools', () => {
102
+ it('registers search tool by default', () => {
103
+ const mm = new MemoryManager({ stores: [createMockStore('test')] });
104
+ const tools = mm.getTools();
105
+ expect(tools).toHaveLength(1);
106
+ expect(tools[0].name).toBe('search_memory');
107
+ });
108
+ it('registers add tool when addToolConfig is enabled', () => {
109
+ const mm = new MemoryManager({
110
+ stores: [createMockStore('test', { writable: true })],
111
+ addToolConfig: true,
112
+ });
113
+ const tools = mm.getTools();
114
+ expect(tools.map((t) => t.name)).toStrictEqual(['search_memory', 'add_memory']);
115
+ });
116
+ it('does not register add tool by default', () => {
117
+ const mm = new MemoryManager({ stores: [createMockStore('test', { writable: true })] });
118
+ const tools = mm.getTools();
119
+ expect(tools.map((t) => t.name)).toStrictEqual(['search_memory']);
120
+ });
121
+ it('returns empty array when searchToolConfig is false and addToolConfig is false', () => {
122
+ const mm = new MemoryManager({
123
+ stores: [createMockStore('test', { writable: true })],
124
+ searchToolConfig: false,
125
+ addToolConfig: false,
126
+ });
127
+ expect(mm.getTools()).toStrictEqual([]);
128
+ });
129
+ it('uses custom tool names from MemoryToolConfig', () => {
130
+ const mm = new MemoryManager({
131
+ stores: [createMockStore('test', { writable: true })],
132
+ searchToolConfig: { name: 'recall' },
133
+ addToolConfig: { name: 'remember' },
134
+ });
135
+ const tools = mm.getTools();
136
+ expect(tools.map((t) => t.name)).toStrictEqual(['recall', 'remember']);
137
+ });
138
+ it('includes store descriptions in search tool description', () => {
139
+ const store = createMockStore('personal', { description: 'User preferences' });
140
+ const mm = new MemoryManager({ stores: [store] });
141
+ const tools = mm.getTools();
142
+ expect(tools[0].description).toContain('personal: User preferences');
143
+ expect(tools[0].description).toContain('target one or more memory stores by name');
144
+ });
145
+ it('includes store descriptions in add tool description', () => {
146
+ const store = createMockStore('notes', { writable: true, description: 'Personal notes' });
147
+ const mm = new MemoryManager({ stores: [store], addToolConfig: true });
148
+ const tools = mm.getTools();
149
+ const addTool = tools.find((t) => t.name === 'add_memory');
150
+ expect(addTool.description).toContain('notes: Personal notes');
151
+ expect(addTool.description).toContain('target a specific store by name');
152
+ });
153
+ it('aggregates tools provided by stores via getTools', () => {
154
+ const store = createMockStore('kb', { tools: [createNamedTool('kb_query')] });
155
+ const mm = new MemoryManager({ stores: [store] });
156
+ expect(mm.getTools().map((t) => t.name)).toStrictEqual(['search_memory', 'kb_query']);
157
+ });
158
+ it('aggregates store tools across multiple stores alongside the manager tools', () => {
159
+ const a = createMockStore('a', { writable: true, tools: [createNamedTool('a_tool')] });
160
+ const b = createMockStore('b', { tools: [createNamedTool('b_tool')] });
161
+ const mm = new MemoryManager({ stores: [a, b], addToolConfig: true });
162
+ expect(mm.getTools().map((t) => t.name)).toStrictEqual(['search_memory', 'add_memory', 'a_tool', 'b_tool']);
163
+ });
164
+ it('includes store tools even when the manager registers no tools of its own', () => {
165
+ const store = createMockStore('kb', { tools: [createNamedTool('kb_query')] });
166
+ const mm = new MemoryManager({ stores: [store], searchToolConfig: false });
167
+ expect(mm.getTools().map((t) => t.name)).toStrictEqual(['kb_query']);
168
+ });
169
+ });
170
+ describe('search', () => {
171
+ it('queries all stores and concatenates results', async () => {
172
+ const store1 = createMockStore('a', { entries: [{ content: 'fact one' }] });
173
+ const store2 = createMockStore('b', { entries: [{ content: 'fact two' }] });
174
+ const mm = new MemoryManager({ stores: [store1, store2] });
175
+ const results = await mm.search('query');
176
+ expect(results).toStrictEqual([
177
+ { content: 'fact one', storeName: 'a' },
178
+ { content: 'fact two', storeName: 'b' },
179
+ ]);
180
+ });
181
+ it("resolves a store's per-instance maxSearchResults when the caller omits it", async () => {
182
+ const store = createMockStore('a', { maxSearchResults: 5 });
183
+ const mm = new MemoryManager({ stores: [store] });
184
+ await mm.search('query');
185
+ expect(store.search).toHaveBeenCalledWith('query', { maxSearchResults: 5 });
186
+ });
187
+ it('forwards an explicit maxSearchResults override to each store', async () => {
188
+ const store = createMockStore('a', { maxSearchResults: 5 });
189
+ const mm = new MemoryManager({ stores: [store] });
190
+ await mm.search('query', { maxSearchResults: 2 });
191
+ expect(store.search).toHaveBeenCalledWith('query', { maxSearchResults: 2 });
192
+ });
193
+ it('falls back to the SDK default when neither caller nor store specifies a limit', async () => {
194
+ const store = createMockStore('a');
195
+ const mm = new MemoryManager({ stores: [store] });
196
+ await mm.search('query');
197
+ expect(store.search).toHaveBeenCalledWith('query', { maxSearchResults: 3 });
198
+ });
199
+ it('filters to named stores when options.stores is provided', async () => {
200
+ const store1 = createMockStore('personal', { entries: [{ content: 'personal fact' }] });
201
+ const store2 = createMockStore('team', { entries: [{ content: 'team fact' }] });
202
+ const mm = new MemoryManager({ stores: [store1, store2] });
203
+ const results = await mm.search('query', { stores: ['personal'] });
204
+ expect(results).toStrictEqual([{ content: 'personal fact', storeName: 'personal' }]);
205
+ expect(store2.search).not.toHaveBeenCalled();
206
+ });
207
+ it('gracefully handles store failures', async () => {
208
+ const store1 = {
209
+ name: 'failing',
210
+ writable: false,
211
+ search: vi.fn().mockRejectedValue(new Error('network error')),
212
+ };
213
+ const store2 = createMockStore('ok', { entries: [{ content: 'fact' }] });
214
+ const mm = new MemoryManager({ stores: [store1, store2] });
215
+ const results = await mm.search('query');
216
+ expect(results).toStrictEqual([{ content: 'fact', storeName: 'ok' }]);
217
+ });
218
+ it('searches all stores when stores option is omitted', async () => {
219
+ const store1 = createMockStore('a', { entries: [{ content: 'fact one' }] });
220
+ const store2 = createMockStore('b', { entries: [{ content: 'fact two' }] });
221
+ const mm = new MemoryManager({ stores: [store1, store2] });
222
+ const results = await mm.search('query');
223
+ expect(results).toStrictEqual([
224
+ { content: 'fact one', storeName: 'a' },
225
+ { content: 'fact two', storeName: 'b' },
226
+ ]);
227
+ });
228
+ it('searches no stores when stores option is an empty array', async () => {
229
+ const store1 = createMockStore('a', { entries: [{ content: 'fact one' }] });
230
+ const store2 = createMockStore('b', { entries: [{ content: 'fact two' }] });
231
+ const mm = new MemoryManager({ stores: [store1, store2] });
232
+ const results = await mm.search('query', { stores: [] });
233
+ expect(results).toStrictEqual([]);
234
+ expect(store1.search).not.toHaveBeenCalled();
235
+ expect(store2.search).not.toHaveBeenCalled();
236
+ });
237
+ it('throws a not-found error when a named store does not exist', async () => {
238
+ const store = createMockStore('personal', { entries: [{ content: 'fact' }] });
239
+ const mm = new MemoryManager({ stores: [store] });
240
+ await expect(mm.search('query', { stores: ['nonexistent'] })).rejects.toThrow("store 'nonexistent' not found");
241
+ expect(store.search).not.toHaveBeenCalled();
242
+ });
243
+ });
244
+ describe('add', () => {
245
+ it('writes to all writable stores', async () => {
246
+ const store1 = createMockStore('a', { writable: true });
247
+ const store2 = createMockStore('b', { writable: true });
248
+ const mm = new MemoryManager({ stores: [store1, store2] });
249
+ await mm.add('user likes coffee');
250
+ expect(store1.add).toHaveBeenCalledWith('user likes coffee', undefined);
251
+ expect(store2.add).toHaveBeenCalledWith('user likes coffee', undefined);
252
+ });
253
+ it('passes metadata to stores', async () => {
254
+ const store = createMockStore('a', { writable: true });
255
+ const mm = new MemoryManager({ stores: [store] });
256
+ await mm.add('fact', { metadata: { source: 'user' } });
257
+ expect(store.add).toHaveBeenCalledWith('fact', { source: 'user' });
258
+ });
259
+ it('filters to named stores when options.stores is provided', async () => {
260
+ const store1 = createMockStore('personal', { writable: true });
261
+ const store2 = createMockStore('team', { writable: true });
262
+ const mm = new MemoryManager({ stores: [store1, store2] });
263
+ await mm.add('my preference', { stores: ['personal'] });
264
+ expect(store1.add).toHaveBeenCalledWith('my preference', undefined);
265
+ expect(store2.add).not.toHaveBeenCalled();
266
+ });
267
+ it('dedupes duplicate store names so each store is written once', async () => {
268
+ const store = createMockStore('personal', { writable: true });
269
+ const mm = new MemoryManager({ stores: [store] });
270
+ await mm.add('fact', { stores: ['personal', 'personal'] });
271
+ expect(store.add).toHaveBeenCalledTimes(1);
272
+ });
273
+ it('throws when no writable stores match', async () => {
274
+ const mm = new MemoryManager({ stores: [createMockStore('a')] });
275
+ await expect(mm.add('fact')).rejects.toThrow('no writable store matched');
276
+ });
277
+ it('throws a not-found error when a named store does not exist', async () => {
278
+ const mm = new MemoryManager({ stores: [createMockStore('a', { writable: true })] });
279
+ await expect(mm.add('fact', { stores: ['nonexistent'] })).rejects.toThrow("store 'nonexistent' not found");
280
+ });
281
+ it('throws a read-only error when a named store cannot be written', async () => {
282
+ const mm = new MemoryManager({ stores: [createMockStore('readonly')] });
283
+ await expect(mm.add('fact', { stores: ['readonly'] })).rejects.toThrow("store 'readonly' is read-only");
284
+ });
285
+ it('awaits writes and throws AggregateError naming the failed store on partial failure', async () => {
286
+ const failing = {
287
+ name: 'failing',
288
+ writable: true,
289
+ search: vi.fn().mockResolvedValue([]),
290
+ add: vi.fn().mockRejectedValue(new Error('write error')),
291
+ };
292
+ const ok = createMockStore('ok', { writable: true });
293
+ const mm = new MemoryManager({ stores: [failing, ok] });
294
+ // The method always awaits: a partial failure (failing rejects, ok succeeds) throws.
295
+ await expect(mm.add('fact')).rejects.toThrow('store writes failed: failing');
296
+ expect(ok.add).toHaveBeenCalledWith('fact', undefined);
297
+ });
298
+ it('dispatches writes to all targeted stores', async () => {
299
+ const store1 = createMockStore('a', { writable: true });
300
+ const store2 = createMockStore('b', { writable: true });
301
+ const mm = new MemoryManager({ stores: [store1, store2] });
302
+ await mm.add('fact');
303
+ expect(store1.add).toHaveBeenCalledWith('fact', undefined);
304
+ expect(store2.add).toHaveBeenCalledWith('fact', undefined);
305
+ });
306
+ });
307
+ describe('tool store scoping', () => {
308
+ function searchTool(mm) {
309
+ return mm.getTools().find((t) => t.name === 'search_memory');
310
+ }
311
+ function addTool(mm) {
312
+ return mm.getTools().find((t) => t.name === 'add_memory');
313
+ }
314
+ it('search tool queries all stores when model omits stores', async () => {
315
+ const personal = createMockStore('personal', { entries: [{ content: 'personal fact' }] });
316
+ const team = createMockStore('team', { entries: [{ content: 'team fact' }] });
317
+ const mm = new MemoryManager({ stores: [personal, team] });
318
+ await searchTool(mm).invoke({ query: 'q' });
319
+ expect(personal.search).toHaveBeenCalled();
320
+ expect(team.search).toHaveBeenCalled();
321
+ });
322
+ it('search tool treats an empty stores array as omitted (searches all)', async () => {
323
+ const personal = createMockStore('personal', { entries: [{ content: 'personal fact' }] });
324
+ const team = createMockStore('team', { entries: [{ content: 'team fact' }] });
325
+ const mm = new MemoryManager({ stores: [personal, team] });
326
+ await searchTool(mm).invoke({ query: 'q', stores: [] });
327
+ expect(personal.search).toHaveBeenCalled();
328
+ expect(team.search).toHaveBeenCalled();
329
+ });
330
+ it('search tool targets only the requested store when in scope', async () => {
331
+ const personal = createMockStore('personal', { entries: [{ content: 'personal fact' }] });
332
+ const team = createMockStore('team', { entries: [{ content: 'team fact' }] });
333
+ const mm = new MemoryManager({ stores: [personal, team] });
334
+ await searchTool(mm).invoke({ query: 'q', stores: ['personal'] });
335
+ expect(personal.search).toHaveBeenCalled();
336
+ expect(team.search).not.toHaveBeenCalled();
337
+ });
338
+ it('search tool result attributes each entry to its source store', async () => {
339
+ const personal = createMockStore('personal', { entries: [{ content: 'personal fact' }] });
340
+ const team = createMockStore('team', { entries: [{ content: 'team fact' }] });
341
+ const mm = new MemoryManager({ stores: [personal, team] });
342
+ const result = await searchTool(mm).invoke({ query: 'q' });
343
+ expect(result).toStrictEqual([
344
+ { content: 'personal fact', storeName: 'personal' },
345
+ { content: 'team fact', storeName: 'team' },
346
+ ]);
347
+ });
348
+ it('search tool keeps valid names and warns on out-of-scope names', async () => {
349
+ const warnSpy = vi.spyOn(logger, 'warn').mockImplementation(() => { });
350
+ const personal = createMockStore('personal', { entries: [{ content: 'personal fact' }] });
351
+ const team = createMockStore('team', { entries: [{ content: 'team fact' }] });
352
+ const mm = new MemoryManager({ stores: [personal, team] });
353
+ await searchTool(mm).invoke({ query: 'q', stores: ['personal', 'nonexistent'] });
354
+ expect(personal.search).toHaveBeenCalled();
355
+ expect(team.search).not.toHaveBeenCalled();
356
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('nonexistent'));
357
+ warnSpy.mockRestore();
358
+ });
359
+ it('search tool throws when every requested store is out of scope', async () => {
360
+ const personal = createMockStore('personal', { entries: [{ content: 'personal fact' }] });
361
+ const mm = new MemoryManager({ stores: [personal] });
362
+ await expect(searchTool(mm).invoke({ query: 'q', stores: ['nonexistent'] })).rejects.toThrow('none of the requested memory stores are available');
363
+ expect(personal.search).not.toHaveBeenCalled();
364
+ });
365
+ it('add tool writes to all writable stores when model omits stores', async () => {
366
+ const personal = createMockStore('personal', { writable: true });
367
+ const team = createMockStore('team', { writable: true });
368
+ const mm = new MemoryManager({ stores: [personal, team], addToolConfig: true });
369
+ await addTool(mm).invoke({ entries: ['fact'] });
370
+ expect(personal.add).toHaveBeenCalledWith('fact', undefined);
371
+ expect(team.add).toHaveBeenCalledWith('fact', undefined);
372
+ });
373
+ it('add tool treats an empty stores array as omitted (writes to all writable)', async () => {
374
+ const personal = createMockStore('personal', { writable: true });
375
+ const team = createMockStore('team', { writable: true });
376
+ const mm = new MemoryManager({ stores: [personal, team], addToolConfig: true });
377
+ await addTool(mm).invoke({ entries: ['fact'], stores: [] });
378
+ expect(personal.add).toHaveBeenCalled();
379
+ expect(team.add).toHaveBeenCalled();
380
+ });
381
+ it('add tool is scoped to addToolConfig.stores (excludes other writable stores)', async () => {
382
+ const personal = createMockStore('personal', { writable: true });
383
+ const team = createMockStore('team', { writable: true });
384
+ const mm = new MemoryManager({ stores: [personal, team], addToolConfig: { stores: ['personal'] } });
385
+ // Omitting stores writes to the configured allowlist only — not every writable store.
386
+ await addTool(mm).invoke({ entries: ['fact'] });
387
+ expect(personal.add).toHaveBeenCalledWith('fact', undefined);
388
+ expect(team.add).not.toHaveBeenCalled();
389
+ });
390
+ it('add tool rejects a writable store excluded from addToolConfig.stores (extraction-only store)', async () => {
391
+ // `extractionOnly` is writable (e.g. to receive extraction writes) but excluded from the tool's
392
+ // allowlist, so the agent's add_memory tool cannot write to it.
393
+ const personal = createMockStore('personal', { writable: true });
394
+ const extractionOnly = createMockStore('extraction-only', { writable: true });
395
+ const mm = new MemoryManager({ stores: [personal, extractionOnly], addToolConfig: { stores: ['personal'] } });
396
+ await expect(addTool(mm).invoke({ entries: ['fact'], stores: ['extraction-only'] })).rejects.toThrow('none of the requested memory stores are available');
397
+ expect(extractionOnly.add).not.toHaveBeenCalled();
398
+ });
399
+ it('add tool excludes read-only stores from its scope', async () => {
400
+ const personal = createMockStore('personal', { writable: true });
401
+ const readonly = createMockStore('readonly');
402
+ const mm = new MemoryManager({ stores: [personal, readonly], addToolConfig: true });
403
+ // A read-only store is out of the add tool's scope, so naming it throws.
404
+ await expect(addTool(mm).invoke({ entries: ['fact'], stores: ['readonly'] })).rejects.toThrow('none of the requested memory stores are available');
405
+ expect(personal.add).not.toHaveBeenCalled();
406
+ });
407
+ it('add tool keeps valid names and warns on out-of-scope names', async () => {
408
+ const warnSpy = vi.spyOn(logger, 'warn').mockImplementation(() => { });
409
+ const personal = createMockStore('personal', { writable: true });
410
+ const team = createMockStore('team', { writable: true });
411
+ const mm = new MemoryManager({ stores: [personal, team], addToolConfig: true });
412
+ await addTool(mm).invoke({ entries: ['fact'], stores: ['personal', 'nonexistent'] });
413
+ expect(personal.add).toHaveBeenCalledWith('fact', undefined);
414
+ expect(team.add).not.toHaveBeenCalled();
415
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('nonexistent'));
416
+ warnSpy.mockRestore();
417
+ });
418
+ it('add tool throws when every requested store is out of scope', async () => {
419
+ const personal = createMockStore('personal', { writable: true });
420
+ const mm = new MemoryManager({ stores: [personal], addToolConfig: true });
421
+ await expect(addTool(mm).invoke({ entries: ['fact'], stores: ['nonexistent'] })).rejects.toThrow('none of the requested memory stores are available');
422
+ expect(personal.add).not.toHaveBeenCalled();
423
+ });
424
+ it('add tool rejects an empty entries array', async () => {
425
+ const personal = createMockStore('personal', { writable: true });
426
+ const mm = new MemoryManager({ stores: [personal], addToolConfig: true });
427
+ await expect(addTool(mm).invoke({ entries: [] })).rejects.toThrow();
428
+ expect(personal.add).not.toHaveBeenCalled();
429
+ });
430
+ it('add tool returns stored count by default (awaits writes)', async () => {
431
+ const store = createMockStore('notes', { writable: true });
432
+ const mm = new MemoryManager({ stores: [store], addToolConfig: true });
433
+ const result = await addTool(mm).invoke({ entries: ['a', 'b'] });
434
+ expect(result).toStrictEqual({ stored: 2 });
435
+ });
436
+ it('add tool throws a flattened error with concrete reasons when entries fail (default awaits)', async () => {
437
+ const failing = {
438
+ name: 'failing',
439
+ writable: true,
440
+ search: vi.fn().mockResolvedValue([]),
441
+ add: vi.fn().mockRejectedValue(new Error('write error')),
442
+ };
443
+ const mm = new MemoryManager({ stores: [failing], addToolConfig: true });
444
+ const error = await addTool(mm)
445
+ .invoke({ entries: ['a', 'b'] })
446
+ .catch((e) => e);
447
+ expect(error).toBeInstanceOf(AggregateError);
448
+ const agg = error;
449
+ expect(agg.message).toContain('failed to add 2 of 2 entries');
450
+ expect(agg.message).toContain('write error');
451
+ // Leaves are the underlying store errors, not the per-entry AggregateErrors add() throws.
452
+ expect(agg.errors).toHaveLength(2);
453
+ expect(agg.errors.every((e) => e instanceof Error && !(e instanceof AggregateError))).toBe(true);
454
+ });
455
+ it('add tool with waitForWrites: false returns accepted count (fire-and-forget)', async () => {
456
+ const store = createMockStore('notes', { writable: true });
457
+ const mm = new MemoryManager({ stores: [store], addToolConfig: { waitForWrites: false } });
458
+ const result = await addTool(mm).invoke({ entries: ['a', 'b'] });
459
+ expect(result).toStrictEqual({ accepted: 2 });
460
+ });
461
+ it('add tool with waitForWrites: false returns accepted even when a store write fails (swallows it)', async () => {
462
+ const failing = {
463
+ name: 'failing',
464
+ writable: true,
465
+ search: vi.fn().mockResolvedValue([]),
466
+ add: vi.fn().mockRejectedValue(new Error('write error')),
467
+ };
468
+ const mm = new MemoryManager({ stores: [failing], addToolConfig: { waitForWrites: false } });
469
+ const result = await addTool(mm).invoke({ entries: ['a', 'b'] });
470
+ expect(result).toStrictEqual({ accepted: 2 });
471
+ });
472
+ });
473
+ describe('initAgent', () => {
474
+ it('does not throw', () => {
475
+ const mm = new MemoryManager({ stores: [createMockStore('test')] });
476
+ expect(() => mm.initAgent(createMockAgent())).not.toThrow();
477
+ });
478
+ it('does not register injection middleware when injection is disabled', () => {
479
+ const mm = new MemoryManager({ stores: [createMockStore('test')], injection: false });
480
+ const addMiddleware = vi.fn();
481
+ mm.initAgent(createMockAgent({ extra: { addMiddleware } }));
482
+ expect(addMiddleware).not.toHaveBeenCalled();
483
+ });
484
+ it('registers an InvokeModelStage input middleware when injection is enabled', () => {
485
+ const mm = new MemoryManager({ stores: [createMockStore('test')], injection: true });
486
+ const addMiddleware = vi.fn();
487
+ mm.initAgent(createMockAgent({ extra: { addMiddleware } }));
488
+ expect(addMiddleware).toHaveBeenCalledTimes(1);
489
+ expect(addMiddleware.mock.calls[0][0]).toBe(InvokeModelStage.Input);
490
+ expect(typeof addMiddleware.mock.calls[0][1]).toBe('function');
491
+ });
492
+ it('wires the registered middleware to the memory provide pipeline (folds a search hit)', async () => {
493
+ const store = createMockStore('s', { entries: [{ content: 'dark mode preferred' }] });
494
+ const mm = new MemoryManager({ stores: [store], injection: true });
495
+ const addMiddleware = vi.fn();
496
+ const agent = createMockAgent({ extra: { addMiddleware } });
497
+ mm.initAgent(agent);
498
+ const handler = addMiddleware.mock.calls[0][1];
499
+ const messages = [
500
+ new Message({ role: 'assistant', content: [new TextBlock('prior')] }),
501
+ new Message({ role: 'user', content: [new TextBlock('what is my plan')] }),
502
+ ];
503
+ const result = await handler({ messages, agent });
504
+ expect(result.messages.map((m) => m.toJSON())).toStrictEqual([
505
+ { role: 'assistant', content: [{ text: 'prior' }] },
506
+ {
507
+ role: 'user',
508
+ content: [
509
+ { text: '<memory>\n<entry source="s">dark mode preferred</entry>\n</memory>' },
510
+ { text: 'what is my plan' },
511
+ ],
512
+ },
513
+ ]);
514
+ expect(store.search).toHaveBeenCalledWith('what is my plan', { maxSearchResults: 5 });
515
+ });
516
+ });
517
+ // The injection delivery (folding text into the model input) is wired through the InvokeModelStage
518
+ // input middleware (see the `initAgent` tests). The memory-owned `provide` pipeline below — query
519
+ // derivation, search, and formatting — is exercised directly via `_provideMemoryContext`, the
520
+ // callback the middleware invokes.
521
+ describe('injection', () => {
522
+ const assistant = (text) => new Message({ role: 'assistant', content: [new TextBlock(text)] });
523
+ const user = (text) => new Message({ role: 'user', content: [new TextBlock(text)] });
524
+ const toolUse = () => new Message({ role: 'assistant', content: [new ToolUseBlock({ name: 'x', toolUseId: 't1', input: {} })] });
525
+ const toolResult = () => new Message({
526
+ role: 'user',
527
+ content: [new ToolResultBlock({ toolUseId: 't1', status: 'success', content: [new TextBlock('done')] })],
528
+ });
529
+ // Calls the (private) provide pipeline with the manager's resolved injection config.
530
+ function provide(mm, messages) {
531
+ const data = messages.map((m) => m.toJSON());
532
+ const config = mm._injectionConfig;
533
+ return mm._provideMemoryContext(data, config === false ? {} : config);
534
+ }
535
+ describe('config resolution', () => {
536
+ const injectionConfig = (mm) => mm._injectionConfig;
537
+ it('defaults to an empty config (enabled) when injection is omitted', () => {
538
+ expect(injectionConfig(new MemoryManager({ stores: [createMockStore('s')] }))).toStrictEqual({});
539
+ });
540
+ it('is false when injection is explicitly false', () => {
541
+ expect(injectionConfig(new MemoryManager({ stores: [createMockStore('s')], injection: false }))).toBe(false);
542
+ });
543
+ it('resolves to an empty config when injection is true', () => {
544
+ expect(injectionConfig(new MemoryManager({ stores: [createMockStore('s')], injection: true }))).toStrictEqual({});
545
+ });
546
+ it('passes an injection config object through unchanged', () => {
547
+ const cfg = { maxEntries: 5 };
548
+ expect(injectionConfig(new MemoryManager({ stores: [createMockStore('s')], injection: cfg }))).toBe(cfg);
549
+ });
550
+ });
551
+ describe('query', () => {
552
+ it('uses the latest user ask on a user turn (adaptive default)', async () => {
553
+ const store = createMockStore('s', { entries: [{ content: 'fact' }] });
554
+ const mm = new MemoryManager({ stores: [store], injection: true });
555
+ await provide(mm, [assistant('prior step'), user('what is my plan')]);
556
+ expect(store.search).toHaveBeenCalledWith('what is my plan', { maxSearchResults: 5 });
557
+ });
558
+ it('uses the most recent assistant text on an autonomous (tool-result) turn', async () => {
559
+ const store = createMockStore('s', { entries: [{ content: 'fact' }] });
560
+ const mm = new MemoryManager({ stores: [store], injection: true });
561
+ await provide(mm, [user('task'), assistant('the previous step result'), toolResult()]);
562
+ expect(store.search).toHaveBeenCalledWith('the previous step result', { maxSearchResults: 5 });
563
+ });
564
+ it('honors a custom query', async () => {
565
+ const store = createMockStore('s', { entries: [{ content: 'fact' }] });
566
+ const mm = new MemoryManager({ stores: [store], injection: { query: () => 'custom query' } });
567
+ await provide(mm, [assistant('prior'), user('ask')]);
568
+ expect(store.search).toHaveBeenCalledWith('custom query', { maxSearchResults: 5 });
569
+ });
570
+ it('skips (returns undefined) when a custom query returns undefined', async () => {
571
+ const store = createMockStore('s', { entries: [{ content: 'fact' }] });
572
+ const mm = new MemoryManager({ stores: [store], injection: { query: () => undefined } });
573
+ await expect(provide(mm, [assistant('prior'), user('ask')])).resolves.toBeUndefined();
574
+ expect(store.search).not.toHaveBeenCalled();
575
+ });
576
+ it('fails open (returns undefined) when a custom query throws', async () => {
577
+ const store = createMockStore('s', { entries: [{ content: 'fact' }] });
578
+ const mm = new MemoryManager({
579
+ stores: [store],
580
+ injection: {
581
+ query: () => {
582
+ throw new Error('boom');
583
+ },
584
+ },
585
+ });
586
+ await expect(provide(mm, [assistant('prior'), user('ask')])).resolves.toBeUndefined();
587
+ expect(store.search).not.toHaveBeenCalled();
588
+ });
589
+ it('skips when the latest assistant message has no text (pure tool use)', async () => {
590
+ const store = createMockStore('s', { entries: [{ content: 'fact' }] });
591
+ const mm = new MemoryManager({ stores: [store], injection: true });
592
+ await expect(provide(mm, [toolUse(), toolResult()])).resolves.toBeUndefined();
593
+ expect(store.search).not.toHaveBeenCalled();
594
+ });
595
+ });
596
+ describe('search', () => {
597
+ it('returns undefined when search yields no entries', async () => {
598
+ const store = createMockStore('s', { entries: [] });
599
+ const mm = new MemoryManager({ stores: [store], injection: true });
600
+ await expect(provide(mm, [assistant('prior'), user('ask')])).resolves.toBeUndefined();
601
+ expect(store.search).toHaveBeenCalled();
602
+ });
603
+ it('honors maxEntries and caps the rendered entries', async () => {
604
+ const store = createMockStore('s', {
605
+ entries: [{ content: 'A' }, { content: 'B' }, { content: 'C' }],
606
+ });
607
+ const mm = new MemoryManager({
608
+ stores: [store],
609
+ injection: { maxEntries: 2, format: ({ entries }) => entries.map((e) => e.content).join(',') },
610
+ });
611
+ const text = await provide(mm, [assistant('prior'), user('ask')]);
612
+ expect(store.search).toHaveBeenCalledWith('ask', { maxSearchResults: 2 });
613
+ expect(text).toBe('A,B');
614
+ });
615
+ });
616
+ describe('format', () => {
617
+ it('default renders a <memory> block with per-entry source attribution', async () => {
618
+ const store = createMockStore('s', { entries: [{ content: 'dark mode preferred' }] });
619
+ const mm = new MemoryManager({ stores: [store], injection: true });
620
+ // search() stamps storeName onto each entry, so the default format attributes the source.
621
+ const text = await provide(mm, [assistant('prior'), user('ask')]);
622
+ expect(text).toBe('<memory>\n<entry source="s">dark mode preferred</entry>\n</memory>');
623
+ });
624
+ it('omits the source attribute for an entry with no storeName', () => {
625
+ const mm = new MemoryManager({ stores: [createMockStore('s')], injection: true });
626
+ const text = mm._defaultInjectionFormat([
627
+ { content: 'no source' },
628
+ ]);
629
+ expect(text).toBe('<memory>\n<entry>no source</entry>\n</memory>');
630
+ });
631
+ it('escapes XML in entry content and source so untrusted text cannot break the block', () => {
632
+ const mm = new MemoryManager({ stores: [createMockStore('s')], injection: true });
633
+ const text = mm._defaultInjectionFormat([
634
+ { content: 'a < b & c > d </entry>', storeName: 'pre"f' },
635
+ ]);
636
+ expect(text).toBe('<memory>\n<entry source="pre&quot;f">a &lt; b &amp; c &gt; d &lt;/entry&gt;</entry>\n</memory>');
637
+ });
638
+ it('honors a custom format', async () => {
639
+ const store = createMockStore('s', { entries: [{ content: 'A' }] });
640
+ const mm = new MemoryManager({
641
+ stores: [store],
642
+ injection: { format: ({ entries }) => `[${entries.map((e) => e.content).join('|')}]` },
643
+ });
644
+ await expect(provide(mm, [assistant('prior'), user('ask')])).resolves.toBe('[A]');
645
+ });
646
+ it('fails open (returns undefined) when a custom format throws', async () => {
647
+ const store = createMockStore('s', { entries: [{ content: 'fact' }] });
648
+ const mm = new MemoryManager({
649
+ stores: [store],
650
+ injection: {
651
+ format: () => {
652
+ throw new Error('boom');
653
+ },
654
+ },
655
+ });
656
+ // search ran, but the format threw, so nothing is injected.
657
+ await expect(provide(mm, [assistant('prior'), user('ask')])).resolves.toBeUndefined();
658
+ expect(store.search).toHaveBeenCalled();
659
+ });
660
+ });
661
+ });
662
+ describe('AgentConfig integration', () => {
663
+ it('auto-wraps MemoryManagerConfig into MemoryManager instance', () => {
664
+ const store = createMockStore('test');
665
+ const agent = new Agent({ memoryManager: { stores: [store] } });
666
+ expect(agent.memoryManager).toBeInstanceOf(MemoryManager);
667
+ });
668
+ it('passes through MemoryManager instance unchanged', () => {
669
+ const mm = new MemoryManager({ stores: [createMockStore('test')] });
670
+ const agent = new Agent({ memoryManager: mm });
671
+ expect(agent.memoryManager).toBe(mm);
672
+ });
673
+ it('sets memoryManager to undefined when not configured', () => {
674
+ const agent = new Agent({});
675
+ expect(agent.memoryManager).toBeUndefined();
676
+ });
677
+ });
678
+ });
679
+ //# sourceMappingURL=memory-manager.test.js.map