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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { defineSignal, uuid4, setHandler, defineUpdate, ApplicationFailure, log, condition, defineQuery, proxySinks, workflowInfo, proxyActivities, getExternalWorkflowHandle, startChild } from '@temporalio/workflow';
1
+ import { defineSignal, CancellationScope, isCancellation, uuid4, setHandler, defineUpdate, ApplicationFailure, log, condition, defineQuery, proxySinks, workflowInfo, proxyActivities, getExternalWorkflowHandle, executeChild } from '@temporalio/workflow';
2
2
  import z14, { z } from 'zod';
3
3
  import { randomUUID, randomFillSync } from 'crypto';
4
4
  import { ApplicationFailure as ApplicationFailure$1 } from '@temporalio/common';
@@ -111,7 +111,7 @@ function createToolRouter(options) {
111
111
  });
112
112
  }
113
113
  }
114
- async function processToolCall(toolCall, turn, sandboxId) {
114
+ async function processToolCall(toolCall, turn, sandboxId, onRewindRequested) {
115
115
  const startTime = Date.now();
116
116
  const tool = toolMap.get(toolCall.name);
117
117
  const preResult = await runPreHooks(toolCall, tool, turn);
@@ -126,7 +126,7 @@ function createToolRouter(options) {
126
126
  reason: "Skipped by PreToolUse hook"
127
127
  })
128
128
  });
129
- return null;
129
+ return { kind: "skipped" };
130
130
  }
131
131
  const effectiveArgs = preResult.args;
