@strands-agents/sdk 1.0.0 → 1.1.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 (245) hide show
  1. package/dist/src/__fixtures__/agent-helpers.d.ts +16 -1
  2. package/dist/src/__fixtures__/agent-helpers.d.ts.map +1 -1
  3. package/dist/src/__fixtures__/agent-helpers.js +42 -0
  4. package/dist/src/__fixtures__/agent-helpers.js.map +1 -1
  5. package/dist/src/__fixtures__/tool-helpers.d.ts +2 -1
  6. package/dist/src/__fixtures__/tool-helpers.d.ts.map +1 -1
  7. package/dist/src/__fixtures__/tool-helpers.js +20 -3
  8. package/dist/src/__fixtures__/tool-helpers.js.map +1 -1
  9. package/dist/src/__tests__/interrupt.test.d.ts +2 -0
  10. package/dist/src/__tests__/interrupt.test.d.ts.map +1 -0
  11. package/dist/src/__tests__/interrupt.test.js +259 -0
  12. package/dist/src/__tests__/interrupt.test.js.map +1 -0
  13. package/dist/src/__tests__/mcp.test.js +226 -0
  14. package/dist/src/__tests__/mcp.test.js.map +1 -1
  15. package/dist/src/agent/__tests__/agent.hook.test.js +551 -1
  16. package/dist/src/agent/__tests__/agent.hook.test.js.map +1 -1
  17. package/dist/src/agent/__tests__/agent.interrupt.test.d.ts +2 -0
  18. package/dist/src/agent/__tests__/agent.interrupt.test.d.ts.map +1 -0
  19. package/dist/src/agent/__tests__/agent.interrupt.test.js +730 -0
  20. package/dist/src/agent/__tests__/agent.interrupt.test.js.map +1 -0
  21. package/dist/src/agent/__tests__/agent.model-retry.test.d.ts +2 -0
  22. package/dist/src/agent/__tests__/agent.model-retry.test.d.ts.map +1 -0
  23. package/dist/src/agent/__tests__/agent.model-retry.test.js +161 -0
  24. package/dist/src/agent/__tests__/agent.model-retry.test.js.map +1 -0
  25. package/dist/src/agent/__tests__/agent.test.js +118 -0
  26. package/dist/src/agent/__tests__/agent.test.js.map +1 -1
  27. package/dist/src/agent/__tests__/snapshot.test.js +50 -4
  28. package/dist/src/agent/__tests__/snapshot.test.js.map +1 -1
  29. package/dist/src/agent/agent.d.ts +35 -4
  30. package/dist/src/agent/agent.d.ts.map +1 -1
  31. package/dist/src/agent/agent.js +548 -222
  32. package/dist/src/agent/agent.js.map +1 -1
  33. package/dist/src/agent/snapshot.d.ts +2 -2
  34. package/dist/src/agent/snapshot.d.ts.map +1 -1
  35. package/dist/src/agent/snapshot.js +14 -2
  36. package/dist/src/agent/snapshot.js.map +1 -1
  37. package/dist/src/conversation-manager/__tests__/conversation-manager.test.js +230 -9
  38. package/dist/src/conversation-manager/__tests__/conversation-manager.test.js.map +1 -1
  39. package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.js +19 -6
  40. package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.js.map +1 -1
  41. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js +51 -2
  42. package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js.map +1 -1
  43. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js +75 -1
  44. package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js.map +1 -1
  45. package/dist/src/conversation-manager/conversation-manager.d.ts +67 -22
  46. package/dist/src/conversation-manager/conversation-manager.d.ts.map +1 -1
  47. package/dist/src/conversation-manager/conversation-manager.js +65 -13
  48. package/dist/src/conversation-manager/conversation-manager.js.map +1 -1
  49. package/dist/src/conversation-manager/index.d.ts +1 -1
  50. package/dist/src/conversation-manager/index.d.ts.map +1 -1
  51. package/dist/src/conversation-manager/index.js +1 -1
  52. package/dist/src/conversation-manager/index.js.map +1 -1
  53. package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts +17 -3
  54. package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts.map +1 -1
  55. package/dist/src/conversation-manager/sliding-window-conversation-manager.js +10 -4
  56. package/dist/src/conversation-manager/sliding-window-conversation-manager.js.map +1 -1
  57. package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts +23 -1
  58. package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts.map +1 -1
  59. package/dist/src/conversation-manager/summarizing-conversation-manager.js +39 -17
  60. package/dist/src/conversation-manager/summarizing-conversation-manager.js.map +1 -1
  61. package/dist/src/hooks/__tests__/events.test.js +99 -12
  62. package/dist/src/hooks/__tests__/events.test.js.map +1 -1
  63. package/dist/src/hooks/__tests__/registry.test.js +166 -2
  64. package/dist/src/hooks/__tests__/registry.test.js.map +1 -1
  65. package/dist/src/hooks/events.d.ts +102 -30
  66. package/dist/src/hooks/events.d.ts.map +1 -1
  67. package/dist/src/hooks/events.js +87 -6
  68. package/dist/src/hooks/events.js.map +1 -1
  69. package/dist/src/hooks/index.d.ts +3 -2
  70. package/dist/src/hooks/index.d.ts.map +1 -1
  71. package/dist/src/hooks/index.js +1 -0
  72. package/dist/src/hooks/index.js.map +1 -1
  73. package/dist/src/hooks/registry.d.ts +12 -12
  74. package/dist/src/hooks/registry.d.ts.map +1 -1
  75. package/dist/src/hooks/registry.js +55 -15
  76. package/dist/src/hooks/registry.js.map +1 -1
  77. package/dist/src/hooks/types.d.ts +23 -0
  78. package/dist/src/hooks/types.d.ts.map +1 -1
  79. package/dist/src/hooks/types.js +17 -1
  80. package/dist/src/hooks/types.js.map +1 -1
  81. package/dist/src/index.d.ts +9 -5
  82. package/dist/src/index.d.ts.map +1 -1
  83. package/dist/src/index.js +4 -1
  84. package/dist/src/index.js.map +1 -1
  85. package/dist/src/interrupt.d.ts +220 -0
  86. package/dist/src/interrupt.d.ts.map +1 -0
  87. package/dist/src/interrupt.js +274 -0
  88. package/dist/src/interrupt.js.map +1 -0
  89. package/dist/src/mcp.d.ts +23 -2
  90. package/dist/src/mcp.d.ts.map +1 -1
  91. package/dist/src/mcp.js +77 -18
  92. package/dist/src/mcp.js.map +1 -1
  93. package/dist/src/models/__tests__/anthropic.test.js +55 -0
  94. package/dist/src/models/__tests__/anthropic.test.js.map +1 -1
  95. package/dist/src/models/__tests__/bedrock.test.js +115 -0
  96. package/dist/src/models/__tests__/bedrock.test.js.map +1 -1
  97. package/dist/src/models/__tests__/defaults.test.d.ts +2 -0
  98. package/dist/src/models/__tests__/defaults.test.d.ts.map +1 -0
  99. package/dist/src/models/__tests__/defaults.test.js +36 -0
  100. package/dist/src/models/__tests__/defaults.test.js.map +1 -0
  101. package/dist/src/models/__tests__/google.test.js +58 -0
  102. package/dist/src/models/__tests__/google.test.js.map +1 -1
  103. package/dist/src/models/anthropic.d.ts +8 -0
  104. package/dist/src/models/anthropic.d.ts.map +1 -1
  105. package/dist/src/models/anthropic.js +4 -2
  106. package/dist/src/models/anthropic.js.map +1 -1
  107. package/dist/src/models/bedrock.d.ts +15 -0
  108. package/dist/src/models/bedrock.d.ts.map +1 -1
  109. package/dist/src/models/bedrock.js +58 -4
  110. package/dist/src/models/bedrock.js.map +1 -1
  111. package/dist/src/models/defaults.d.ts +10 -0
  112. package/dist/src/models/defaults.d.ts.map +1 -1
  113. package/dist/src/models/defaults.js +129 -0
  114. package/dist/src/models/defaults.js.map +1 -1
  115. package/dist/src/models/google/model.d.ts.map +1 -1
  116. package/dist/src/models/google/model.js +4 -2
  117. package/dist/src/models/google/model.js.map +1 -1
  118. package/dist/src/models/google/types.d.ts +8 -0
  119. package/dist/src/models/google/types.d.ts.map +1 -1
  120. package/dist/src/models/model.d.ts +15 -0
  121. package/dist/src/models/model.d.ts.map +1 -1
  122. package/dist/src/models/model.js +18 -0
  123. package/dist/src/models/model.js.map +1 -1
  124. package/dist/src/models/openai/__tests__/chat.test.js +45 -0
  125. package/dist/src/models/openai/__tests__/chat.test.js.map +1 -1
  126. package/dist/src/models/openai/model.d.ts.map +1 -1
  127. package/dist/src/models/openai/model.js +2 -2
  128. package/dist/src/models/openai/model.js.map +1 -1
  129. package/dist/src/multiagent/__tests__/graph.test.js +69 -0
  130. package/dist/src/multiagent/__tests__/graph.test.js.map +1 -1
  131. package/dist/src/multiagent/__tests__/nodes.test.js +13 -0
  132. package/dist/src/multiagent/__tests__/nodes.test.js.map +1 -1
  133. package/dist/src/multiagent/__tests__/swarm.test.js +77 -0
  134. package/dist/src/multiagent/__tests__/swarm.test.js.map +1 -1
  135. package/dist/src/multiagent/graph.d.ts +22 -2
  136. package/dist/src/multiagent/graph.d.ts.map +1 -1
  137. package/dist/src/multiagent/graph.js +42 -3
  138. package/dist/src/multiagent/graph.js.map +1 -1
  139. package/dist/src/multiagent/multiagent.d.ts +5 -3
  140. package/dist/src/multiagent/multiagent.d.ts.map +1 -1
  141. package/dist/src/multiagent/nodes.d.ts +18 -0
  142. package/dist/src/multiagent/nodes.d.ts.map +1 -1
  143. package/dist/src/multiagent/nodes.js +14 -1
  144. package/dist/src/multiagent/nodes.js.map +1 -1
  145. package/dist/src/multiagent/swarm.d.ts +15 -1
  146. package/dist/src/multiagent/swarm.d.ts.map +1 -1
  147. package/dist/src/multiagent/swarm.js +46 -3
  148. package/dist/src/multiagent/swarm.js.map +1 -1
  149. package/dist/src/registry/__tests__/tool-registry.test.js +11 -0
  150. package/dist/src/registry/__tests__/tool-registry.test.js.map +1 -1
  151. package/dist/src/registry/tool-registry.d.ts +4 -0
  152. package/dist/src/registry/tool-registry.d.ts.map +1 -1
  153. package/dist/src/registry/tool-registry.js +6 -0
  154. package/dist/src/registry/tool-registry.js.map +1 -1
  155. package/dist/src/retry/__tests__/backoff-strategy.test.d.ts +2 -0
  156. package/dist/src/retry/__tests__/backoff-strategy.test.d.ts.map +1 -0
  157. package/dist/src/retry/__tests__/backoff-strategy.test.js +116 -0
  158. package/dist/src/retry/__tests__/backoff-strategy.test.js.map +1 -0
  159. package/dist/src/retry/__tests__/default-model-retry-strategy.test.d.ts +2 -0
  160. package/dist/src/retry/__tests__/default-model-retry-strategy.test.d.ts.map +1 -0
  161. package/dist/src/retry/__tests__/default-model-retry-strategy.test.js +225 -0
  162. package/dist/src/retry/__tests__/default-model-retry-strategy.test.js.map +1 -0
  163. package/dist/src/retry/backoff-strategy.d.ts +108 -0
  164. package/dist/src/retry/backoff-strategy.d.ts.map +1 -0
  165. package/dist/src/retry/backoff-strategy.js +86 -0
  166. package/dist/src/retry/backoff-strategy.js.map +1 -0
  167. package/dist/src/retry/default-model-retry-strategy.d.ts +76 -0
  168. package/dist/src/retry/default-model-retry-strategy.d.ts.map +1 -0
  169. package/dist/src/retry/default-model-retry-strategy.js +104 -0
  170. package/dist/src/retry/default-model-retry-strategy.js.map +1 -0
  171. package/dist/src/retry/index.d.ts +8 -0
  172. package/dist/src/retry/index.d.ts.map +1 -0
  173. package/dist/src/retry/index.js +7 -0
  174. package/dist/src/retry/index.js.map +1 -0
  175. package/dist/src/retry/model-retry-strategy.d.ts +80 -0
  176. package/dist/src/retry/model-retry-strategy.d.ts.map +1 -0
  177. package/dist/src/retry/model-retry-strategy.js +85 -0
  178. package/dist/src/retry/model-retry-strategy.js.map +1 -0
  179. package/dist/src/retry/retry-strategy.d.ts +34 -0
  180. package/dist/src/retry/retry-strategy.d.ts.map +1 -0
  181. package/dist/src/retry/retry-strategy.js +25 -0
  182. package/dist/src/retry/retry-strategy.js.map +1 -0
  183. package/dist/src/session/__tests__/session-manager.test.js +39 -0
  184. package/dist/src/session/__tests__/session-manager.test.js.map +1 -1
  185. package/dist/src/session/session-manager.d.ts +6 -0
  186. package/dist/src/session/session-manager.d.ts.map +1 -1
  187. package/dist/src/session/session-manager.js +8 -0
  188. package/dist/src/session/session-manager.js.map +1 -1
  189. package/dist/src/tools/__tests__/tool.test.js +24 -1
  190. package/dist/src/tools/__tests__/tool.test.js.map +1 -1
  191. package/dist/src/tools/function-tool.d.ts.map +1 -1
  192. package/dist/src/tools/function-tool.js +6 -1
  193. package/dist/src/tools/function-tool.js.map +1 -1
  194. package/dist/src/tools/tool.d.ts +10 -1
  195. package/dist/src/tools/tool.d.ts.map +1 -1
  196. package/dist/src/tools/tool.js +12 -0
  197. package/dist/src/tools/tool.js.map +1 -1
  198. package/dist/src/tsconfig.tsbuildinfo +1 -1
  199. package/dist/src/types/agent.d.ts +22 -3
  200. package/dist/src/types/agent.d.ts.map +1 -1
  201. package/dist/src/types/agent.js +8 -0
  202. package/dist/src/types/agent.js.map +1 -1
  203. package/dist/src/types/interrupt.d.ts +103 -0
  204. package/dist/src/types/interrupt.d.ts.map +1 -0
  205. package/dist/src/types/interrupt.js +63 -0
  206. package/dist/src/types/interrupt.js.map +1 -0
  207. package/dist/src/types/messages.d.ts +2 -1
  208. package/dist/src/types/messages.d.ts.map +1 -1
  209. package/dist/src/types/messages.js.map +1 -1
  210. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.d.ts +2 -0
  211. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.d.ts.map +1 -0
  212. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js +292 -0
  213. package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js.map +1 -0
  214. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.d.ts +2 -0
  215. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.d.ts.map +1 -0
  216. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js +148 -0
  217. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js.map +1 -0
  218. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.d.ts +2 -0
  219. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.d.ts.map +1 -0
  220. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.js +78 -0
  221. package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.node.js.map +1 -0
  222. package/dist/src/vended-plugins/context-offloader/index.d.ts +23 -0
  223. package/dist/src/vended-plugins/context-offloader/index.d.ts.map +1 -0
  224. package/dist/src/vended-plugins/context-offloader/index.js +21 -0
  225. package/dist/src/vended-plugins/context-offloader/index.js.map +1 -0
  226. package/dist/src/vended-plugins/context-offloader/plugin.d.ts +48 -0
  227. package/dist/src/vended-plugins/context-offloader/plugin.d.ts.map +1 -0
  228. package/dist/src/vended-plugins/context-offloader/plugin.js +244 -0
  229. package/dist/src/vended-plugins/context-offloader/plugin.js.map +1 -0
  230. package/dist/src/vended-plugins/context-offloader/storage.d.ts +114 -0
  231. package/dist/src/vended-plugins/context-offloader/storage.d.ts.map +1 -0
  232. package/dist/src/vended-plugins/context-offloader/storage.js +204 -0
  233. package/dist/src/vended-plugins/context-offloader/storage.js.map +1 -0
  234. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js +12 -0
  235. package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js.map +1 -1
  236. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js +3 -0
  237. package/dist/src/vended-tools/bash/__tests__/bash.test.node.js.map +1 -1
  238. package/dist/src/vended-tools/bash/bash.d.ts.map +1 -1
  239. package/dist/src/vended-tools/bash/bash.js +0 -3
  240. package/dist/src/vended-tools/bash/bash.js.map +1 -1
  241. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js +3 -0
  242. package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js.map +1 -1
  243. package/dist/src/vended-tools/notebook/__tests__/notebook.test.js +3 -0
  244. package/dist/src/vended-tools/notebook/__tests__/notebook.test.js.map +1 -1
  245. package/package.json +9 -5
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Context offloading plugin for Strands Agents.
3
+ *
4
+ * This module provides the ContextOffloader plugin and Storage backends for
5
+ * automatically offloading oversized tool results to external storage, replacing
6
+ * them with truncated previews and actionable storage references.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { Agent } from '@strands-agents/sdk'
11
+ * import { ContextOffloader, InMemoryStorage } from '@strands-agents/sdk/vended-plugins/context-offloader'
12
+ *
13
+ * const agent = new Agent({
14
+ * model,
15
+ * plugins: [new ContextOffloader({ storage: new InMemoryStorage() })],
16
+ * })
17
+ * ```
18
+ */
19
+ export { ContextOffloader } from './plugin.js';
20
+ export { InMemoryStorage, FileStorage, S3Storage } from './storage.js';
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/vended-plugins/context-offloader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAG9C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,48 @@
1
+ import type { Plugin } from '../../plugins/plugin.js';
2
+ import type { Tool } from '../../tools/tool.js';
3
+ import type { LocalAgent } from '../../types/agent.js';
4
+ import type { Storage } from './storage.js';
5
+ /** Configuration for the {@link ContextOffloader} plugin. */
6
+ export interface ContextOffloaderConfig {
7
+ /** Storage backend for persisting offloaded content. */
8
+ storage: Storage;
9
+ /** Token threshold above which tool results are offloaded. Defaults to 2,500. */
10
+ maxResultTokens?: number;
11
+ /** Number of tokens to keep as an inline preview. Defaults to 1,000. */
12
+ previewTokens?: number;
13
+ /** Whether to register the `retrieve_offloaded_content` tool. Defaults to true. */
14
+ includeRetrievalTool?: boolean;
15
+ }
16
+ /**
17
+ * Plugin that offloads oversized tool results to reduce context consumption.
18
+ *
19
+ * When a tool result exceeds the configured token threshold, this plugin stores
20
+ * each content block to a storage backend and replaces the in-context result with
21
+ * a truncated text preview plus per-block storage references.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * import { ContextOffloader, InMemoryStorage } from '@strands-agents/sdk/vended-plugins/context-offloader'
26
+ *
27
+ * const agent = new Agent({
28
+ * model,
29
+ * plugins: [new ContextOffloader({ storage: new InMemoryStorage() })],
30
+ * })
31
+ * ```
32
+ */
33
+ export declare class ContextOffloader implements Plugin {
34
+ readonly name = "strands:context-offloader";
35
+ private readonly _storage;
36
+ private readonly _maxResultTokens;
37
+ private readonly _previewTokens;
38
+ private readonly _includeRetrievalTool;
39
+ private _retrievalTool;
40
+ constructor(config: ContextOffloaderConfig);
41
+ initAgent(agent: LocalAgent): void;
42
+ getTools(): Tool[];
43
+ private _createRetrievalTool;
44
+ private _storeBlock;
45
+ private _buildPreviewText;
46
+ private _handleToolResult;
47
+ }
48
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../src/vended-plugins/context-offloader/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAUtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAmE3C,6DAA6D;AAC7D,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAA;IAChB,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAiB,YAAW,MAAM;IAC7C,QAAQ,CAAC,IAAI,+BAA8B;IAE3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,cAAc,CAAkB;gBAE5B,MAAM,EAAE,sBAAsB;IAc1C,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAIlC,QAAQ,IAAI,IAAI,EAAE;IAQlB,OAAO,CAAC,oBAAoB;YAoBd,WAAW;IAiCzB,OAAO,CAAC,iBAAiB;YA4BX,iBAAiB;CA4DhC"}
@@ -0,0 +1,244 @@
1
+ import { AfterToolCallEvent } from '../../hooks/events.js';
2
+ import { TextBlock, JsonBlock, ToolResultBlock, Message } from '../../types/messages.js';
3
+ import { ImageBlock, VideoBlock, DocumentBlock } from '../../types/media.js';
4
+ import { tool } from '../../tools/tool-factory.js';
5
+ import { z } from 'zod';
6
+ import { logger } from '../../logging/logger.js';
7
+ const CHARS_PER_TOKEN = 4;
8
+ const DEFAULT_MAX_RESULT_TOKENS = 2_500;
9
+ const DEFAULT_PREVIEW_TOKENS = 1_000;
10
+ const RETRIEVAL_TOOL_NAME = 'retrieve_offloaded_content';
11
+ function slicePreview(text, previewTokens) {
12
+ const maxChars = previewTokens * CHARS_PER_TOKEN;
13
+ if (text.length <= maxChars)
14
+ return text;
15
+ return text.slice(0, maxChars);
16
+ }
17
+ function getBytes(block) {
18
+ if (block instanceof ImageBlock && block.source.type === 'imageSourceBytes') {
19
+ return block.source.bytes;
20
+ }
21
+ if (block instanceof VideoBlock && block.source.type === 'videoSourceBytes') {
22
+ return block.source.bytes;
23
+ }
24
+ if (block instanceof DocumentBlock) {
25
+ if (block.source.type === 'documentSourceBytes')
26
+ return block.source.bytes;
27
+ if (block.source.type === 'documentSourceText')
28
+ return new TextEncoder().encode(block.source.text);
29
+ }
30
+ return undefined;
31
+ }
32
+ function decodeStoredContent(content, contentType, reference) {
33
+ if (contentType.startsWith('text/')) {
34
+ return new TextDecoder().decode(content);
35
+ }
36
+ if (contentType === 'application/json') {
37
+ const text = new TextDecoder().decode(content);
38
+ try {
39
+ return JSON.parse(text);
40
+ }
41
+ catch {
42
+ return text;
43
+ }
44
+ }
45
+ // Return native content blocks for binary types so the agent sees the actual content.
46
+ // FunctionTool._wrapInToolResult passes ImageBlock/VideoBlock/DocumentBlock through as-is
47
+ // at runtime, even though the callback type signature only accepts JSONValue.
48
+ if (contentType.startsWith('image/')) {
49
+ const format = contentType.split('/').pop();
50
+ return new ImageBlock({
51
+ format: format,
52
+ source: { bytes: content },
53
+ });
54
+ }
55
+ if (contentType.startsWith('video/')) {
56
+ const format = contentType.split('/').pop();
57
+ return new VideoBlock({
58
+ format: format,
59
+ source: { bytes: content },
60
+ });
61
+ }
62
+ if (contentType.startsWith('application/')) {
63
+ const format = contentType.split('/').pop();
64
+ return new DocumentBlock({
65
+ format: format,
66
+ name: reference,
67
+ source: { bytes: content },
68
+ });
69
+ }
70
+ return new TextDecoder('utf-8', { fatal: false }).decode(content);
71
+ }
72
+ /**
73
+ * Plugin that offloads oversized tool results to reduce context consumption.
74
+ *
75
+ * When a tool result exceeds the configured token threshold, this plugin stores
76
+ * each content block to a storage backend and replaces the in-context result with
77
+ * a truncated text preview plus per-block storage references.
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * import { ContextOffloader, InMemoryStorage } from '@strands-agents/sdk/vended-plugins/context-offloader'
82
+ *
83
+ * const agent = new Agent({
84
+ * model,
85
+ * plugins: [new ContextOffloader({ storage: new InMemoryStorage() })],
86
+ * })
87
+ * ```
88
+ */
89
+ export class ContextOffloader {
90
+ name = 'strands:context-offloader';
91
+ _storage;
92
+ _maxResultTokens;
93
+ _previewTokens;
94
+ _includeRetrievalTool;
95
+ _retrievalTool;
96
+ constructor(config) {
97
+ const maxResultTokens = config.maxResultTokens ?? DEFAULT_MAX_RESULT_TOKENS;
98
+ const previewTokens = config.previewTokens ?? DEFAULT_PREVIEW_TOKENS;
99
+ if (maxResultTokens <= 0)
100
+ throw new Error('maxResultTokens must be positive');
101
+ if (previewTokens < 0)
102
+ throw new Error('previewTokens must be non-negative');
103
+ if (previewTokens >= maxResultTokens)
104
+ throw new Error('previewTokens must be less than maxResultTokens');
105
+ this._storage = config.storage;
106
+ this._maxResultTokens = maxResultTokens;
107
+ this._previewTokens = previewTokens;
108
+ this._includeRetrievalTool = config.includeRetrievalTool ?? true;
109
+ }
110
+ initAgent(agent) {
111
+ agent.addHook(AfterToolCallEvent, (event) => this._handleToolResult(event));
112
+ }
113
+ getTools() {
114
+ if (!this._includeRetrievalTool)
115
+ return [];
116
+ if (!this._retrievalTool) {
117
+ this._retrievalTool = this._createRetrievalTool();
118
+ }
119
+ return [this._retrievalTool];
120
+ }
121
+ _createRetrievalTool() {
122
+ const storage = this._storage;
123
+ return tool({
124
+ name: RETRIEVAL_TOOL_NAME,
125
+ description: 'Retrieve offloaded content by reference. Use this tool when you see a placeholder with a reference (ref: ...) and need the full content. Only use this as a fallback if the data cannot be accessed using your existing tools.',
126
+ inputSchema: z.object({
127
+ reference: z.string().describe('The reference string from the offload placeholder.'),
128
+ }),
129
+ callback: async (input) => {
130
+ try {
131
+ const result = await storage.retrieve(input.reference);
132
+ return decodeStoredContent(result.content, result.contentType, input.reference);
133
+ }
134
+ catch {
135
+ return `Error: reference not found: ${input.reference}`;
136
+ }
137
+ },
138
+ });
139
+ }
140
+ async _storeBlock(block, key) {
141
+ if (block instanceof TextBlock && block.text) {
142
+ const ref = await this._storage.store(key, new TextEncoder().encode(block.text), 'text/plain');
143
+ return { ref, contentType: 'text/plain', description: `text, ${block.text.length.toLocaleString()} chars` };
144
+ }
145
+ if (block instanceof JsonBlock) {
146
+ const jsonStr = JSON.stringify(block.json, null, 2);
147
+ const jsonBytes = new TextEncoder().encode(jsonStr);
148
+ const ref = await this._storage.store(key, jsonBytes, 'application/json');
149
+ return { ref, contentType: 'application/json', description: `json, ${jsonBytes.length.toLocaleString()} bytes` };
150
+ }
151
+ if (block instanceof ImageBlock || block instanceof VideoBlock || block instanceof DocumentBlock) {
152
+ const bytes = getBytes(block);
153
+ const contentType = block instanceof ImageBlock
154
+ ? `image/${block.format}`
155
+ : block instanceof VideoBlock
156
+ ? `video/${block.format}`
157
+ : `application/${block.format}`;
158
+ const label = block instanceof DocumentBlock ? block.name : contentType;
159
+ if (bytes) {
160
+ const ref = await this._storage.store(key, bytes, contentType);
161
+ return { ref, contentType, description: `${label}, ${bytes.length.toLocaleString()} bytes` };
162
+ }
163
+ return { ref: '', contentType, description: `${label}, 0 bytes` };
164
+ }
165
+ logger.warn('unsupported content block type encountered during offloading, skipping');
166
+ return { ref: '', contentType: 'unknown', description: 'unknown block type' };
167
+ }
168
+ _buildPreviewText(content, references, tokenCount, fullText) {
169
+ const preview = fullText ? slicePreview(fullText, this._previewTokens) : '';
170
+ const refLines = references
171
+ .filter((r) => r.ref)
172
+ .map((r) => ` ${r.ref} (${r.description})`)
173
+ .join('\n');
174
+ let guidance = 'Tool result was offloaded to external storage due to size.\n' +
175
+ 'Use the preview below to answer if possible.\n' +
176
+ 'Use your available tools to selectively access the data you need.';
177
+ if (this._includeRetrievalTool) {
178
+ guidance += '\nYou can also use retrieve_offloaded_content with a reference to get the full content.';
179
+ }
180
+ return (`[Offloaded: ${content.length} blocks, ~${tokenCount.toLocaleString()} tokens]\n` +
181
+ `${guidance}\n\n` +
182
+ `${preview}\n\n` +
183
+ `[Stored references:]\n${refLines}`);
184
+ }
185
+ async _handleToolResult(event) {
186
+ if (event.result.status === 'error')
187
+ return;
188
+ // Skip results from the retrieval tool to prevent circular offloading
189
+ if (this._includeRetrievalTool && event.toolUse.name === RETRIEVAL_TOOL_NAME)
190
+ return;
191
+ const content = event.result.content;
192
+ const toolUseId = event.result.toolUseId;
193
+ const tokenCount = await event.agent.model.countTokens([new Message({ role: 'user', content: [event.result] })]);
194
+ if (tokenCount <= this._maxResultTokens)
195
+ return;
196
+ // Extract text preview from text/JSON blocks
197
+ const textParts = [];
198
+ for (const block of content) {
199
+ if (block instanceof TextBlock && block.text)
200
+ textParts.push(block.text);
201
+ else if (block instanceof JsonBlock)
202
+ textParts.push(JSON.stringify(block.json, null, 2));
203
+ }
204
+ const fullText = textParts.join('\n');
205
+ // Store each content block to the storage backend
206
+ let references;
207
+ try {
208
+ references = await Promise.all(content.map((block, i) => this._storeBlock(block, `${toolUseId}_${i}`)));
209
+ }
210
+ catch (err) {
211
+ logger.warn(`tool_use_id=<${toolUseId}> | failed to offload tool result, keeping original`, err);
212
+ return;
213
+ }
214
+ logger.debug(`tool_use_id=<${toolUseId}>, blocks=<${references.length}>, tokens=<${tokenCount}> | tool result offloaded`);
215
+ // Build replacement content: preview text + media placeholders
216
+ const newContent = [
217
+ new TextBlock(this._buildPreviewText(content, references, tokenCount, fullText)),
218
+ ];
219
+ for (let i = 0; i < content.length; i++) {
220
+ const block = content[i];
221
+ const ref = references[i]?.ref ?? '';
222
+ if (block instanceof TextBlock || block instanceof JsonBlock)
223
+ continue;
224
+ const bytes = getBytes(block);
225
+ const size = bytes ? bytes.length : 0;
226
+ let label;
227
+ if (block instanceof ImageBlock)
228
+ label = `image: ${block.format}`;
229
+ else if (block instanceof VideoBlock)
230
+ label = `video: ${block.format}`;
231
+ else if (block instanceof DocumentBlock)
232
+ label = `document: ${block.format}, ${block.name}`;
233
+ if (label) {
234
+ newContent.push(new TextBlock(`[${label}, ${size} bytes${ref ? ` | ref: ${ref}` : ''}]`));
235
+ }
236
+ }
237
+ event.result = new ToolResultBlock({
238
+ toolUseId: event.result.toolUseId,
239
+ status: event.result.status,
240
+ content: newContent,
241
+ });
242
+ }
243
+ }
244
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../src/vended-plugins/context-offloader/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Storage backends for offloaded tool result content.
3
+ *
4
+ * This module defines the {@link Storage} interface and provides three built-in
5
+ * implementations: {@link InMemoryStorage}, {@link FileStorage}, and {@link S3Storage}.
6
+ * Each content block from a tool result is stored individually with its content type preserved.
7
+ */
8
+ /**
9
+ * Backend for storing and retrieving offloaded content blocks.
10
+ *
11
+ * Implement this interface to create custom storage backends (e.g., Redis, DynamoDB).
12
+ * The SDK ships three built-in implementations: {@link InMemoryStorage},
13
+ * {@link FileStorage}, and {@link S3Storage}.
14
+ */
15
+ export interface Storage {
16
+ /**
17
+ * Store content and return a reference identifier.
18
+ *
19
+ * @param key - Unique key for this content block
20
+ * @param content - Raw content bytes to store
21
+ * @param contentType - MIME type of the content (e.g., "text/plain", "image/png")
22
+ * @returns Reference string for later retrieval
23
+ */
24
+ store(key: string, content: Uint8Array, contentType?: string): Promise<string>;
25
+ /**
26
+ * Retrieve previously stored content by reference.
27
+ *
28
+ * @param reference - Reference returned by a previous {@link store} call
29
+ * @returns Content bytes and content type
30
+ * @throws Error if the reference is not found
31
+ */
32
+ retrieve(reference: string): Promise<{
33
+ content: Uint8Array;
34
+ contentType: string;
35
+ }>;
36
+ }
37
+ /**
38
+ * In-memory storage backend.
39
+ *
40
+ * Useful for testing and serverless environments where disk access is not available.
41
+ * Content accumulates for the lifetime of this instance; call {@link clear} to free memory.
42
+ */
43
+ export declare class InMemoryStorage implements Storage {
44
+ private _store;
45
+ private _counter;
46
+ /** {@inheritdoc} */
47
+ store(key: string, content: Uint8Array, contentType?: string): Promise<string>;
48
+ /** {@inheritdoc} */
49
+ retrieve(reference: string): Promise<{
50
+ content: Uint8Array;
51
+ contentType: string;
52
+ }>;
53
+ /** Remove all stored content. */
54
+ clear(): void;
55
+ }
56
+ /**
57
+ * File-based storage backend.
58
+ *
59
+ * Stores offloaded content as files on disk. File extensions are derived from the
60
+ * content type. A `.metadata.json` sidecar file tracks content types across restarts.
61
+ * References are file paths preserving the configured artifact directory form.
62
+ *
63
+ * @param artifactDir - Directory path where artifact files will be stored
64
+ */
65
+ export declare class FileStorage implements Storage {
66
+ private static readonly METADATA_FILE;
67
+ private readonly _artifactDir;
68
+ private _counter;
69
+ private _contentTypes;
70
+ private _metadataLoaded;
71
+ private _metadataWriteChain;
72
+ constructor(artifactDir?: string);
73
+ private static _extensionFor;
74
+ private _ensureDir;
75
+ private _loadMetadata;
76
+ private _saveMetadata;
77
+ /** {@inheritdoc} */
78
+ store(key: string, content: Uint8Array, contentType?: string): Promise<string>;
79
+ /** {@inheritdoc} */
80
+ retrieve(reference: string): Promise<{
81
+ content: Uint8Array;
82
+ contentType: string;
83
+ }>;
84
+ }
85
+ /**
86
+ * S3-based storage backend.
87
+ *
88
+ * Stores offloaded content as S3 objects. Content type is preserved as S3 object metadata.
89
+ * References are `s3://` URIs for direct access via AWS CLI or SDK.
90
+ *
91
+ * @param bucket - S3 bucket name
92
+ * @param options - Optional configuration (prefix, region, pre-configured S3Client)
93
+ */
94
+ export declare class S3Storage implements Storage {
95
+ private readonly _bucket;
96
+ private readonly _prefix;
97
+ private _client;
98
+ private readonly _region;
99
+ private _counter;
100
+ constructor(bucket: string, options?: {
101
+ prefix?: string;
102
+ region?: string;
103
+ s3Client?: import('@aws-sdk/client-s3').S3Client;
104
+ });
105
+ private _getClient;
106
+ /** {@inheritdoc} */
107
+ store(key: string, content: Uint8Array, contentType?: string): Promise<string>;
108
+ /** {@inheritdoc} */
109
+ retrieve(reference: string): Promise<{
110
+ content: Uint8Array;
111
+ contentType: string;
112
+ }>;
113
+ }
114
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../src/vended-plugins/context-offloader/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB;;;;;;;OAOG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAE9E;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnF;AASD;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,OAAO;IAC7C,OAAO,CAAC,MAAM,CAAkE;IAChF,OAAO,CAAC,QAAQ,CAAI;IAEpB,oBAAoB;IACd,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,GAAE,MAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAOlG,oBAAoB;IACd,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAQxF,iCAAiC;IACjC,KAAK,IAAI,IAAI;CAGd;AAED;;;;;;;;GAQG;AACH,qBAAa,WAAY,YAAW,OAAO;IACzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAmB;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,mBAAmB,CAAmC;gBAElD,WAAW,GAAE,MAAsB;IAI/C,OAAO,CAAC,MAAM,CAAC,aAAa;YAKd,UAAU;YAUV,aAAa;YAWb,aAAa;IAM3B,oBAAoB;IACd,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,GAAE,MAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBlG,oBAAoB;IACd,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CAoBzF;AAED;;;;;;;;GAQG;AACH,qBAAa,SAAU,YAAW,OAAO;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,OAAO,CAAmD;IAClE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAI;gBAGlB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,oBAAoB,EAAE,QAAQ,CAAA;KAAE;YAQpF,UAAU;IAOxB,oBAAoB;IACd,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,GAAE,MAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBlG,oBAAoB;IACd,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CAgCzF"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Storage backends for offloaded tool result content.
3
+ *
4
+ * This module defines the {@link Storage} interface and provides three built-in
5
+ * implementations: {@link InMemoryStorage}, {@link FileStorage}, and {@link S3Storage}.
6
+ * Each content block from a tool result is stored individually with its content type preserved.
7
+ */
8
+ function sanitizeId(rawId) {
9
+ return rawId
10
+ .replace(/\.\./g, '_')
11
+ .replace(/[/\\]/g, '_')
12
+ .replace(/[^\w\-.]/g, '_');
13
+ }
14
+ /**
15
+ * In-memory storage backend.
16
+ *
17
+ * Useful for testing and serverless environments where disk access is not available.
18
+ * Content accumulates for the lifetime of this instance; call {@link clear} to free memory.
19
+ */
20
+ export class InMemoryStorage {
21
+ _store = new Map();
22
+ _counter = 0;
23
+ /** {@inheritdoc} */
24
+ async store(key, content, contentType = 'text/plain') {
25
+ this._counter++;
26
+ const reference = `mem_${this._counter}_${key}`;
27
+ this._store.set(reference, { content, contentType });
28
+ return reference;
29
+ }
30
+ /** {@inheritdoc} */
31
+ async retrieve(reference) {
32
+ const entry = this._store.get(reference);
33
+ if (!entry) {
34
+ throw new Error(`Reference not found: ${reference}`);
35
+ }
36
+ return entry;
37
+ }
38
+ /** Remove all stored content. */
39
+ clear() {
40
+ this._store.clear();
41
+ }
42
+ }
43
+ /**
44
+ * File-based storage backend.
45
+ *
46
+ * Stores offloaded content as files on disk. File extensions are derived from the
47
+ * content type. A `.metadata.json` sidecar file tracks content types across restarts.
48
+ * References are file paths preserving the configured artifact directory form.
49
+ *
50
+ * @param artifactDir - Directory path where artifact files will be stored
51
+ */
52
+ export class FileStorage {
53
+ static METADATA_FILE = '.metadata.json';
54
+ _artifactDir;
55
+ _counter = 0;
56
+ _contentTypes = {};
57
+ _metadataLoaded = false;
58
+ _metadataWriteChain = Promise.resolve();
59
+ constructor(artifactDir = './artifacts') {
60
+ this._artifactDir = artifactDir;
61
+ }
62
+ static _extensionFor(contentType) {
63
+ if (contentType === 'text/plain')
64
+ return '.txt';
65
+ return `.${contentType.split('/').pop()}`;
66
+ }
67
+ async _ensureDir() {
68
+ const fs = await import('node:fs/promises');
69
+ await fs.mkdir(this._artifactDir, { recursive: true });
70
+ if (!this._metadataLoaded) {
71
+ this._contentTypes = await this._loadMetadata(fs);
72
+ this._metadataLoaded = true;
73
+ }
74
+ return fs;
75
+ }
76
+ async _loadMetadata(fs) {
77
+ const path = await import('node:path');
78
+ const metadataPath = path.join(this._artifactDir, FileStorage.METADATA_FILE);
79
+ try {
80
+ const raw = await fs.readFile(metadataPath, 'utf-8');
81
+ return JSON.parse(raw);
82
+ }
83
+ catch {
84
+ return {};
85
+ }
86
+ }
87
+ async _saveMetadata(fs) {
88
+ const path = await import('node:path');
89
+ const metadataPath = path.join(this._artifactDir, FileStorage.METADATA_FILE);
90
+ await fs.writeFile(metadataPath, JSON.stringify(this._contentTypes), 'utf-8');
91
+ }
92
+ /** {@inheritdoc} */
93
+ async store(key, content, contentType = 'text/plain') {
94
+ const fs = await this._ensureDir();
95
+ const path = await import('node:path');
96
+ const sanitizedKey = sanitizeId(key);
97
+ const timestampMs = Date.now();
98
+ this._counter++;
99
+ const ext = FileStorage._extensionFor(contentType);
100
+ const filename = `${timestampMs}_${this._counter}_${sanitizedKey}${ext}`;
101
+ this._contentTypes[filename] = contentType;
102
+ this._metadataWriteChain = this._metadataWriteChain.then(() => this._saveMetadata(fs));
103
+ await this._metadataWriteChain;
104
+ const filePath = path.join(this._artifactDir, filename);
105
+ await fs.writeFile(filePath, content);
106
+ return filePath;
107
+ }
108
+ /** {@inheritdoc} */
109
+ async retrieve(reference) {
110
+ const fs = await this._ensureDir();
111
+ const path = await import('node:path');
112
+ const filePath = path.resolve(this._artifactDir, reference);
113
+ const resolvedDir = path.resolve(this._artifactDir);
114
+ if (!filePath.startsWith(resolvedDir)) {
115
+ throw new Error(`Reference not found: ${reference}`);
116
+ }
117
+ const filename = path.basename(filePath);
118
+ try {
119
+ const content = await fs.readFile(filePath);
120
+ const contentType = this._contentTypes[filename] ?? 'application/octet-stream';
121
+ return { content: new Uint8Array(content), contentType };
122
+ }
123
+ catch {
124
+ throw new Error(`Reference not found: ${reference}`);
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * S3-based storage backend.
130
+ *
131
+ * Stores offloaded content as S3 objects. Content type is preserved as S3 object metadata.
132
+ * References are `s3://` URIs for direct access via AWS CLI or SDK.
133
+ *
134
+ * @param bucket - S3 bucket name
135
+ * @param options - Optional configuration (prefix, region, pre-configured S3Client)
136
+ */
137
+ export class S3Storage {
138
+ _bucket;
139
+ _prefix;
140
+ _client;
141
+ _region;
142
+ _counter = 0;
143
+ constructor(bucket, options) {
144
+ this._bucket = bucket;
145
+ this._prefix = options?.prefix ? options.prefix.replace(/\/+$/, '') + '/' : '';
146
+ this._client = options?.s3Client;
147
+ this._region = options?.region ?? 'us-east-1';
148
+ }
149
+ async _getClient() {
150
+ if (this._client)
151
+ return this._client;
152
+ const { S3Client } = await import('@aws-sdk/client-s3');
153
+ this._client = new S3Client({ region: this._region });
154
+ return this._client;
155
+ }
156
+ /** {@inheritdoc} */
157
+ async store(key, content, contentType = 'text/plain') {
158
+ const client = await this._getClient();
159
+ const { PutObjectCommand } = await import('@aws-sdk/client-s3');
160
+ const sanitizedKey = sanitizeId(key);
161
+ const timestampMs = Date.now();
162
+ this._counter++;
163
+ const s3Key = `${this._prefix}${timestampMs}_${this._counter}_${sanitizedKey}`;
164
+ await client.send(new PutObjectCommand({
165
+ Bucket: this._bucket,
166
+ Key: s3Key,
167
+ Body: content,
168
+ ContentType: contentType,
169
+ }));
170
+ return `s3://${this._bucket}/${s3Key}`;
171
+ }
172
+ /** {@inheritdoc} */
173
+ async retrieve(reference) {
174
+ const client = await this._getClient();
175
+ const { GetObjectCommand } = await import('@aws-sdk/client-s3');
176
+ // Accept both s3:// URIs and raw keys
177
+ let s3Key = reference;
178
+ const uriMatch = reference.match(/^s3:\/\/([^/]+)\/(.+)$/);
179
+ if (uriMatch?.[1] && uriMatch[2]) {
180
+ if (uriMatch[1] !== this._bucket) {
181
+ throw new Error(`Reference not found: ${reference} (bucket mismatch)`);
182
+ }
183
+ s3Key = uriMatch[2];
184
+ }
185
+ try {
186
+ const response = await client.send(new GetObjectCommand({
187
+ Bucket: this._bucket,
188
+ Key: s3Key,
189
+ }));
190
+ const body = await response.Body?.transformToByteArray();
191
+ if (!body)
192
+ throw new Error(`Reference not found: ${reference}`);
193
+ const contentType = response.ContentType ?? 'application/octet-stream';
194
+ return { content: new Uint8Array(body), contentType };
195
+ }
196
+ catch (error) {
197
+ if (error instanceof Error && error.name === 'NoSuchKey') {
198
+ throw new Error(`Reference not found: ${reference}`);
199
+ }
200
+ throw error;
201
+ }
202
+ }
203
+ }
204
+ //# sourceMappingURL=storage.js.map