zeitlich 0.2.36 → 0.2.38

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 (204) hide show
  1. package/README.md +146 -92
  2. package/dist/{activities-BVI2lTwr.d.ts → activities-BKhMtKDd.d.ts} +4 -2
  3. package/dist/{activities-hd4aNnZE.d.cts → activities-CDcwkRZs.d.cts} +4 -2
  4. package/dist/adapters/sandbox/bedrock/index.cjs +17 -14
  5. package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
  6. package/dist/adapters/sandbox/bedrock/index.d.cts +7 -6
  7. package/dist/adapters/sandbox/bedrock/index.d.ts +7 -6
  8. package/dist/adapters/sandbox/bedrock/index.js +17 -14
  9. package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
  10. package/dist/adapters/sandbox/bedrock/workflow.cjs +2 -0
  11. package/dist/adapters/sandbox/bedrock/workflow.cjs.map +1 -1
  12. package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
  13. package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
  14. package/dist/adapters/sandbox/bedrock/workflow.js +2 -0
  15. package/dist/adapters/sandbox/bedrock/workflow.js.map +1 -1
  16. package/dist/adapters/sandbox/daytona/index.cjs +11 -3
  17. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  18. package/dist/adapters/sandbox/daytona/index.d.cts +5 -4
  19. package/dist/adapters/sandbox/daytona/index.d.ts +5 -4
  20. package/dist/adapters/sandbox/daytona/index.js +11 -3
  21. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  22. package/dist/adapters/sandbox/daytona/workflow.cjs +2 -0
  23. package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -1
  24. package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
  25. package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
  26. package/dist/adapters/sandbox/daytona/workflow.js +2 -0
  27. package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
  28. package/dist/adapters/sandbox/e2b/index.cjs +73 -12
  29. package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
  30. package/dist/adapters/sandbox/e2b/index.d.cts +26 -4
  31. package/dist/adapters/sandbox/e2b/index.d.ts +26 -4
  32. package/dist/adapters/sandbox/e2b/index.js +73 -12
  33. package/dist/adapters/sandbox/e2b/index.js.map +1 -1
  34. package/dist/adapters/sandbox/e2b/workflow.cjs +2 -0
  35. package/dist/adapters/sandbox/e2b/workflow.cjs.map +1 -1
  36. package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
  37. package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
  38. package/dist/adapters/sandbox/e2b/workflow.js +2 -0
  39. package/dist/adapters/sandbox/e2b/workflow.js.map +1 -1
  40. package/dist/adapters/sandbox/inmemory/index.cjs +8 -3
  41. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  42. package/dist/adapters/sandbox/inmemory/index.d.cts +5 -4
  43. package/dist/adapters/sandbox/inmemory/index.d.ts +5 -4
  44. package/dist/adapters/sandbox/inmemory/index.js +8 -3
  45. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  46. package/dist/adapters/sandbox/inmemory/workflow.cjs +2 -0
  47. package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -1
  48. package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
  49. package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
  50. package/dist/adapters/sandbox/inmemory/workflow.js +2 -0
  51. package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
  52. package/dist/adapters/thread/anthropic/index.cjs +94 -39
  53. package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
  54. package/dist/adapters/thread/anthropic/index.d.cts +5 -5
  55. package/dist/adapters/thread/anthropic/index.d.ts +5 -5
  56. package/dist/adapters/thread/anthropic/index.js +94 -39
  57. package/dist/adapters/thread/anthropic/index.js.map +1 -1
  58. package/dist/adapters/thread/anthropic/workflow.cjs +7 -2
  59. package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
  60. package/dist/adapters/thread/anthropic/workflow.d.cts +5 -5
  61. package/dist/adapters/thread/anthropic/workflow.d.ts +5 -5
  62. package/dist/adapters/thread/anthropic/workflow.js +7 -2
  63. package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
  64. package/dist/adapters/thread/google-genai/index.cjs +77 -28
  65. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  66. package/dist/adapters/thread/google-genai/index.d.cts +5 -5
  67. package/dist/adapters/thread/google-genai/index.d.ts +5 -5
  68. package/dist/adapters/thread/google-genai/index.js +77 -28
  69. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  70. package/dist/adapters/thread/google-genai/workflow.cjs +7 -2
  71. package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
  72. package/dist/adapters/thread/google-genai/workflow.d.cts +5 -5
  73. package/dist/adapters/thread/google-genai/workflow.d.ts +5 -5
  74. package/dist/adapters/thread/google-genai/workflow.js +7 -2
  75. package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
  76. package/dist/adapters/thread/langchain/index.cjs +57 -10
  77. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  78. package/dist/adapters/thread/langchain/index.d.cts +5 -5
  79. package/dist/adapters/thread/langchain/index.d.ts +5 -5
  80. package/dist/adapters/thread/langchain/index.js +57 -10
  81. package/dist/adapters/thread/langchain/index.js.map +1 -1
  82. package/dist/adapters/thread/langchain/workflow.cjs +7 -2
  83. package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
  84. package/dist/adapters/thread/langchain/workflow.d.cts +5 -5
  85. package/dist/adapters/thread/langchain/workflow.d.ts +5 -5
  86. package/dist/adapters/thread/langchain/workflow.js +7 -2
  87. package/dist/adapters/thread/langchain/workflow.js.map +1 -1
  88. package/dist/index.cjs +322 -146
  89. package/dist/index.cjs.map +1 -1
  90. package/dist/index.d.cts +20 -14
  91. package/dist/index.d.ts +20 -14
  92. package/dist/index.js +323 -147
  93. package/dist/index.js.map +1 -1
  94. package/dist/{proxy-BjdFGPTm.d.ts → proxy-CUlKSvZS.d.ts} +1 -1
  95. package/dist/{proxy-7RnVaPdJ.d.cts → proxy-D_3x7RN4.d.cts} +1 -1
  96. package/dist/{thread-manager-CbpiGq1L.d.ts → thread-manager-CVu7o2cs.d.ts} +4 -2
  97. package/dist/{thread-manager-DzXm9eeI.d.cts → thread-manager-HSwyh28L.d.cts} +4 -2
  98. package/dist/{thread-manager-BBzNgQWH.d.cts → thread-manager-c1gPopAG.d.ts} +4 -2
  99. package/dist/{thread-manager-DjN5JYul.d.ts → thread-manager-wGi-LqIP.d.cts} +4 -2
  100. package/dist/{types-Mc_4BCfT.d.cts → types-BH_IRryz.d.ts} +10 -1
  101. package/dist/{types-yiXmqedU.d.ts → types-BaOw4hKI.d.cts} +10 -1
  102. package/dist/{types-DQ1l_gXL.d.cts → types-C06FwR96.d.cts} +121 -17
  103. package/dist/{types-wiGLvxWf.d.ts → types-DAsQ21Rt.d.ts} +1 -1
  104. package/dist/{types-CADc5V_P.d.ts → types-DNr31FzL.d.ts} +121 -17
  105. package/dist/{types-CBH54cwr.d.cts → types-lm8tMNJQ.d.cts} +1 -1
  106. package/dist/{types-DxCpFNv_.d.cts → types-yx0LzPGn.d.cts} +44 -5
  107. package/dist/{types-DxCpFNv_.d.ts → types-yx0LzPGn.d.ts} +44 -5
  108. package/dist/{workflow-DhtWRovz.d.cts → workflow-CSCkpwAL.d.ts} +2 -2
  109. package/dist/{workflow-P2pTSfKu.d.ts → workflow-DuvMZ8Vm.d.cts} +2 -2
  110. package/dist/workflow.cjs +274 -130
  111. package/dist/workflow.cjs.map +1 -1
  112. package/dist/workflow.d.cts +3 -3
  113. package/dist/workflow.d.ts +3 -3
  114. package/dist/workflow.js +275 -131
  115. package/dist/workflow.js.map +1 -1
  116. package/package.json +2 -2
  117. package/src/adapters/sandbox/bedrock/filesystem.ts +6 -12
  118. package/src/adapters/sandbox/bedrock/index.ts +22 -11
  119. package/src/adapters/sandbox/bedrock/proxy.ts +2 -0
  120. package/src/adapters/sandbox/daytona/index.ts +18 -3
  121. package/src/adapters/sandbox/daytona/proxy.ts +2 -0
  122. package/src/adapters/sandbox/e2b/filesystem.ts +5 -4
  123. package/src/adapters/sandbox/e2b/index.ts +87 -14
  124. package/src/adapters/sandbox/e2b/proxy.ts +2 -0
  125. package/src/adapters/sandbox/e2b/types.ts +16 -0
  126. package/src/adapters/sandbox/inmemory/index.ts +17 -3
  127. package/src/adapters/sandbox/inmemory/proxy.ts +2 -0
  128. package/src/adapters/thread/anthropic/activities.ts +58 -26
  129. package/src/adapters/thread/anthropic/model-invoker.ts +18 -7
  130. package/src/adapters/thread/anthropic/proxy.ts +6 -2
  131. package/src/adapters/thread/anthropic/thread-manager.test.ts +26 -7
  132. package/src/adapters/thread/anthropic/thread-manager.ts +63 -46
  133. package/src/adapters/thread/google-genai/activities.ts +20 -2
  134. package/src/adapters/thread/google-genai/model-invoker.ts +27 -7
  135. package/src/adapters/thread/google-genai/proxy.ts +6 -2
  136. package/src/adapters/thread/google-genai/thread-manager.test.ts +13 -3
  137. package/src/adapters/thread/google-genai/thread-manager.ts +57 -33
  138. package/src/adapters/thread/langchain/activities.ts +55 -24
  139. package/src/adapters/thread/langchain/hooks.test.ts +36 -49
  140. package/src/adapters/thread/langchain/hooks.ts +18 -5
  141. package/src/adapters/thread/langchain/model-invoker.ts +5 -4
  142. package/src/adapters/thread/langchain/proxy.ts +6 -2
  143. package/src/adapters/thread/langchain/thread-manager.test.ts +5 -1
  144. package/src/adapters/thread/langchain/thread-manager.ts +23 -9
  145. package/src/index.ts +4 -1
  146. package/src/lib/activity.ts +16 -6
  147. package/src/lib/hooks/types.ts +6 -6
  148. package/src/lib/lifecycle.ts +18 -3
  149. package/src/lib/model/proxy.ts +2 -2
  150. package/src/lib/model/types.ts +10 -0
  151. package/src/lib/observability/hooks.ts +4 -5
  152. package/src/lib/observability/index.ts +1 -4
  153. package/src/lib/sandbox/manager.ts +45 -20
  154. package/src/lib/sandbox/node-fs.ts +3 -6
  155. package/src/lib/sandbox/sandbox.test.ts +36 -3
  156. package/src/lib/sandbox/tree.integration.test.ts +10 -3
  157. package/src/lib/sandbox/types.ts +60 -6
  158. package/src/lib/session/session-edge-cases.integration.test.ts +316 -14
  159. package/src/lib/session/session.integration.test.ts +161 -1
  160. package/src/lib/session/session.ts +106 -21
  161. package/src/lib/session/types.ts +25 -5
  162. package/src/lib/skills/fs-provider.ts +12 -8
  163. package/src/lib/skills/handler.ts +1 -1
  164. package/src/lib/skills/parse.ts +3 -1
  165. package/src/lib/skills/register.ts +1 -3
  166. package/src/lib/skills/skills.integration.test.ts +25 -15
  167. package/src/lib/state/manager.integration.test.ts +12 -2
  168. package/src/lib/subagent/define.ts +1 -1
  169. package/src/lib/subagent/handler.ts +186 -71
  170. package/src/lib/subagent/index.ts +1 -5
  171. package/src/lib/subagent/register.ts +3 -2
  172. package/src/lib/subagent/signals.ts +1 -10
  173. package/src/lib/subagent/subagent.integration.test.ts +526 -248
  174. package/src/lib/subagent/tool.ts +4 -3
  175. package/src/lib/subagent/types.ts +50 -20
  176. package/src/lib/subagent/workflow.ts +9 -49
  177. package/src/lib/thread/id.test.ts +1 -1
  178. package/src/lib/thread/id.ts +1 -2
  179. package/src/lib/thread/manager.ts +18 -0
  180. package/src/lib/thread/proxy.ts +4 -4
  181. package/src/lib/thread/types.ts +20 -3
  182. package/src/lib/tool-router/index.ts +3 -5
  183. package/src/lib/tool-router/router-edge-cases.integration.test.ts +93 -1
  184. package/src/lib/tool-router/router.integration.test.ts +12 -0
  185. package/src/lib/tool-router/router.ts +90 -16
  186. package/src/lib/tool-router/types.ts +45 -4
  187. package/src/lib/tool-router/with-sandbox.ts +19 -5
  188. package/src/lib/virtual-fs/filesystem.ts +1 -1
  189. package/src/lib/virtual-fs/index.ts +5 -1
  190. package/src/lib/virtual-fs/mutations.ts +2 -4
  191. package/src/lib/virtual-fs/queries.ts +9 -5
  192. package/src/lib/virtual-fs/types.ts +4 -1
  193. package/src/lib/virtual-fs/virtual-fs.test.ts +9 -11
  194. package/src/lib/workflow.test.ts +7 -4
  195. package/src/lib/workflow.ts +1 -5
  196. package/src/tools/ask-user-question/tool.ts +1 -3
  197. package/src/tools/glob/handler.ts +1 -4
  198. package/src/tools/task-get/handler.ts +4 -5
  199. package/src/tools/task-list/handler.ts +1 -4
  200. package/src/tools/task-update/handler.ts +4 -5
  201. package/src/workflow.ts +22 -7
  202. package/tsup.config.ts +9 -6
  203. package/src/lib/.env +0 -1
  204. package/src/tools/bash/.env +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zeitlich",