132
132
  log.debug("tool call dispatched", {
@@ -138,6 +138,7 @@ function createToolRouter(options) {
138
138
  let content;
139
139
  let resultAppended = false;
140
140
  let metadata;
141
+ let rewindRequested = false;
141
142
  try {
142
143
  if (tool) {
143
144
  const routerContext = {
@@ -155,11 +156,15 @@ function createToolRouter(options) {
155
156
  content = response.toolResponse;
156
157
  resultAppended = response.resultAppended === true;
157
158
  metadata = response.metadata;
159
+ rewindRequested = response.rewind === true;
158
160
  } else {
159
161
  result = { error: `Unknown tool: ${toolCall.name}` };
160
162
  content = JSON.stringify(result, null, 2);
161
163
  }
162
164
  } catch (error) {
165
+ if (isCancellation(error)) {
166
+ throw error;
167
+ }
163
168
  log.warn("tool call failed", {
164
169
  toolName: toolCall.name,
165
170
  toolCallId: toolCall.id,
@@ -177,6 +182,15 @@ function createToolRouter(options) {
177
182
  result = recovery.result;
178
183
  content = recovery.content;
179
184
  }
185
+ if (rewindRequested) {
186
+ const signal = {
187
+ toolCallId: toolCall.id,
188
+ toolName: toolCall.name
189
+ };
190
+ log.info("tool requested rewind", { ...signal });
191
+ onRewindRequested?.(signal);
192
+ return { kind: "rewind", signal };
193
+ }
180
194
  if (!resultAppended) {
181
195
  const config = {
182
196
  threadId: options.threadId,
@@ -213,7 +227,7 @@ function createToolRouter(options) {
213
227
  turn,
214
228
  durationMs
215
229
  );
216
- return toolResult;
230
+ return { kind: "result", value: toolResult };
217
231
  }
218
232
  return {
219
233
  hasTools() {
@@ -248,27 +262,59 @@ function createToolRouter(options) {
248
262
  }));
249
263
  },
250
264
  async processToolCalls(toolCalls, context) {
265
+ const attachRewind = (arr, rewind) => {
266
+ if (rewind) {
267
+ arr.rewind = rewind;
268
+ }
269
+ return arr;
270
+ };
251
271
  if (toolCalls.length === 0) {
252
- return [];
272
+ return attachRewind([], void 0);
253
273
  }
254
274
  const turn = context?.turn ?? 0;
255
275
  const sandboxId = context?.sandboxId;
276
+ let rewindSignal;
256
277
  if (options.parallel) {
257
- const results2 = await Promise.all(
258
- toolCalls.map((tc) => processToolCall(tc, turn, sandboxId))
259
- );
260
- return results2.filter(
261
- (r) => r !== null
278
+ const scope = new CancellationScope({ cancellable: true });
279
+ const onRewindRequested = (signal) => {
280
+ if (!rewindSignal) {
281
+ rewindSignal = signal;
282
+ scope.cancel();
283
+ }
284
+ };
285
+ const outcomes = await scope.run(
286
+ async () => Promise.allSettled(
287
+ toolCalls.map(
288
+ (tc) => processToolCall(tc, turn, sandboxId, onRewindRequested)
289
+ )
290
+ )
262
291
  );
292
+ const results2 = [];
293
+ for (const outcome of outcomes) {
294
+ if (outcome.status === "rejected") {
295
+ if (isCancellation(outcome.reason)) {
296
+ continue;
297
+ }
298
+ throw outcome.reason;
299
+ }
300
+ if (outcome.value.kind === "result") {
301
+ results2.push(outcome.value.value);
302
+ }
303
+ }
304
+ return attachRewind(results2, rewindSignal);
263
305
  }
264
306
  const results = [];
265
307
  for (const toolCall of toolCalls) {
266
- const result = await processToolCall(toolCall, turn, sandboxId);
267
- if (result !== null) {
268
- results.push(result);
308
+ const outcome = await processToolCall(toolCall, turn, sandboxId);
309
+ if (outcome.kind === "rewind") {
310
+ rewindSignal = outcome.signal;
311
+ break;
312
+ }
313
+ if (outcome.kind === "result") {
314
+ results.push(outcome.value);
269
315
  }
270
316
  }
271
- return results;
317
+ return attachRewind(results, rewindSignal);
272
318
  },
273
319
  async processToolCallsByName(toolCalls, toolName, handler, context) {
274
320
  const matchingCalls = toolCalls.filter((tc) => tc.name === toolName);
@@ -389,9 +435,7 @@ function createSubagentTool(subagents) {
389
435
  schema
390
436
  };
391
437
  }
392
- var childResultSignal = defineSignal("childResult");
393
438
  var childSandboxReadySignal = defineSignal("childSandboxReady");
394
- var destroySandboxSignal = defineSignal("destroySandbox");
395
439
 
396
440
  // src/lib/subagent/handler.ts
397
441
  function resolveSandboxConfig(config) {
@@ -415,25 +459,27 @@ function resolveSandboxConfig(config) {
415
459
  }
416
460
  function createSubagentHandler(subagents) {
417
461
  const { taskQueue: parentTaskQueue } = workflowInfo();
418
- const childResults = /* @__PURE__ */ new Map();
462
+ const agentSandboxOps = /* @__PURE__ */ new Map();
463
+ for (const cfg of subagents) {
464
+ if (cfg.sandbox && cfg.sandbox !== "none") {
465
+ agentSandboxOps.set(cfg.agentName, cfg.sandbox.proxy(cfg.agentName));
466
+ }
467
+ }
419
468
  const pendingDestroys = /* @__PURE__ */ new Map();
420
469
  const threadSandboxes = /* @__PURE__ */ new Map();
421
470
  const persistentSandboxes = /* @__PURE__ */ new Map();
422
471
  const persistentSandboxCreating = /* @__PURE__ */ new Set();
423
472
  const lazyCreatorAgent = /* @__PURE__ */ new Map();
424
- setHandler(childResultSignal, ({ childWorkflowId, result }) => {
425
- childResults.set(childWorkflowId, result);
426
- });
427
- setHandler(
428
- childSandboxReadySignal,
429
- ({ childWorkflowId, sandboxId }) => {
430
- const agentName = lazyCreatorAgent.get(childWorkflowId);
431
- if (agentName && !persistentSandboxes.has(agentName)) {
432
- persistentSandboxes.set(agentName, sandboxId);
433
- lazyCreatorAgent.delete(childWorkflowId);
434
- }
473
+ const threadSnapshots = /* @__PURE__ */ new Map();
474
+ const persistentBaseSnapshot = /* @__PURE__ */ new Map();
475
+ const persistentBaseSnapshotCreating = /* @__PURE__ */ new Set();
476
+ setHandler(childSandboxReadySignal, ({ childWorkflowId, sandboxId }) => {
477
+ const agentName = lazyCreatorAgent.get(childWorkflowId);
478
+ if (agentName && !persistentSandboxes.has(agentName)) {
479
+ persistentSandboxes.set(agentName, sandboxId);
480
+ lazyCreatorAgent.delete(childWorkflowId);
435
481
  }
436
- );
482
+ });
437
483
  const handler = async (args, context) => {
438
484
  const config = subagents.find((s) => s.agentName === args.subagent);
439
485
  if (!config) {
@@ -444,6 +490,12 @@ function createSubagentHandler(subagents) {
444
490
  const childWorkflowId = `${args.subagent}-${getShortId()}`;
445
491
  const { sandboxId: parentSandboxId } = context;
446
492
  const sandboxCfg = resolveSandboxConfig(config.sandbox);
493
+ if (sandboxCfg.source !== "none" && !agentSandboxOps.has(config.agentName)) {
494
+ throw ApplicationFailure.create({
495
+ message: `Subagent "${config.agentName}" uses a sandbox but no \`sandbox.proxy\` is configured on its SubagentConfig`,
496
+ nonRetryable: true
497
+ });
498
+ }
447
499
  if (sandboxCfg.source === "inherit" && !parentSandboxId) {
448
500
  throw new Error(
449
501
  `Subagent "${config.agentName}" is configured with sandbox: "inherit" but the parent has no sandbox`
@@ -462,12 +514,39 @@ function createSubagentHandler(subagents) {
462
514
  let sandbox;
463
515
  let sandboxShutdownOverride;
464
516
  let isLazyCreator = false;
517
+ let isSnapshotBaseCreator = false;
465
518
  if (sandboxCfg.source === "inherit" && parentSandboxId) {
466
519
  if (sandboxCfg.continuation === "fork") {
467
520
  sandbox = { mode: "fork", sandboxId: parentSandboxId };
521
+ } else if (sandboxCfg.continuation === "snapshot") {
522
+ throw new Error(
523
+ `Subagent "${config.agentName}" has sandbox source "inherit" with continuation "snapshot" \u2014 snapshot continuation is only supported for source "own"`
524
+ );
468
525
  } else {
469
526
  sandbox = { mode: "inherit", sandboxId: parentSandboxId };
470
527
  }
528
+ } else if (sandboxCfg.source === "own" && sandboxCfg.continuation === "snapshot") {
529
+ const isLazy = sandboxCfg.init === "once";
530
+ let baseSnap;
531
+ if (continuationThreadId) {
532
+ baseSnap = threadSnapshots.get(continuationThreadId)?.snapshot;
533
+ }
534
+ if (!baseSnap && isLazy) {
535
+ baseSnap = persistentBaseSnapshot.get(config.agentName);
536
+ if (!baseSnap) {
537
+ if (persistentBaseSnapshotCreating.has(config.agentName)) {
538
+ await condition(() => persistentBaseSnapshot.has(config.agentName));
539
+ baseSnap = persistentBaseSnapshot.get(config.agentName);
540
+ } else {
541
+ persistentBaseSnapshotCreating.add(config.agentName);
542
+ isSnapshotBaseCreator = true;
543
+ }
544
+ }
545
+ }
546
+ if (baseSnap) {
547
+ sandbox = { mode: "from-snapshot", snapshot: baseSnap };
548
+ }
549
+ sandboxShutdownOverride = "snapshot";
471
550
  } else if (sandboxCfg.source === "own") {
472
551
  const isLazy = sandboxCfg.init === "once";
473
552
  let baseSandboxId;
@@ -518,31 +597,8 @@ function createSubagentHandler(subagents) {
518
597
  threadMode,
519
598
  sandboxSource: sandboxCfg.source
520
599
  });
521
- const childHandle = await startChild(config.workflow, childOpts);
600
+ const childResult = await executeChild(config.workflow, childOpts);
522
601
  const effectiveShutdown = sandboxShutdownOverride ?? sandboxCfg.shutdown ?? "destroy";
523
- if (effectiveShutdown === "pause-until-parent-close" || effectiveShutdown === "keep-until-parent-close") {
524
- const key = isLazyCreator ? `persistent:${config.agentName}` : childWorkflowId;
525
- pendingDestroys.set(key, childHandle);
526
- }
527
- await Promise.race([
528
- condition(() => childResults.has(childWorkflowId)),
529
- childHandle.result()
530
- ]);
531
- if (!childResults.has(childWorkflowId)) {
532
- await condition(() => childResults.has(childWorkflowId));
533
- }
534
- const childResult = childResults.get(childWorkflowId);
535
- childResults.delete(childWorkflowId);
536
- if (!childResult) {
537
- log.warn("subagent returned no result", {
538
- subagent: config.agentName,
539
- childWorkflowId
540
- });
541
- return {
542
- toolResponse: "Subagent workflow did not signal a result",
543
- data: null
544
- };
545
- }
546
602
  log.info("subagent completed", {
547
603
  subagent: config.agentName,
548
604
  childWorkflowId,
@@ -554,19 +610,42 @@ function createSubagentHandler(subagents) {
554
610
  usage,
555
611
  threadId: childThreadId,
556
612
  sandboxId: childSandboxId,
613
+ snapshot: childSnapshot,
614
+ baseSnapshot: childBaseSnapshot,
557
615
  metadata
558
616
  } = childResult;
559
617
  if (childSandboxId) {
560
- if (sandboxCfg.source === "own" && sandboxCfg.init === "once" && !persistentSandboxes.has(config.agentName)) {
618
+ if (sandboxCfg.source === "own" && sandboxCfg.init === "once" && sandboxCfg.continuation !== "snapshot" && !persistentSandboxes.has(config.agentName)) {
561
619
  persistentSandboxes.set(config.agentName, childSandboxId);
562
- } else if (allowsContinuation && childThreadId) {
620
+ } else if (allowsContinuation && childThreadId && sandboxCfg.source === "own" && sandboxCfg.continuation !== "snapshot") {
563
621
  threadSandboxes.set(childThreadId, childSandboxId);
564
622
  }
565
623
  }
624
+ if (childSandboxId && (effectiveShutdown === "pause-until-parent-close" || effectiveShutdown === "keep-until-parent-close")) {
625
+ const key = isLazyCreator ? `persistent:${config.agentName}` : childWorkflowId;
626
+ pendingDestroys.set(key, {
627
+ agentName: config.agentName,
628
+ sandboxId: childSandboxId
629
+ });
630
+ }
631
+ if (sandboxCfg.source === "own" && sandboxCfg.continuation === "snapshot") {
632
+ if (childSnapshot && childThreadId) {
633
+ threadSnapshots.set(childThreadId, {
634
+ agentName: config.agentName,
635
+ snapshot: childSnapshot
636
+ });
637
+ }
638
+ if (isSnapshotBaseCreator && childBaseSnapshot && !persistentBaseSnapshot.has(config.agentName)) {
639
+ persistentBaseSnapshot.set(config.agentName, childBaseSnapshot);
640
+ }
641
+ }
566
642
  if (isLazyCreator) {
567
643
  persistentSandboxCreating.delete(config.agentName);
568
644
  lazyCreatorAgent.delete(childWorkflowId);
569
645
  }
646
+ if (isSnapshotBaseCreator) {
647
+ persistentBaseSnapshotCreating.delete(config.agentName);
648
+ }
570
649
  if (!toolResponse) {
571
650
  return {
572
651
  toolResponse: "Subagent workflow returned no response",
@@ -602,22 +681,60 @@ function createSubagentHandler(subagents) {
602
681
  };
603
682
  };
604
683
  const destroySubagentSandboxes = async () => {
605
- const handles = [...pendingDestroys.values()];
684
+ const entries = [...pendingDestroys.values()];
606
685
  pendingDestroys.clear();
607
686
  await Promise.all(
608
- handles.map(async (handle) => {
687
+ entries.map(async ({ agentName, sandboxId }) => {
688
+ const ops = agentSandboxOps.get(agentName);
689
+ if (!ops) {
690
+ log.warn(
691
+ "Skipping sandbox destroy \u2014 no sandbox.proxy registered for agent",
692
+ { agentName, sandboxId }
693
+ );
694
+ return;
695
+ }
696
+ try {
697
+ await ops.destroySandbox(sandboxId);
698
+ } catch (err) {
699
+ log.warn("Failed to destroy subagent sandbox", {
700
+ agentName,
701
+ sandboxId,
702
+ error: err
703
+ });
704
+ }
705
+ })
706
+ );
707
+ };
708
+ const cleanupSubagentSnapshots = async () => {
709
+ const tagged = [];
710
+ for (const entry of threadSnapshots.values()) tagged.push(entry);
711
+ for (const [agentName, snapshot] of persistentBaseSnapshot.entries()) {
712
+ tagged.push({ agentName, snapshot });
713
+ }
714
+ threadSnapshots.clear();
715
+ persistentBaseSnapshot.clear();
716
+ await Promise.all(
717
+ tagged.map(async ({ agentName, snapshot }) => {
718
+ const ops = agentSandboxOps.get(agentName);
719
+ if (!ops) {
720
+ log.warn(
721
+ "Skipping snapshot delete \u2014 no sandbox.proxy registered for agent",
722
+ { agentName }
723
+ );
724
+ return;
725
+ }
609
726
  try {
610
- await handle.signal(destroySandboxSignal);
611
- await handle.result();
727
+ await ops.deleteSandboxSnapshot(snapshot);
612
728
  } catch (err) {
613
- log.warn("Failed to signal destroySandbox to child workflow", {
729
+ log.warn("Failed to delete subagent snapshot", {
730
+ agentName,
614
731
  error: err
615
732
  });
616
733
  }
617
734
  })
618
735
  );
619
736
  };
620
- return { handler, destroySubagentSandboxes };
737
+ return { handler, destroySubagentSandboxes, cleanupSubagentSnapshots };
621
738
  }
622
739
 
623
740
  // src/lib/subagent/register.ts
@@ -631,7 +748,7 @@ function buildSubagentRegistration(subagents) {
631
748
  if (s.hooks) subagentHooksMap.set(s.agentName, s.hooks);
632
749
  }
633
750
  const resolveSubagentName = (args) => args.subagent;
634
- const { handler, destroySubagentSandboxes } = createSubagentHandler(subagents);
751
+ const { handler, destroySubagentSandboxes, cleanupSubagentSnapshots } = createSubagentHandler(subagents);
635
752
  const registration = {
636
753
  name: SUBAGENT_TOOL_NAME,
637
754
  enabled: () => getEnabled().length > 0,
@@ -655,7 +772,7 @@ function buildSubagentRegistration(subagents) {
655
772
  }
656
773
  }
657
774
  };
658
- return { registration, destroySubagentSandboxes };
775
+ return { registration, destroySubagentSandboxes, cleanupSubagentSnapshots };
659
776
  }
660
777
  var READ_SKILL_TOOL_NAME = "ReadSkill";
661
778
  function buildReadSkillDescription(skills) {
@@ -728,9 +845,7 @@ function validateSkillNames(skills) {
728
845
  const names = skills.map((s) => s.name);
729
846
  const dupes = names.filter((n, i) => names.indexOf(n) !== i);
730
847
  if (dupes.length > 0) {
731
- throw new Error(
732
- `Duplicate skill names: ${[...new Set(dupes)].join(", ")}`
733
- );
848
+ throw new Error(`Duplicate skill names: ${[...new Set(dupes)].join(", ")}`);
734
849
  }
735
850
  }
736
851
  function buildSkillRegistration(skills) {
@@ -796,15 +911,18 @@ async function createSession({
796
911
  initializeThread,
797
912
  appendSystemMessage,
798
913
  appendAgentMessage,
799
- forkThread
914
+ forkThread,
915
+ truncateThread
800
916
  } = threadOps;
801
917
  const plugins = [];
802
918
  let destroySubagentSandboxes;
919
+ let cleanupSubagentSnapshots;
803
920
  if (subagents) {
804
921
  const result = buildSubagentRegistration(subagents);
805
922
  if (result) {
806
923
  plugins.push(result.registration);
807
924
  destroySubagentSandboxes = result.destroySubagentSandboxes;
925
+ cleanupSubagentSnapshots = result.cleanupSubagentSnapshots;
808
926
  }
809
927
  }
810
928
  if (skills) {
@@ -857,6 +975,9 @@ async function createSession({
857
975
  const sandboxMode = sandboxInit?.mode;
858
976
  let sandboxId;
859
977
  let sandboxOwned = false;
978
+ let baseSnapshot;
979
+ let exitSnapshot;
980
+ let freshlyCreated = false;
860
981
  if (sandboxMode === "inherit") {
861
982
  const inheritInit = sandboxInit;
862
983
  sandboxId = inheritInit.sandboxId;
@@ -885,8 +1006,23 @@ async function createSession({
885
1006
  nonRetryable: true
886
1007
  });
887
1008
  }
1009
+ const forkInit = sandboxInit;
888
1010
  sandboxId = await sandboxOps.forkSandbox(
889
- sandboxInit.sandboxId
1011
+ forkInit.sandboxId,
1012
+ forkInit.options
1013
+ );
1014
+ sandboxOwned = true;
1015
+ } else if (sandboxMode === "from-snapshot") {
1016
+ if (!sandboxOps) {
1017
+ throw ApplicationFailure.create({
1018
+ message: "No sandboxOps provided \u2014 cannot restore sandbox",
1019
+ nonRetryable: true
1020
+ });
1021
+ }
1022
+ const restoreInit = sandboxInit;
1023
+ sandboxId = await sandboxOps.restoreSandbox(
1024
+ restoreInit.snapshot,
1025
+ restoreInit.options
890
1026
  );
891
1027
  sandboxOwned = true;
892
1028
  } else if (sandboxOps) {
@@ -897,9 +1033,13 @@ async function createSession({
897
1033
  if (result) {
898
1034
  sandboxId = result.sandboxId;
899
1035
  sandboxOwned = true;
1036
+ freshlyCreated = true;
900
1037
  }
901
1038
  }
902
- if (sandboxId && onSandboxReady) {
1039
+ if (sandboxId && sandboxOwned && freshlyCreated && sandboxShutdown === "snapshot" && sandboxOps) {
1040
+ baseSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
1041
+ }
1042
+ if (sandboxId && sandboxOwned && onSandboxReady) {
903
1043
  onSandboxReady(sandboxId);
904
1044
  }
905
1045
  if (virtualFsConfig) {
@@ -965,18 +1105,25 @@ async function createSession({
965
1105
  threadKey
966
1106
  );
967
1107
  let exitReason = "completed";
1108
+ let finalMessage = null;
968
1109
  try {
969
1110
  while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
970
1111
  stateManager.incrementTurns();
971
1112
  const currentTurn = stateManager.getTurns();
972
1113
  log.debug("turn started", { agentName, threadId, turn: currentTurn });
973
1114
  stateManager.setTools(toolRouter.getToolDefinitions());
974
- const { message, rawToolCalls, usage } = await runAgent({
1115
+ const {
1116
+ message,
1117
+ rawToolCalls,
1118
+ usage,
1119
+ threadLengthAtCall
1120
+ } = await runAgent({
975
1121
  threadId,
976
1122
  threadKey,
977
1123
  agentName,
978
1124
  metadata
979
1125
  });
1126
+ const preAssistantLength = threadLengthAtCall;
980
1127
  await appendAgentMessage(threadId, uuid4(), message, threadKey);
981
1128
  if (usage) {
982
1129
  stateManager.updateUsage(usage);
@@ -991,21 +1138,8 @@ async function createSession({
991
1138
  if (!toolRouter.hasTools() || rawToolCalls.length === 0) {
992
1139
  stateManager.complete();
993
1140
  exitReason = "completed";
994
- log.info("session ended", {
995
- agentName,
996
- threadId,
997
- exitReason,
998
- turns: currentTurn,
999
- durationMs: Date.now() - sessionStartMs,
1000
- usage: stateManager.getTotalUsage()
1001
- });
1002
- return {
1003
- threadId,
1004
- finalMessage: message,
1005
- exitReason,
1006
- usage: stateManager.getTotalUsage(),
1007
- sandboxId
1008
- };
1141
+ finalMessage = message;
1142
+ break;
1009
1143
  }
1010
1144
  const parsedToolCalls = [];
1011
1145
  for (const tc of rawToolCalls) {
@@ -1035,6 +1169,24 @@ async function createSession({
1035
1169
  stateManager.updateUsage(result.usage);
1036
1170
  }
1037
1171
  }
1172
+ const rewind = toolCallResults.rewind;
1173
+ if (rewind) {
1174
+ log.info("rewinding turn", {
1175
+ agentName,
1176
+ threadId,
1177
+ turn: currentTurn,
1178
+ toolCallId: rewind.toolCallId,
1179
+ toolName: rewind.toolName
1180
+ });
1181
+ if (preAssistantLength === void 0) {
1182
+ throw ApplicationFailure.create({
1183
+ message: "Rewind requested but runAgent did not report `threadLengthAtCall`; the adapter must populate it to support rewinds.",
1184
+ nonRetryable: true
1185
+ });
1186
+ }
1187
+ await truncateThread(threadId, preAssistantLength, threadKey);
1188
+ continue;
1189
+ }
1038
1190
  if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
1039
1191
  const conditionMet = await condition(
1040
1192
  () => stateManager.getStatus() === "RUNNING",
@@ -1077,11 +1229,21 @@ async function createSession({
1077
1229
  case "pause-until-parent-close":
1078
1230
  await sandboxOps.pauseSandbox(sandboxId);
1079
1231
  break;
1232
+ case "keep":
1233
+ case "keep-until-parent-close":
1234
+ break;
1235
+ case "snapshot":
1236
+ exitSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
1237
+ await sandboxOps.destroySandbox(sandboxId);
1238
+ break;
1080
1239
  }
1081
1240
  }
1082
1241
  if (destroySubagentSandboxes) {
1083
1242
  await destroySubagentSandboxes();
1084
1243
  }
1244
+ if (cleanupSubagentSnapshots) {
1245
+ await cleanupSubagentSnapshots();
1246
+ }
1085
1247
  }
1086
1248
  log.info("session ended", {
1087
1249
  agentName,
@@ -1089,14 +1251,18 @@ async function createSession({
1089
1251
  exitReason,
1090
1252
  turns: stateManager.getTurns(),
1091
1253
  durationMs: Date.now() - sessionStartMs,
1092
- usage: stateManager.getTotalUsage()
1254
+ usage: stateManager.getTotalUsage(),
1255
+ ...baseSnapshot && { hasBaseSnapshot: true },
1256
+ ...exitSnapshot && { hasExitSnapshot: true }
1093
1257
  });
1094
1258
  return {
1095
1259
  threadId,
1096
- finalMessage: null,
1260
+ finalMessage,
1097
1261
  exitReason,
1098
1262
  usage: stateManager.getTotalUsage(),
1099
- sandboxId
1263
+ sandboxId,
1264
+ ...baseSnapshot && { baseSnapshot },
1265
+ ...exitSnapshot && { snapshot: exitSnapshot }
1100
1266
  };
1101
1267
  }
1102
1268
  };
@@ -1385,44 +1551,16 @@ function defineSubagentWorkflow(config, fn) {
1385
1551
  ...workflowInput.thread && { thread: workflowInput.thread },
1386
1552
  ...workflowInput.sandbox && { sandbox: workflowInput.sandbox },
1387
1553
  onSandboxReady: (sandboxId) => {
1388
- void parentHandle.signal(childSandboxReadySignal, {
1389
- childWorkflowId: workflowInfo().workflowId,
1390
- sandboxId
1391
- });
1554
+ const isReuse = workflowInput.sandbox?.mode === "continue";
1555
+ if (!isReuse) {
1556
+ void parentHandle.signal(childSandboxReadySignal, {
1557
+ childWorkflowId: workflowInfo().workflowId,
1558
+ sandboxId
1559
+ });
1560
+ }
1392
1561
  }
1393
1562
  };
1394
- const { destroySandbox, ...result } = await fn(
1395
- prompt,
1396
- sessionInput,
1397
- context ?? {}
1398
- );
1399
- if (effectiveShutdown === "pause-until-parent-close" || effectiveShutdown === "keep-until-parent-close") {
1400
- if (!destroySandbox) {
1401
- throw ApplicationFailure.create({
1402
- message: `Subagent "${config.name}" has sandboxShutdown="${effectiveShutdown}" but fn did not return a destroySandbox callback`,
1403
- nonRetryable: true
1404
- });
1405
- }
1406
- if (!result.sandboxId) {
1407
- throw ApplicationFailure.create({
1408
- message: `Subagent "${config.name}" has sandboxShutdown="${effectiveShutdown}" but fn did not return a sandboxId`,
1409
- nonRetryable: true
1410
- });
1411
- }
1412
- }
1413
- await parentHandle.signal(childResultSignal, {
1414
- childWorkflowId: workflowInfo().workflowId,
1415
- result
1416
- });
1417
- if (destroySandbox) {
1418
- let destroyRequested = false;
1419
- setHandler(destroySandboxSignal, () => {
1420
- destroyRequested = true;
1421
- });
1422
- await condition(() => destroyRequested);
1423
- await destroySandbox();
1424
- }
1425
- return result;
1563
+ return fn(prompt, sessionInput, context ?? {});
1426
1564
  };
1427
1565
  Object.defineProperty(workflow, "name", { value: config.name });
1428
1566
  return Object.assign(workflow, {
@@ -1532,9 +1670,7 @@ function applyVirtualTreeMutations(stateManager, mutations) {
1532
1670
  tree = tree.filter((e) => e.path !== m.path);
1533
1671
  break;
1534
1672
  case "update":
1535
- tree = tree.map(
1536
- (e) => e.path === m.path ? { ...e, ...m.entry } : e
1537
- );
1673
+ tree = tree.map((e) => e.path === m.path ? { ...e, ...m.entry } : e);
1538
1674
  break;
1539
1675
  }
1540
1676
  }
@@ -1593,7 +1729,9 @@ function formatVirtualFileTree(entries, opts = {}) {
1593
1729
  // src/lib/virtual-fs/queries.ts
1594
1730
  function hasFileWithMimeType(stateManager, pattern) {
1595
1731
  const tree = stateManager.get("fileTree");
1596
- const matchers = (Array.isArray(pattern) ? pattern : [pattern]).map(buildMatcher);
1732
+ const matchers = (Array.isArray(pattern) ? pattern : [pattern]).map(
1733
+ buildMatcher
1734
+ );
1597
1735
  return tree.some((entry) => {
1598
1736
  const meta = entry.metadata;
1599
1737
  const mime = meta?.mimeType;
@@ -1654,7 +1792,9 @@ function proxyVirtualFsOps(scope, options) {
1654
1792
  // src/lib/skills/parse.ts
1655
1793
  function parseSkillFile(raw) {
1656
1794
  const trimmed = raw.replace(/^\uFEFF/, "");
1657
- const match = trimmed.match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?([\s\S]*)$/);
1795
+ const match = trimmed.match(
1796
+ /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?([\s\S]*)$/
1797
+ );
1658
1798
  if (!match) {
1659
1799
  throw new Error(
1660
1800
  "SKILL.md must start with YAML frontmatter delimited by ---"
@@ -1926,7 +2066,9 @@ function createTaskGetHandler(stateManager) {
1926
2066
  const task = stateManager.getTask(args.taskId) ?? null;
1927
2067
  if (!task) {
1928
2068
  return {
1929
- toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
2069
+ toolResponse: JSON.stringify({
2070
+ error: `Task not found: ${args.taskId}`
2071
+ }),
1930
2072
  data: null
1931
2073
  };
1932
2074
  }
@@ -1969,7 +2111,9 @@ function createTaskUpdateHandler(stateManager) {
1969
2111
  const task = stateManager.getTask(args.taskId);
1970
2112
  if (!task) {
1971
2113
  return {
1972
- toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
2114
+ toolResponse: JSON.stringify({
2115
+ error: `Task not found: ${args.taskId}`
2116
+ }),
1973
2117
  data: null
1974
2118
  };
1975
2119
  }
@@ -2079,6 +2223,8 @@ var FileSystemSkillProvider = class {
2079
2223
  this.fs = fs;
2080
2224
  this.baseDir = baseDir;
2081
2225
  }
2226
+ fs;
2227
+ baseDir;
2082
2228
  async listSkills() {
2083
2229
  const dirs = await this.discoverSkillDirs();
2084
2230
  const skills = [];
@@ -2094,9 +2240,7 @@ var FileSystemSkillProvider = class {
2094
2240
  return skills;
2095
2241
  }
2096
2242
  async getSkill(name) {
2097
- const raw = await this.fs.readFile(
2098
- join(this.baseDir, name, "SKILL.md")
2099
- );
2243
+ const raw = await this.fs.readFile(join(this.baseDir, name, "SKILL.md"));
2100
2244
  const { frontmatter, body } = parseSkillFile(raw);
2101
2245
  if (frontmatter.name !== name) {
2102
2246
  throw new Error(
@@ -2105,7 +2249,10 @@ var FileSystemSkillProvider = class {
2105
2249
  }
2106
2250
  const location = join(this.baseDir, name);
2107
2251
  const resourcePaths = await this.discoverResources(name);
2108
- const resourceContents = await this.readResourceContents(location, resourcePaths);
2252
+ const resourceContents = await this.readResourceContents(
2253
+ location,
2254
+ resourcePaths
2255
+ );
2109
2256
  return {
2110
2257
  ...frontmatter,
2111
2258
  instructions: body,
@@ -2125,7 +2272,10 @@ var FileSystemSkillProvider = class {
2125
2272
  const { frontmatter, body } = parseSkillFile(raw);
2126
2273
  const location = join(this.baseDir, dir);
2127
2274
  const resourcePaths = await this.discoverResources(dir);
2128
- const resourceContents = await this.readResourceContents(location, resourcePaths);
2275
+ const resourceContents = await this.readResourceContents(
2276
+ location,
2277
+ resourcePaths
2278
+ );
2129
2279
  skills.push({
2130
2280
  ...frontmatter,
2131
2281
  instructions: body,
@@ -2258,6 +2408,20 @@ function createThreadManager(config) {
2258
2408
  },
2259
2409
  async delete() {
2260
2410
  await redis.del(redisKey, metaKey);
2411
+ },
2412
+ async length() {
2413
+ await assertThreadExists();
2414
+ return redis.llen(redisKey);
2415
+ },
2416
+ async truncate(length) {
2417
+ await assertThreadExists();
2418
+ if (length <= 0) {
2419
+ await redis.del(redisKey);
2420
+ await redis.expire(metaKey, THREAD_TTL_SECONDS);
2421
+ } else {
2422
+ await redis.ltrim(redisKey, 0, length - 1);
2423
+ await redis.expire(redisKey, THREAD_TTL_SECONDS);
2424
+ }
2261
2425
  }
2262
2426
  };
2263
2427
  }
@@ -2299,6 +2463,7 @@ var SandboxManager = class {
2299
2463
  this.provider = provider;
2300
2464
  this.hooks = options?.hooks ?? {};
2301
2465
  }
2466
+ provider;
2302
2467
  hooks;
2303
2468
  async create(options, ctx) {
2304
2469
  let providerOptions = options;
@@ -2327,7 +2492,7 @@ var SandboxManager = class {
2327
2492
  }
2328
2493
  const { sandbox } = await this.provider.create(providerOptions);
2329
2494
  if (this.hooks.onPostCreate) {
2330
- await this.hooks.onPostCreate(sandbox.id);
2495
+ await this.hooks.onPostCreate(sandbox, ctx ?? {});
2331
2496
  }
2332
2497
  return { sandboxId: sandbox.id };
2333
2498
  }
@@ -2343,15 +2508,18 @@ var SandboxManager = class {
2343
2508
  async resume(id) {
2344
2509
  await this.provider.resume(id);
2345
2510
  }
2346
- async snapshot(id) {
2347
- return this.provider.snapshot(id);
2511
+ async snapshot(id, options) {
2512
+ return this.provider.snapshot(id, options);
2348
2513
  }
2349
- async restore(snapshot) {
2350
- const sandbox = await this.provider.restore(snapshot);
2514
+ async restore(snapshot, options) {
2515
+ const sandbox = await this.provider.restore(snapshot, options);
2351
2516
  return sandbox.id;
2352
2517
  }
2353
- async fork(sandboxId) {
2354
- const sandbox = await this.provider.fork(sandboxId);
2518
+ async deleteSnapshot(snapshot) {
2519
+ await this.provider.deleteSnapshot(snapshot);
2520
+ }
2521
+ async fork(sandboxId, options) {
2522
+ const sandbox = await this.provider.fork(sandboxId, options);
2355
2523
  return sandbox.id;
2356
2524
  }
2357
2525
  /**
@@ -2389,11 +2557,17 @@ var SandboxManager = class {
2389
2557
  resumeSandbox: async (sandboxId) => {
2390
2558
  await this.resume(sandboxId);
2391
2559
  },
2392
- snapshotSandbox: async (sandboxId) => {
2393
- return this.snapshot(sandboxId);
2560
+ snapshotSandbox: async (sandboxId, options) => {
2561
+ return this.snapshot(sandboxId, options);
2562
+ },
2563
+ restoreSandbox: async (snapshot, options) => {
2564
+ return this.restore(snapshot, options);
2565
+ },
2566
+ deleteSandboxSnapshot: async (snapshot) => {
2567
+ await this.deleteSnapshot(snapshot);
2394
2568
  },
2395
- forkSandbox: async (sandboxId) => {
2396
- return this.fork(sandboxId);
2569
+ forkSandbox: async (sandboxId, options) => {
2570
+ return this.fork(sandboxId, options);
2397
2571
  }
2398
2572
  };
2399
2573
  const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
@@ -2507,6 +2681,8 @@ var VirtualFileSystem = class {
2507
2681
  ]) : []
2508
2682
  );
2509
2683
  }
2684
+ resolver;
2685
+ ctx;
2510
2686
  workspaceBase;
2511
2687
  entries;
2512
2688
  directories;