3
- "version": "0.2.36",
3
+ "version": "0.2.38",
4
4
  "description": "[EXPERIMENTAL] An opinionated AI agent implementation for Temporal",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -210,7 +210,7 @@
210
210
  "node": ">=18"
211
211
  },
212
212
  "devDependencies": {
213
- "@anthropic-ai/sdk": "^0.80.0",
213
+ "@anthropic-ai/sdk": "^0.81.0",
214
214
  "@aws-sdk/client-bedrock-agentcore": "^3.900.0",
215
215
  "@daytonaio/sdk": "^0.158.1",
216
216
  "@e2b/code-interpreter": "^2.3.3",
@@ -26,9 +26,7 @@ async function consumeStream(
26
26
  event.resourceNotFoundException.message ?? "Resource not found"
27
27
  );
28
28
  if ("validationException" in event && event.validationException)
29
- throw new Error(
30
- event.validationException.message ?? "Validation error"
31
- );
29
+ throw new Error(event.validationException.message ?? "Validation error");
32
30
  if ("internalServerException" in event && event.internalServerException)
33
31
  throw new Error(
34
32
  event.internalServerException.message ?? "Internal server error"
@@ -185,9 +183,7 @@ export class BedrockSandboxFileSystem implements SandboxFileSystem {
185
183
  async appendFile(path: string, content: string | Uint8Array): Promise<void> {
186
184
  const norm = this.normalisePath(path);
187
185
  const addition =
188
- typeof content === "string"
189
- ? content
190
- : new TextDecoder().decode(content);
186
+ typeof content === "string" ? content : new TextDecoder().decode(content);
191
187
  const escaped = addition.replace(/'/g, "'\\''");
192
188
  const { exitCode, stderr } = await this.execShell(
193
189
  `printf '%s' '${escaped}' >> "${norm}"`
@@ -227,9 +223,7 @@ export class BedrockSandboxFileSystem implements SandboxFileSystem {
227
223
  async mkdir(path: string, options?: { recursive?: boolean }): Promise<void> {
228
224
  const norm = this.normalisePath(path);
229
225
  const flag = options?.recursive ? "-p " : "";
230
- const { exitCode, stderr } = await this.execShell(
231
- `mkdir ${flag}"${norm}"`
232
- );
226
+ const { exitCode, stderr } = await this.execShell(`mkdir ${flag}"${norm}"`);
233
227
  if (exitCode !== 0) throw new Error(`mkdir failed: ${stderr}`);
234
228
  }
235
229
 
@@ -287,7 +281,8 @@ export class BedrockSandboxFileSystem implements SandboxFileSystem {
287
281
  ): Promise<void> {
288
282
  const norm = this.normalisePath(path);
289
283
  if (options?.recursive || options?.force) {
290
- const flags = `${options?.recursive ? "-r" : ""} ${options?.force ? "-f" : ""}`.trim();
284
+ const flags =
285
+ `${options?.recursive ? "-r" : ""} ${options?.force ? "-f" : ""}`.trim();
291
286
  const { exitCode, stderr } = await this.execShell(
292
287
  `rm ${flags} "${norm}"`
293
288
  );
@@ -301,8 +296,7 @@ export class BedrockSandboxFileSystem implements SandboxFileSystem {
301
296
  paths: [rel],
302
297
  });
303
298
  if (result.isError) {
304
- const msg =
305
- result.content?.map((b) => b.text).join("") ?? "rm failed";
299
+ const msg = result.content?.map((b) => b.text).join("") ?? "rm failed";
306
300
  throw new Error(msg);
307
301
  }
308
302
  }
@@ -49,9 +49,7 @@ async function consumeExecStream(
49
49
  event.resourceNotFoundException.message ?? "Resource not found"
50
50
  );
51
51
  if ("validationException" in event && event.validationException)
52
- throw new Error(
53
- event.validationException.message ?? "Validation error"
54
- );
52
+ throw new Error(event.validationException.message ?? "Validation error");
55
53
  if ("internalServerException" in event && event.internalServerException)
56
54
  throw new Error(
57
55
  event.internalServerException.message ?? "Internal server error"
@@ -118,8 +116,7 @@ class BedrockSandboxImpl implements Sandbox {
118
116
  })
119
117
  );
120
118
 
121
- if (!resp.stream)
122
- throw new Error("No stream in code interpreter response");
119
+ if (!resp.stream) throw new Error("No stream in code interpreter response");
123
120
  return consumeExecStream(resp.stream);
124
121
  }
125
122
 
@@ -137,9 +134,10 @@ class BedrockSandboxImpl implements Sandbox {
137
134
  // BedrockSandboxProvider
138
135
  // ============================================================================
139
136
 
140
- export class BedrockSandboxProvider
141
- implements SandboxProvider<BedrockSandboxCreateOptions, BedrockSandbox>
142
- {
137
+ export class BedrockSandboxProvider implements SandboxProvider<
138
+ BedrockSandboxCreateOptions,
139
+ BedrockSandbox
140
+ > {
143
141
  readonly id = "bedrock";
144
142
  readonly capabilities: SandboxCapabilities = {
145
143
  filesystem: true,
@@ -241,17 +239,30 @@ export class BedrockSandboxProvider
241
239
  // Bedrock sandboxes don't support pause, so resume is a no-op
242
240
  }
243
241
 
244
- async snapshot(_sandboxId: string): Promise<SandboxSnapshot> {
242
+ async snapshot(
243
+ _sandboxId: string,
244
+ _options?: BedrockSandboxCreateOptions
245
+ ): Promise<SandboxSnapshot> {
245
246
  throw new SandboxNotSupportedError("snapshot");
246
247
  }
247
248
 
248
- async restore(_snapshot: SandboxSnapshot): Promise<never> {
249
+ async restore(
250
+ _snapshot: SandboxSnapshot,
251
+ _options?: BedrockSandboxCreateOptions
252
+ ): Promise<never> {
249
253
  throw new SandboxNotSupportedError("restore");
250
254
  }
251
255
 
252
- async fork(_sandboxId: string): Promise<Sandbox> {
256
+ async fork(
257
+ _sandboxId: string,
258
+ _options?: BedrockSandboxCreateOptions
259
+ ): Promise<Sandbox> {
253
260
  throw new SandboxNotSupportedError("fork");
254
261
  }
262
+
263
+ async deleteSnapshot(_snapshot: SandboxSnapshot): Promise<void> {
264
+ throw new SandboxNotSupportedError("deleteSnapshot");
265
+ }
255
266
  }
256
267
 
257
268
  // Re-exports
@@ -52,6 +52,8 @@ export function proxyBedrockSandboxOps(
52
52
  pauseSandbox: acts[p("pauseSandbox")],
53
53
  resumeSandbox: acts[p("resumeSandbox")],
54
54
  snapshotSandbox: acts[p("snapshotSandbox")],
55
+ restoreSandbox: acts[p("restoreSandbox")],
56
+ deleteSandboxSnapshot: acts[p("deleteSandboxSnapshot")],
55
57
  forkSandbox: acts[p("forkSandbox")],
56
58
  } as SandboxOps<BedrockSandboxCreateOptions>;
57
59
  }
@@ -149,21 +149,36 @@ export class DaytonaSandboxProvider implements SandboxProvider<
149
149
  // Daytona sandboxes don't support pause, so resume is a no-op
150
150
  }
151
151
 
152
- async fork(_sandboxId: string): Promise<Sandbox> {
152
+ async fork(
153
+ _sandboxId: string,
154
+ _options?: DaytonaSandboxCreateOptions
155
+ ): Promise<Sandbox> {
153
156
  throw new Error("Not implemented");
154
157
  }
155
158
 
156
- async snapshot(_sandboxId: string): Promise<SandboxSnapshot> {
159
+ async snapshot(
160
+ _sandboxId: string,
161
+ _options?: DaytonaSandboxCreateOptions
162
+ ): Promise<SandboxSnapshot> {
157
163
  throw new SandboxNotSupportedError(
158
164
  "snapshot (use Daytona's native snapshot API directly)"
159
165
  );
160
166
  }
161
167
 
162
- async restore(_snapshot: SandboxSnapshot): Promise<never> {
168
+ async restore(
169
+ _snapshot: SandboxSnapshot,
170
+ _options?: DaytonaSandboxCreateOptions
171
+ ): Promise<never> {
163
172
  throw new SandboxNotSupportedError(
164
173
  "restore (use Daytona's native snapshot API directly)"
165
174
  );
166
175
  }
176
+
177
+ async deleteSnapshot(_snapshot: SandboxSnapshot): Promise<void> {
178
+ throw new SandboxNotSupportedError(
179
+ "deleteSnapshot (use Daytona's native snapshot API directly)"
180
+ );
181
+ }
167
182
  }
168
183
 
169
184
  // Re-exports
@@ -52,6 +52,8 @@ export function proxyDaytonaSandboxOps(
52
52
  pauseSandbox: acts[p("pauseSandbox")],
53
53
  resumeSandbox: acts[p("resumeSandbox")],
54
54
  snapshotSandbox: acts[p("snapshotSandbox")],
55
+ restoreSandbox: acts[p("restoreSandbox")],
56
+ deleteSandboxSnapshot: acts[p("deleteSandboxSnapshot")],
55
57
  forkSandbox: acts[p("forkSandbox")],
56
58
  } as SandboxOps<DaytonaSandboxCreateOptions>;
57
59
  }
@@ -7,7 +7,10 @@ import type {
7
7
  import { posix } from "node:path";
8
8
 
9
9
  function toArrayBuffer(u8: Uint8Array): ArrayBuffer {
10
- return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength) as ArrayBuffer;
10
+ return u8.buffer.slice(
11
+ u8.byteOffset,
12
+ u8.byteOffset + u8.byteLength
13
+ ) as ArrayBuffer;
11
14
  }
12
15
 
13
16
  /**
@@ -59,9 +62,7 @@ export class E2bSandboxFileSystem implements SandboxFileSystem {
59
62
  // file doesn't exist yet — write from scratch
60
63
  }
61
64
  const addition =
62
- typeof content === "string"
63
- ? content
64
- : new TextDecoder().decode(content);
65
+ typeof content === "string" ? content : new TextDecoder().decode(content);
65
66
  await this.sandbox.files.write(norm, existing + addition);
66
67
  }
67
68
 
@@ -62,9 +62,10 @@ class E2bSandboxImpl implements Sandbox {
62
62
  // E2bSandboxProvider
63
63
  // ============================================================================
64
64
 
65
- export class E2bSandboxProvider
66
- implements SandboxProvider<E2bSandboxCreateOptions, E2bSandbox>
67
- {
65
+ export class E2bSandboxProvider implements SandboxProvider<
66
+ E2bSandboxCreateOptions,
67
+ E2bSandbox
68
+ > {
68
69
  readonly id = "e2b";
69
70
  readonly capabilities: SandboxCapabilities = {
70
71
  filesystem: true,
@@ -75,11 +76,19 @@ export class E2bSandboxProvider
75
76
  private readonly defaultTemplate?: string;
76
77
  private readonly defaultWorkspaceBase: string;
77
78
  private readonly defaultTimeoutMs?: number;
79
+ private readonly defaultAllowInternetAccess?: boolean;
80
+ private readonly defaultNetwork?: E2bSandboxConfig["network"];
81
+ private readonly defaultMetadata?: E2bSandboxConfig["metadata"];
82
+ private readonly defaultLifecycle?: E2bSandboxConfig["lifecycle"];
78
83
 
79
84
  constructor(config?: E2bSandboxConfig) {
80
85
  this.defaultTemplate = config?.template;
81
86
  this.defaultWorkspaceBase = config?.workspaceBase ?? "/home/user";
82
87
  this.defaultTimeoutMs = config?.timeoutMs;
88
+ this.defaultAllowInternetAccess = config?.allowInternetAccess;
89
+ this.defaultNetwork = config?.network;
90
+ this.defaultMetadata = config?.metadata;
91
+ this.defaultLifecycle = config?.lifecycle;
83
92
  }
84
93
 
85
94
  async create(
@@ -87,10 +96,7 @@ export class E2bSandboxProvider
87
96
  ): Promise<SandboxCreateResult> {
88
97
  const template = options?.template ?? this.defaultTemplate;
89
98
  const workspaceBase = this.defaultWorkspaceBase;
90
- const createOpts = {
91
- envs: options?.env,
92
- timeoutMs: options?.timeoutMs ?? this.defaultTimeoutMs,
93
- };
99
+ const createOpts = this.buildSdkCreateOpts(options);
94
100
 
95
101
  const sdkSandbox = template
96
102
  ? await E2bSdkSandbox.create(template, createOpts)
@@ -116,7 +122,11 @@ export class E2bSandboxProvider
116
122
  async get(sandboxId: string): Promise<E2bSandbox> {
117
123
  try {
118
124
  const sdkSandbox = await E2bSdkSandbox.connect(sandboxId);
119
- return new E2bSandboxImpl(sandboxId, sdkSandbox, this.defaultWorkspaceBase);
125
+ return new E2bSandboxImpl(
126
+ sandboxId,
127
+ sdkSandbox,
128
+ this.defaultWorkspaceBase
129
+ );
120
130
  } catch {
121
131
  throw new SandboxNotFoundError(sandboxId);
122
132
  }
@@ -140,23 +150,86 @@ export class E2bSandboxProvider
140
150
  await E2bSdkSandbox.connect(sandboxId);
141
151
  }
142
152
 
143
- async snapshot(_sandboxId: string): Promise<SandboxSnapshot> {
144
- throw new SandboxNotSupportedError("snapshot");
153
+ async snapshot(
154
+ sandboxId: string,
155
+ _options?: E2bSandboxCreateOptions
156
+ ): Promise<SandboxSnapshot> {
157
+ const { snapshotId } = await E2bSdkSandbox.createSnapshot(sandboxId);
158
+ return {
159
+ sandboxId,
160
+ providerId: this.id,
161
+ data: { snapshotId },
162
+ createdAt: new Date().toISOString(),
163
+ };
164
+ }
165
+
166
+ async restore(
167
+ snapshot: SandboxSnapshot,
168
+ options?: E2bSandboxCreateOptions
169
+ ): Promise<Sandbox> {
170
+ const data = snapshot.data as { snapshotId?: string } | null;
171
+ if (!data?.snapshotId) {
172
+ throw new SandboxNotSupportedError(
173
+ "restore: snapshot is missing snapshotId"
174
+ );
175
+ }
176
+ const sdkOpts = this.buildSdkCreateOpts(options);
177
+ const sdkSandbox = await E2bSdkSandbox.create(data.snapshotId, sdkOpts);
178
+ return new E2bSandboxImpl(
179
+ sdkSandbox.sandboxId,
180
+ sdkSandbox,
181
+ this.defaultWorkspaceBase
182
+ );
145
183
  }
146
184
 
147
- async restore(_snapshot: SandboxSnapshot): Promise<Sandbox> {
148
- throw new SandboxNotSupportedError("restore");
185
+ async deleteSnapshot(snapshot: SandboxSnapshot): Promise<void> {
186
+ const data = snapshot.data as { snapshotId?: string } | null;
187
+ if (!data?.snapshotId) return;
188
+ try {
189
+ await E2bSdkSandbox.deleteSnapshot(data.snapshotId);
190
+ } catch {
191
+ // Already deleted or no longer accessible — treat as no-op.
192
+ }
149
193
  }
150
194
 
151
- async fork(sandboxId: string): Promise<Sandbox> {
195
+ async fork(
196
+ sandboxId: string,
197
+ options?: E2bSandboxCreateOptions
198
+ ): Promise<Sandbox> {
152
199
  const { snapshotId } = await E2bSdkSandbox.createSnapshot(sandboxId);
153
- const sdkSandbox = await E2bSdkSandbox.create(snapshotId);
200
+ const sdkOpts = this.buildSdkCreateOpts(options);
201
+ const sdkSandbox = await E2bSdkSandbox.create(snapshotId, sdkOpts);
154
202
  return new E2bSandboxImpl(
155
203
  sdkSandbox.sandboxId,
156
204
  sdkSandbox,
157
205
  this.defaultWorkspaceBase
158
206
  );
159
207
  }
208
+
209
+ private buildSdkCreateOpts(options?: E2bSandboxCreateOptions) {
210
+ const network = options?.network ?? this.defaultNetwork;
211
+ const lifecycle = options?.lifecycle ?? this.defaultLifecycle;
212
+ return {
213
+ envs: options?.env,
214
+ timeoutMs: options?.timeoutMs ?? this.defaultTimeoutMs,
215
+ metadata: options?.metadata ?? this.defaultMetadata,
216
+ allowInternetAccess:
217
+ options?.allowInternetAccess ?? this.defaultAllowInternetAccess,
218
+ network: network
219
+ ? {
220
+ allowOut: network.allowOut,
221
+ denyOut: network.denyOut,
222
+ allowPublicTraffic: network.allowPublicTraffic,
223
+ }
224
+ : undefined,
225
+ lifecycle: lifecycle
226
+ ? {
227
+ onTimeout: lifecycle.onTimeout,
228
+ autoResume: lifecycle.autoResume,
229
+ }
230
+ : undefined,
231
+ };
232
+ }
160
233
  }
161
234
 
162
235
  // Re-exports
@@ -52,6 +52,8 @@ export function proxyE2bSandboxOps(
52
52
  pauseSandbox: acts[p("pauseSandbox")],
53
53
  resumeSandbox: acts[p("resumeSandbox")],
54
54
  snapshotSandbox: acts[p("snapshotSandbox")],
55
+ restoreSandbox: acts[p("restoreSandbox")],
56
+ deleteSandboxSnapshot: acts[p("deleteSandboxSnapshot")],
55
57
  forkSandbox: acts[p("forkSandbox")],
56
58
  } as SandboxOps<E2bSandboxCreateOptions>;
57
59
  }
@@ -6,6 +6,14 @@ import type { E2bSandboxFileSystem } from "./filesystem";
6
6
  */
7
7
  export type E2bSandbox = Sandbox & { fs: E2bSandboxFileSystem };
8
8
 
9
+ /**
10
+ * Provider-level defaults for E2B sandboxes. Every lifecycle op
11
+ * (`create` / `restore` / `fork`) merges per-call options on top of these —
12
+ * per-call options win per-field. This is how E2B preserves sandbox-level
13
+ * config (network policy, metadata, lifecycle, timeout) across
14
+ * snapshot/restore and fork, since the E2B API treats those as pure
15
+ * create-time inputs that aren't carried in the snapshot blob.
16
+ */
9
17
  export interface E2bSandboxConfig {
10
18
  /** Sandbox template name or ID */
11
19
  template?: string;
@@ -13,6 +21,14 @@ export interface E2bSandboxConfig {
13
21
  workspaceBase?: string;
14
22
  /** Sandbox idle timeout in milliseconds */
15
23
  timeoutMs?: number;
24
+ /** Default outbound internet access policy */
25
+ allowInternetAccess?: boolean;
26
+ /** Default outbound network allow/deny rules */
27
+ network?: SandboxCreateOptions["network"];
28
+ /** Default metadata surfaced via provider list/query APIs */
29
+ metadata?: SandboxCreateOptions["metadata"];
30
+ /** Default sandbox timeout behaviour */
31
+ lifecycle?: SandboxCreateOptions["lifecycle"];
16
32
  }
17
33
 
18
34
  export interface E2bSandboxCreateOptions extends SandboxCreateOptions {
@@ -183,7 +183,10 @@ export class InMemorySandboxProvider implements SandboxProvider {
183
183
  return { sandbox };
184
184
  }
185
185
 
186
- async snapshot(sandboxId: string): Promise<SandboxSnapshot> {
186
+ async snapshot(
187
+ sandboxId: string,
188
+ _options?: SandboxCreateOptions
189
+ ): Promise<SandboxSnapshot> {
187
190
  const sandbox = this.sandboxes.get(sandboxId);
188
191
  if (!sandbox) throw new SandboxNotFoundError(sandboxId);
189
192
 
@@ -210,7 +213,10 @@ export class InMemorySandboxProvider implements SandboxProvider {
210
213
  };
211
214
  }
212
215
 
213
- async fork(sandboxId: string): Promise<Sandbox> {
216
+ async fork(
217
+ sandboxId: string,
218
+ _options?: SandboxCreateOptions
219
+ ): Promise<Sandbox> {
214
220
  const sandbox = await this.get(sandboxId);
215
221
 
216
222
  const entries = await sandbox.fs.readdirWithFileTypes("/");
@@ -228,7 +234,10 @@ export class InMemorySandboxProvider implements SandboxProvider {
228
234
  return newSandbox.sandbox;
229
235
  }
230
236
 
231
- async restore(snapshot: SandboxSnapshot): Promise<Sandbox> {
237
+ async restore(
238
+ snapshot: SandboxSnapshot,
239
+ _options?: SandboxCreateOptions
240
+ ): Promise<Sandbox> {
232
241
  const { files } = snapshot.data as { files: Record<string, string> };
233
242
  const initialFiles: InitialFiles = {};
234
243
  for (const [path, content] of Object.entries(files)) {
@@ -244,4 +253,9 @@ export class InMemorySandboxProvider implements SandboxProvider {
244
253
  this.sandboxes.set(sandbox.id, sandbox);
245
254
  return sandbox;
246
255
  }
256
+
257
+ async deleteSnapshot(_snapshot: SandboxSnapshot): Promise<void> {
258
+ // In-memory snapshots are opaque data held by the caller — nothing to
259
+ // delete on the provider side.
260
+ }
247
261
  }
@@ -49,6 +49,8 @@ export function proxyInMemorySandboxOps(
49
49
  pauseSandbox: acts[p("pauseSandbox")],
50
50
  resumeSandbox: acts[p("resumeSandbox")],
51
51
  snapshotSandbox: acts[p("snapshotSandbox")],
52
+ restoreSandbox: acts[p("restoreSandbox")],
53
+ deleteSandboxSnapshot: acts[p("deleteSandboxSnapshot")],
52
54
  forkSandbox: acts[p("forkSandbox")],
53
55
  } as SandboxOps;
54
56
  }
@@ -25,8 +25,10 @@ import {
25
25
 
26
26
  const ADAPTER_PREFIX = "anthropic" as const;
27
27
 
28
- export type AnthropicThreadOps<TScope extends string = ""> =
29
- PrefixedThreadOps<ScopedPrefix<TScope, typeof ADAPTER_PREFIX>, AnthropicContent>;
28
+ export type AnthropicThreadOps<TScope extends string = ""> = PrefixedThreadOps<
29
+ ScopedPrefix<TScope, typeof ADAPTER_PREFIX>,
30
+ AnthropicContent
31
+ >;
30
32
 
31
33
  export interface AnthropicAdapterConfig {
32
34
  redis: Redis;
@@ -47,7 +49,8 @@ export interface AnthropicAdapterConfig {
47
49
  * (e.g. `{ type: "text", text: "..." }`, `{ type: "image", source: { ... } }`).
48
50
  * Passed through as-is to the `tool_result` block.
49
51
  */
50
- export type AnthropicToolResponse = Anthropic.Messages.ToolResultBlockParam["content"];
52
+ export type AnthropicToolResponse =
53
+ Anthropic.Messages.ToolResultBlockParam["content"];
51
54
 
52
55
  export interface AnthropicAdapter {
53
56
  /** Model invoker using the default model (only available when `model` was provided) */
@@ -55,7 +58,7 @@ export interface AnthropicAdapter {
55
58
  /** Create an invoker for a specific model name (for multi-model setups) */
56
59
  createModelInvoker(
57
60
  model: string,
58
- maxTokens?: number,
61
+ maxTokens?: number
59
62
  ): ModelInvoker<Anthropic.Messages.Message>;
60
63
  /**
61
64
  * Create prefixed thread activities for registration on the worker.
@@ -72,9 +75,7 @@ export interface AnthropicAdapter {
72
75
  * // → { anthropicResearchAgentInitializeThread, … }
73
76
  * ```
74
77
  */
75
- createActivities<S extends string = "">(
76
- scope?: S,
77
- ): AnthropicThreadOps<S>;
78
+ createActivities<S extends string = "">(scope?: S): AnthropicThreadOps<S>;
78
79
 
79
80
  /**
80
81
  * Identity wrapper that types a tool handler for this adapter.
@@ -83,8 +84,8 @@ export interface AnthropicAdapter {
83
84
  wrapHandler<TArgs, TResult, TContext extends RouterContext = RouterContext>(
84
85
  handler: (
85
86
  args: TArgs,
86
- context: TContext,
87
- ) => Promise<ToolHandlerResponse<TResult, AnthropicToolResponse>>,
87
+ context: TContext
88
+ ) => Promise<ToolHandlerResponse<TResult, AnthropicToolResponse>>
88
89
  ): ActivityToolHandler<TArgs, TResult, TContext, AnthropicToolResponse>;
89
90
  }
90
91
 
@@ -130,13 +131,20 @@ export interface AnthropicAdapter {
130
131
  * ```
131
132
  */
132
133
  export function createAnthropicAdapter(
133
- config: AnthropicAdapterConfig,
134
+ config: AnthropicAdapterConfig
134
135
  ): AnthropicAdapter {
135
136
  const { redis, client } = config;
136
137
 
137
138
  const threadOps: ThreadOps<AnthropicContent> = {
138
- async initializeThread(threadId: string, threadKey?: string): Promise<void> {
139
- const thread = createAnthropicThreadManager({ redis, threadId, key: threadKey });
139
+ async initializeThread(
140
+ threadId: string,
141
+ threadKey?: string
142
+ ): Promise<void> {
143
+ const thread = createAnthropicThreadManager({
144
+ redis,
145
+ threadId,
146
+ key: threadKey,
147
+ });
140
148
  await thread.initialize();
141
149
  },
142
150
 
@@ -144,9 +152,13 @@ export function createAnthropicAdapter(
144
152
  threadId: string,
145
153
  id: string,
146
154
  content: AnthropicContent,
147
- threadKey?: string,
155
+ threadKey?: string
148
156
  ): Promise<void> {
149
- const thread = createAnthropicThreadManager({ redis, threadId, key: threadKey });
157
+ const thread = createAnthropicThreadManager({
158
+ redis,
159
+ threadId,
160
+ key: threadKey,
161
+ });
150
162
  await thread.appendUserMessage(id, content);
151
163
  },
152
164
 
@@ -154,15 +166,23 @@ export function createAnthropicAdapter(
154
166
  threadId: string,
155
167
  id: string,
156
168
  content: AnthropicSystemContent,
157
- threadKey?: string,
169
+ threadKey?: string
158
170
  ): Promise<void> {
159
- const thread = createAnthropicThreadManager({ redis, threadId, key: threadKey });
171
+ const thread = createAnthropicThreadManager({
172
+ redis,
173
+ threadId,
174
+ key: threadKey,
175
+ });
160
176
  await thread.appendSystemMessage(id, content);
161
177
  },
162
178
 
163
179
  async appendToolResult(id: string, cfg: ToolResultConfig): Promise<void> {
164
180
  const { threadId, threadKey, toolCallId, toolName, content } = cfg;
165
- const thread = createAnthropicThreadManager({ redis, threadId, key: threadKey });
181
+ const thread = createAnthropicThreadManager({
182
+ redis,
183
+ threadId,
184
+ key: threadKey,
185
+ });
166
186
  await thread.appendToolResult(id, toolCallId, toolName, content);
167
187
  },
168
188
 
@@ -170,16 +190,20 @@ export function createAnthropicAdapter(
170
190
  threadId: string,
171
191
  id: string,
172
192
  message: Anthropic.Messages.Message,
173
- threadKey?: string,
193
+ threadKey?: string
174
194
  ): Promise<void> {
175
- const thread = createAnthropicThreadManager({ redis, threadId, key: threadKey });
195
+ const thread = createAnthropicThreadManager({
196
+ redis,
197
+ threadId,
198
+ key: threadKey,
199
+ });
176
200
  await thread.appendAssistantMessage(id, message.content);
177
201
  },
178
202
 
179
203
  async forkThread(
180
204
  sourceThreadId: string,
181
205
  targetThreadId: string,
182
- threadKey?: string,
206
+ threadKey?: string
183
207
  ): Promise<void> {
184
208
  const thread = createAnthropicThreadManager({
185
209
  redis,
@@ -188,24 +212,32 @@ export function createAnthropicAdapter(
188
212
  });
189
213
  await thread.fork(targetThreadId);
190
214
  },
215
+
216
+ async truncateThread(
217
+ threadId: string,
218
+ length: number,
219
+ threadKey?: string,
220
+ ): Promise<void> {
221
+ const thread = createAnthropicThreadManager({ redis, threadId, key: threadKey });
222
+ await thread.truncate(length);
223
+ },
191
224
  };
192
225
 
193
226
  function createActivities<S extends string = "">(
194
- scope?: S,
227
+ scope?: S
195
228
  ): AnthropicThreadOps<S> {
196
229
  const prefix = scope
197
230
  ? `${ADAPTER_PREFIX}${scope.charAt(0).toUpperCase()}${scope.slice(1)}`
198
231
  : ADAPTER_PREFIX;
199
- const cap = (s: string): string =>
200
- s.charAt(0).toUpperCase() + s.slice(1);
232
+ const cap = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);
201
233
  return Object.fromEntries(
202
- Object.entries(threadOps).map(([k, v]) => [`${prefix}${cap(k)}`, v]),
234
+ Object.entries(threadOps).map(([k, v]) => [`${prefix}${cap(k)}`, v])
203
235
  ) as AnthropicThreadOps<S>;
204
236
  }
205
237
 
206
238
  const makeInvoker = (
207
239
  model: string,
208
- maxTokens?: number,
240
+ maxTokens?: number
209
241
  ): ModelInvoker<Anthropic.Messages.Message> => {
210
242
  const invokerConfig: AnthropicModelInvokerConfig = {
211
243
  redis,
@@ -225,7 +257,7 @@ export function createAnthropicAdapter(
225
257
  : ((() => {
226
258
  throw new Error(
227
259
  "No default model provided to createAnthropicAdapter. " +
228
- "Either pass `model` in the config or use `createModelInvoker(model)` instead.",
260
+ "Either pass `model` in the config or use `createModelInvoker(model)` instead."
229
261
  );
230
262
  }) as unknown as ModelInvoker<Anthropic.Messages.Message>);
231
263