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.
- package/README.md +146 -92
- package/dist/{activities-BVI2lTwr.d.ts → activities-BKhMtKDd.d.ts} +4 -2
- package/dist/{activities-hd4aNnZE.d.cts → activities-CDcwkRZs.d.cts} +4 -2
- package/dist/adapters/sandbox/bedrock/index.cjs +17 -14
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +7 -6
- package/dist/adapters/sandbox/bedrock/index.d.ts +7 -6
- package/dist/adapters/sandbox/bedrock/index.js +17 -14
- package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.cjs +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
- package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
- package/dist/adapters/sandbox/bedrock/workflow.js +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.js.map +1 -1
- package/dist/adapters/sandbox/daytona/index.cjs +11 -3
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +5 -4
- package/dist/adapters/sandbox/daytona/index.d.ts +5 -4
- package/dist/adapters/sandbox/daytona/index.js +11 -3
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.cjs +2 -0
- package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.js +2 -0
- package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
- package/dist/adapters/sandbox/e2b/index.cjs +73 -12
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +26 -4
- package/dist/adapters/sandbox/e2b/index.d.ts +26 -4
- package/dist/adapters/sandbox/e2b/index.js +73 -12
- package/dist/adapters/sandbox/e2b/index.js.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.cjs +2 -0
- package/dist/adapters/sandbox/e2b/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.js +2 -0
- package/dist/adapters/sandbox/e2b/workflow.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +8 -3
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +5 -4
- package/dist/adapters/sandbox/inmemory/index.d.ts +5 -4
- package/dist/adapters/sandbox/inmemory/index.js +8 -3
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs +2 -0
- package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.js +2 -0
- package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
- package/dist/adapters/thread/anthropic/index.cjs +94 -39
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +5 -5
- package/dist/adapters/thread/anthropic/index.d.ts +5 -5
- package/dist/adapters/thread/anthropic/index.js +94 -39
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +7 -2
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -5
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -5
- package/dist/adapters/thread/anthropic/workflow.js +7 -2
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +77 -28
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -5
- package/dist/adapters/thread/google-genai/index.d.ts +5 -5
- package/dist/adapters/thread/google-genai/index.js +77 -28
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +7 -2
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -5
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -5
- package/dist/adapters/thread/google-genai/workflow.js +7 -2
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +57 -10
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +5 -5
- package/dist/adapters/thread/langchain/index.d.ts +5 -5
- package/dist/adapters/thread/langchain/index.js +57 -10
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +7 -2
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -5
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -5
- package/dist/adapters/thread/langchain/workflow.js +7 -2
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +322 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -14
- package/dist/index.d.ts +20 -14
- package/dist/index.js +323 -147
- package/dist/index.js.map +1 -1
- package/dist/{proxy-BjdFGPTm.d.ts → proxy-CUlKSvZS.d.ts} +1 -1
- package/dist/{proxy-7RnVaPdJ.d.cts → proxy-D_3x7RN4.d.cts} +1 -1
- package/dist/{thread-manager-CbpiGq1L.d.ts → thread-manager-CVu7o2cs.d.ts} +4 -2
- package/dist/{thread-manager-DzXm9eeI.d.cts → thread-manager-HSwyh28L.d.cts} +4 -2
- package/dist/{thread-manager-BBzNgQWH.d.cts → thread-manager-c1gPopAG.d.ts} +4 -2
- package/dist/{thread-manager-DjN5JYul.d.ts → thread-manager-wGi-LqIP.d.cts} +4 -2
- package/dist/{types-Mc_4BCfT.d.cts → types-BH_IRryz.d.ts} +10 -1
- package/dist/{types-yiXmqedU.d.ts → types-BaOw4hKI.d.cts} +10 -1
- package/dist/{types-DQ1l_gXL.d.cts → types-C06FwR96.d.cts} +121 -17
- package/dist/{types-wiGLvxWf.d.ts → types-DAsQ21Rt.d.ts} +1 -1
- package/dist/{types-CADc5V_P.d.ts → types-DNr31FzL.d.ts} +121 -17
- package/dist/{types-CBH54cwr.d.cts → types-lm8tMNJQ.d.cts} +1 -1
- package/dist/{types-DxCpFNv_.d.cts → types-yx0LzPGn.d.cts} +44 -5
- package/dist/{types-DxCpFNv_.d.ts → types-yx0LzPGn.d.ts} +44 -5
- package/dist/{workflow-DhtWRovz.d.cts → workflow-CSCkpwAL.d.ts} +2 -2
- package/dist/{workflow-P2pTSfKu.d.ts → workflow-DuvMZ8Vm.d.cts} +2 -2
- package/dist/workflow.cjs +274 -130
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +3 -3
- package/dist/workflow.d.ts +3 -3
- package/dist/workflow.js +275 -131
- package/dist/workflow.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/sandbox/bedrock/filesystem.ts +6 -12
- package/src/adapters/sandbox/bedrock/index.ts +22 -11
- package/src/adapters/sandbox/bedrock/proxy.ts +2 -0
- package/src/adapters/sandbox/daytona/index.ts +18 -3
- package/src/adapters/sandbox/daytona/proxy.ts +2 -0
- package/src/adapters/sandbox/e2b/filesystem.ts +5 -4
- package/src/adapters/sandbox/e2b/index.ts +87 -14
- package/src/adapters/sandbox/e2b/proxy.ts +2 -0
- package/src/adapters/sandbox/e2b/types.ts +16 -0
- package/src/adapters/sandbox/inmemory/index.ts +17 -3
- package/src/adapters/sandbox/inmemory/proxy.ts +2 -0
- package/src/adapters/thread/anthropic/activities.ts +58 -26
- package/src/adapters/thread/anthropic/model-invoker.ts +18 -7
- package/src/adapters/thread/anthropic/proxy.ts +6 -2
- package/src/adapters/thread/anthropic/thread-manager.test.ts +26 -7
- package/src/adapters/thread/anthropic/thread-manager.ts +63 -46
- package/src/adapters/thread/google-genai/activities.ts +20 -2
- package/src/adapters/thread/google-genai/model-invoker.ts +27 -7
- package/src/adapters/thread/google-genai/proxy.ts +6 -2
- package/src/adapters/thread/google-genai/thread-manager.test.ts +13 -3
- package/src/adapters/thread/google-genai/thread-manager.ts +57 -33
- package/src/adapters/thread/langchain/activities.ts +55 -24
- package/src/adapters/thread/langchain/hooks.test.ts +36 -49
- package/src/adapters/thread/langchain/hooks.ts +18 -5
- package/src/adapters/thread/langchain/model-invoker.ts +5 -4
- package/src/adapters/thread/langchain/proxy.ts +6 -2
- package/src/adapters/thread/langchain/thread-manager.test.ts +5 -1
- package/src/adapters/thread/langchain/thread-manager.ts +23 -9
- package/src/index.ts +4 -1
- package/src/lib/activity.ts +16 -6
- package/src/lib/hooks/types.ts +6 -6
- package/src/lib/lifecycle.ts +18 -3
- package/src/lib/model/proxy.ts +2 -2
- package/src/lib/model/types.ts +10 -0
- package/src/lib/observability/hooks.ts +4 -5
- package/src/lib/observability/index.ts +1 -4
- package/src/lib/sandbox/manager.ts +45 -20
- package/src/lib/sandbox/node-fs.ts +3 -6
- package/src/lib/sandbox/sandbox.test.ts +36 -3
- package/src/lib/sandbox/tree.integration.test.ts +10 -3
- package/src/lib/sandbox/types.ts +60 -6
- package/src/lib/session/session-edge-cases.integration.test.ts +316 -14
- package/src/lib/session/session.integration.test.ts +161 -1
- package/src/lib/session/session.ts +106 -21
- package/src/lib/session/types.ts +25 -5
- package/src/lib/skills/fs-provider.ts +12 -8
- package/src/lib/skills/handler.ts +1 -1
- package/src/lib/skills/parse.ts +3 -1
- package/src/lib/skills/register.ts +1 -3
- package/src/lib/skills/skills.integration.test.ts +25 -15
- package/src/lib/state/manager.integration.test.ts +12 -2
- package/src/lib/subagent/define.ts +1 -1
- package/src/lib/subagent/handler.ts +186 -71
- package/src/lib/subagent/index.ts +1 -5
- package/src/lib/subagent/register.ts +3 -2
- package/src/lib/subagent/signals.ts +1 -10
- package/src/lib/subagent/subagent.integration.test.ts +526 -248
- package/src/lib/subagent/tool.ts +4 -3
- package/src/lib/subagent/types.ts +50 -20
- package/src/lib/subagent/workflow.ts +9 -49
- package/src/lib/thread/id.test.ts +1 -1
- package/src/lib/thread/id.ts +1 -2
- package/src/lib/thread/manager.ts +18 -0
- package/src/lib/thread/proxy.ts +4 -4
- package/src/lib/thread/types.ts +20 -3
- package/src/lib/tool-router/index.ts +3 -5
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +93 -1
- package/src/lib/tool-router/router.integration.test.ts +12 -0
- package/src/lib/tool-router/router.ts +90 -16
- package/src/lib/tool-router/types.ts +45 -4
- package/src/lib/tool-router/with-sandbox.ts +19 -5
- package/src/lib/virtual-fs/filesystem.ts +1 -1
- package/src/lib/virtual-fs/index.ts +5 -1
- package/src/lib/virtual-fs/mutations.ts +2 -4
- package/src/lib/virtual-fs/queries.ts +9 -5
- package/src/lib/virtual-fs/types.ts +4 -1
- package/src/lib/virtual-fs/virtual-fs.test.ts +9 -11
- package/src/lib/workflow.test.ts +7 -4
- package/src/lib/workflow.ts +1 -5
- package/src/tools/ask-user-question/tool.ts +1 -3
- package/src/tools/glob/handler.ts +1 -4
- package/src/tools/task-get/handler.ts +4 -5
- package/src/tools/task-list/handler.ts +1 -4
- package/src/tools/task-update/handler.ts +4 -5
- package/src/workflow.ts +22 -7
- package/tsup.config.ts +9 -6
- package/src/lib/.env +0 -1
- package/src/tools/bash/.env +0 -1
package/dist/index.cjs
CHANGED
|
@@ -117,7 +117,7 @@ function createToolRouter(options) {
|
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
async function processToolCall(toolCall, turn, sandboxId) {
|
|
120
|
+
async function processToolCall(toolCall, turn, sandboxId, onRewindRequested) {
|
|
121
121
|
const startTime = Date.now();
|
|
122
122
|
const tool = toolMap.get(toolCall.name);
|
|
123
123
|
const preResult = await runPreHooks(toolCall, tool, turn);
|
|
@@ -132,7 +132,7 @@ function createToolRouter(options) {
|
|
|
132
132
|
reason: "Skipped by PreToolUse hook"
|
|
133
133
|
})
|
|
134
134
|
});
|
|
135
|
-
return
|
|
135
|
+
return { kind: "skipped" };
|
|
136
136
|
}
|
|
137
137
|
const effectiveArgs = preResult.args;
|
|
138
138
|
workflow.log.debug("tool call dispatched", {
|
|
@@ -144,6 +144,7 @@ function createToolRouter(options) {
|
|
|
144
144
|
let content;
|
|
145
145
|
let resultAppended = false;
|
|
146
146
|
let metadata;
|
|
147
|
+
let rewindRequested = false;
|
|
147
148
|
try {
|
|
148
149
|
if (tool) {
|
|
149
150
|
const routerContext = {
|
|
@@ -161,11 +162,15 @@ function createToolRouter(options) {
|
|
|
161
162
|
content = response.toolResponse;
|
|
162
163
|
resultAppended = response.resultAppended === true;
|
|
163
164
|
metadata = response.metadata;
|
|
165
|
+
rewindRequested = response.rewind === true;
|
|
164
166
|
} else {
|
|
165
167
|
result = { error: `Unknown tool: ${toolCall.name}` };
|
|
166
168
|
content = JSON.stringify(result, null, 2);
|
|
167
169
|
}
|
|
168
170
|
} catch (error) {
|
|
171
|
+
if (workflow.isCancellation(error)) {
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
169
174
|
workflow.log.warn("tool call failed", {
|
|
170
175
|
toolName: toolCall.name,
|
|
171
176
|
toolCallId: toolCall.id,
|
|
@@ -183,6 +188,15 @@ function createToolRouter(options) {
|
|
|
183
188
|
result = recovery.result;
|
|
184
189
|
content = recovery.content;
|
|
185
190
|
}
|
|
191
|
+
if (rewindRequested) {
|
|
192
|
+
const signal = {
|
|
193
|
+
toolCallId: toolCall.id,
|
|
194
|
+
toolName: toolCall.name
|
|
195
|
+
};
|
|
196
|
+
workflow.log.info("tool requested rewind", { ...signal });
|
|
197
|
+
onRewindRequested?.(signal);
|
|
198
|
+
return { kind: "rewind", signal };
|
|
199
|
+
}
|
|
186
200
|
if (!resultAppended) {
|
|
187
201
|
const config = {
|
|
188
202
|
threadId: options.threadId,
|
|
@@ -219,7 +233,7 @@ function createToolRouter(options) {
|
|
|
219
233
|
turn,
|
|
220
234
|
durationMs
|
|
221
235
|
);
|
|
222
|
-
return toolResult;
|
|
236
|
+
return { kind: "result", value: toolResult };
|
|
223
237
|
}
|
|
224
238
|
return {
|
|
225
239
|
hasTools() {
|
|
@@ -254,27 +268,59 @@ function createToolRouter(options) {
|
|
|
254
268
|
}));
|
|
255
269
|
},
|
|
256
270
|
async processToolCalls(toolCalls, context) {
|
|
271
|
+
const attachRewind = (arr, rewind) => {
|
|
272
|
+
if (rewind) {
|
|
273
|
+
arr.rewind = rewind;
|
|
274
|
+
}
|
|
275
|
+
return arr;
|
|
276
|
+
};
|
|
257
277
|
if (toolCalls.length === 0) {
|
|
258
|
-
return [];
|
|
278
|
+
return attachRewind([], void 0);
|
|
259
279
|
}
|
|
260
280
|
const turn = context?.turn ?? 0;
|
|
261
281
|
const sandboxId = context?.sandboxId;
|
|
282
|
+
let rewindSignal;
|
|
262
283
|
if (options.parallel) {
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
284
|
+
const scope = new workflow.CancellationScope({ cancellable: true });
|
|
285
|
+
const onRewindRequested = (signal) => {
|
|
286
|
+
if (!rewindSignal) {
|
|
287
|
+
rewindSignal = signal;
|
|
288
|
+
scope.cancel();
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const outcomes = await scope.run(
|
|
292
|
+
async () => Promise.allSettled(
|
|
293
|
+
toolCalls.map(
|
|
294
|
+
(tc) => processToolCall(tc, turn, sandboxId, onRewindRequested)
|
|
295
|
+
)
|
|
296
|
+
)
|
|
268
297
|
);
|
|
298
|
+
const results2 = [];
|
|
299
|
+
for (const outcome of outcomes) {
|
|
300
|
+
if (outcome.status === "rejected") {
|
|
301
|
+
if (workflow.isCancellation(outcome.reason)) {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
throw outcome.reason;
|
|
305
|
+
}
|
|
306
|
+
if (outcome.value.kind === "result") {
|
|
307
|
+
results2.push(outcome.value.value);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return attachRewind(results2, rewindSignal);
|
|
269
311
|
}
|
|
270
312
|
const results = [];
|
|
271
313
|
for (const toolCall of toolCalls) {
|
|
272
|
-
const
|
|
273
|
-
if (
|
|
274
|
-
|
|
314
|
+
const outcome = await processToolCall(toolCall, turn, sandboxId);
|
|
315
|
+
if (outcome.kind === "rewind") {
|
|
316
|
+
rewindSignal = outcome.signal;
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
if (outcome.kind === "result") {
|
|
320
|
+
results.push(outcome.value);
|
|
275
321
|
}
|
|
276
322
|
}
|
|
277
|
-
return results;
|
|
323
|
+
return attachRewind(results, rewindSignal);
|
|
278
324
|
},
|
|
279
325
|
async processToolCallsByName(toolCalls, toolName, handler, context) {
|
|
280
326
|
const matchingCalls = toolCalls.filter((tc) => tc.name === toolName);
|
|
@@ -395,9 +441,7 @@ function createSubagentTool(subagents) {
|
|
|
395
441
|
schema
|
|
396
442
|
};
|
|
397
443
|
}
|
|
398
|
-
var childResultSignal = workflow.defineSignal("childResult");
|
|
399
444
|
var childSandboxReadySignal = workflow.defineSignal("childSandboxReady");
|
|
400
|
-
var destroySandboxSignal = workflow.defineSignal("destroySandbox");
|
|
401
445
|
|
|
402
446
|
// src/lib/subagent/handler.ts
|
|
403
447
|
function resolveSandboxConfig(config) {
|
|
@@ -421,25 +465,27 @@ function resolveSandboxConfig(config) {
|
|
|
421
465
|
}
|
|
422
466
|
function createSubagentHandler(subagents) {
|
|
423
467
|
const { taskQueue: parentTaskQueue } = workflow.workflowInfo();
|
|
424
|
-
const
|
|
468
|
+
const agentSandboxOps = /* @__PURE__ */ new Map();
|
|
469
|
+
for (const cfg of subagents) {
|
|
470
|
+
if (cfg.sandbox && cfg.sandbox !== "none") {
|
|
471
|
+
agentSandboxOps.set(cfg.agentName, cfg.sandbox.proxy(cfg.agentName));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
425
474
|
const pendingDestroys = /* @__PURE__ */ new Map();
|
|
426
475
|
const threadSandboxes = /* @__PURE__ */ new Map();
|
|
427
476
|
const persistentSandboxes = /* @__PURE__ */ new Map();
|
|
428
477
|
const persistentSandboxCreating = /* @__PURE__ */ new Set();
|
|
429
478
|
const lazyCreatorAgent = /* @__PURE__ */ new Map();
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
workflow.setHandler(
|
|
434
|
-
|
|
435
|
-
(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
persistentSandboxes.set(agentName, sandboxId);
|
|
439
|
-
lazyCreatorAgent.delete(childWorkflowId);
|
|
440
|
-
}
|
|
479
|
+
const threadSnapshots = /* @__PURE__ */ new Map();
|
|
480
|
+
const persistentBaseSnapshot = /* @__PURE__ */ new Map();
|
|
481
|
+
const persistentBaseSnapshotCreating = /* @__PURE__ */ new Set();
|
|
482
|
+
workflow.setHandler(childSandboxReadySignal, ({ childWorkflowId, sandboxId }) => {
|
|
483
|
+
const agentName = lazyCreatorAgent.get(childWorkflowId);
|
|
484
|
+
if (agentName && !persistentSandboxes.has(agentName)) {
|
|
485
|
+
persistentSandboxes.set(agentName, sandboxId);
|
|
486
|
+
lazyCreatorAgent.delete(childWorkflowId);
|
|
441
487
|
}
|
|
442
|
-
);
|
|
488
|
+
});
|
|
443
489
|
const handler = async (args, context) => {
|
|
444
490
|
const config = subagents.find((s) => s.agentName === args.subagent);
|
|
445
491
|
if (!config) {
|
|
@@ -450,6 +496,12 @@ function createSubagentHandler(subagents) {
|
|
|
450
496
|
const childWorkflowId = `${args.subagent}-${getShortId()}`;
|
|
451
497
|
const { sandboxId: parentSandboxId } = context;
|
|
452
498
|
const sandboxCfg = resolveSandboxConfig(config.sandbox);
|
|
499
|
+
if (sandboxCfg.source !== "none" && !agentSandboxOps.has(config.agentName)) {
|
|
500
|
+
throw workflow.ApplicationFailure.create({
|
|
501
|
+
message: `Subagent "${config.agentName}" uses a sandbox but no \`sandbox.proxy\` is configured on its SubagentConfig`,
|
|
502
|
+
nonRetryable: true
|
|
503
|
+
});
|
|
504
|
+
}
|
|
453
505
|
if (sandboxCfg.source === "inherit" && !parentSandboxId) {
|
|
454
506
|
throw new Error(
|
|
455
507
|
`Subagent "${config.agentName}" is configured with sandbox: "inherit" but the parent has no sandbox`
|
|
@@ -468,12 +520,39 @@ function createSubagentHandler(subagents) {
|
|
|
468
520
|
let sandbox;
|
|
469
521
|
let sandboxShutdownOverride;
|
|
470
522
|
let isLazyCreator = false;
|
|
523
|
+
let isSnapshotBaseCreator = false;
|
|
471
524
|
if (sandboxCfg.source === "inherit" && parentSandboxId) {
|
|
472
525
|
if (sandboxCfg.continuation === "fork") {
|
|
473
526
|
sandbox = { mode: "fork", sandboxId: parentSandboxId };
|
|
527
|
+
} else if (sandboxCfg.continuation === "snapshot") {
|
|
528
|
+
throw new Error(
|
|
529
|
+
`Subagent "${config.agentName}" has sandbox source "inherit" with continuation "snapshot" \u2014 snapshot continuation is only supported for source "own"`
|
|
530
|
+
);
|
|
474
531
|
} else {
|
|
475
532
|
sandbox = { mode: "inherit", sandboxId: parentSandboxId };
|
|
476
533
|
}
|
|
534
|
+
} else if (sandboxCfg.source === "own" && sandboxCfg.continuation === "snapshot") {
|
|
535
|
+
const isLazy = sandboxCfg.init === "once";
|
|
536
|
+
let baseSnap;
|
|
537
|
+
if (continuationThreadId) {
|
|
538
|
+
baseSnap = threadSnapshots.get(continuationThreadId)?.snapshot;
|
|
539
|
+
}
|
|
540
|
+
if (!baseSnap && isLazy) {
|
|
541
|
+
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
542
|
+
if (!baseSnap) {
|
|
543
|
+
if (persistentBaseSnapshotCreating.has(config.agentName)) {
|
|
544
|
+
await workflow.condition(() => persistentBaseSnapshot.has(config.agentName));
|
|
545
|
+
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
546
|
+
} else {
|
|
547
|
+
persistentBaseSnapshotCreating.add(config.agentName);
|
|
548
|
+
isSnapshotBaseCreator = true;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (baseSnap) {
|
|
553
|
+
sandbox = { mode: "from-snapshot", snapshot: baseSnap };
|
|
554
|
+
}
|
|
555
|
+
sandboxShutdownOverride = "snapshot";
|
|
477
556
|
} else if (sandboxCfg.source === "own") {
|
|
478
557
|
const isLazy = sandboxCfg.init === "once";
|
|
479
558
|
let baseSandboxId;
|
|
@@ -524,31 +603,8 @@ function createSubagentHandler(subagents) {
|
|
|
524
603
|
threadMode,
|
|
525
604
|
sandboxSource: sandboxCfg.source
|
|
526
605
|
});
|
|
527
|
-
const
|
|
606
|
+
const childResult = await workflow.executeChild(config.workflow, childOpts);
|
|
528
607
|
const effectiveShutdown = sandboxShutdownOverride ?? sandboxCfg.shutdown ?? "destroy";
|
|
529
|
-
if (effectiveShutdown === "pause-until-parent-close" || effectiveShutdown === "keep-until-parent-close") {
|
|
530
|
-
const key = isLazyCreator ? `persistent:${config.agentName}` : childWorkflowId;
|
|
531
|
-
pendingDestroys.set(key, childHandle);
|
|
532
|
-
}
|
|
533
|
-
await Promise.race([
|
|
534
|
-
workflow.condition(() => childResults.has(childWorkflowId)),
|
|
535
|
-
childHandle.result()
|
|
536
|
-
]);
|
|
537
|
-
if (!childResults.has(childWorkflowId)) {
|
|
538
|
-
await workflow.condition(() => childResults.has(childWorkflowId));
|
|
539
|
-
}
|
|
540
|
-
const childResult = childResults.get(childWorkflowId);
|
|
541
|
-
childResults.delete(childWorkflowId);
|
|
542
|
-
if (!childResult) {
|
|
543
|
-
workflow.log.warn("subagent returned no result", {
|
|
544
|
-
subagent: config.agentName,
|
|
545
|
-
childWorkflowId
|
|
546
|
-
});
|
|
547
|
-
return {
|
|
548
|
-
toolResponse: "Subagent workflow did not signal a result",
|
|
549
|
-
data: null
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
608
|
workflow.log.info("subagent completed", {
|
|
553
609
|
subagent: config.agentName,
|
|
554
610
|
childWorkflowId,
|
|
@@ -560,19 +616,42 @@ function createSubagentHandler(subagents) {
|
|
|
560
616
|
usage,
|
|
561
617
|
threadId: childThreadId,
|
|
562
618
|
sandboxId: childSandboxId,
|
|
619
|
+
snapshot: childSnapshot,
|
|
620
|
+
baseSnapshot: childBaseSnapshot,
|
|
563
621
|
metadata
|
|
564
622
|
} = childResult;
|
|
565
623
|
if (childSandboxId) {
|
|
566
|
-
if (sandboxCfg.source === "own" && sandboxCfg.init === "once" && !persistentSandboxes.has(config.agentName)) {
|
|
624
|
+
if (sandboxCfg.source === "own" && sandboxCfg.init === "once" && sandboxCfg.continuation !== "snapshot" && !persistentSandboxes.has(config.agentName)) {
|
|
567
625
|
persistentSandboxes.set(config.agentName, childSandboxId);
|
|
568
|
-
} else if (allowsContinuation && childThreadId) {
|
|
626
|
+
} else if (allowsContinuation && childThreadId && sandboxCfg.source === "own" && sandboxCfg.continuation !== "snapshot") {
|
|
569
627
|
threadSandboxes.set(childThreadId, childSandboxId);
|
|
570
628
|
}
|
|
571
629
|
}
|
|
630
|
+
if (childSandboxId && (effectiveShutdown === "pause-until-parent-close" || effectiveShutdown === "keep-until-parent-close")) {
|
|
631
|
+
const key = isLazyCreator ? `persistent:${config.agentName}` : childWorkflowId;
|
|
632
|
+
pendingDestroys.set(key, {
|
|
633
|
+
agentName: config.agentName,
|
|
634
|
+
sandboxId: childSandboxId
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
if (sandboxCfg.source === "own" && sandboxCfg.continuation === "snapshot") {
|
|
638
|
+
if (childSnapshot && childThreadId) {
|
|
639
|
+
threadSnapshots.set(childThreadId, {
|
|
640
|
+
agentName: config.agentName,
|
|
641
|
+
snapshot: childSnapshot
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
if (isSnapshotBaseCreator && childBaseSnapshot && !persistentBaseSnapshot.has(config.agentName)) {
|
|
645
|
+
persistentBaseSnapshot.set(config.agentName, childBaseSnapshot);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
572
648
|
if (isLazyCreator) {
|
|
573
649
|
persistentSandboxCreating.delete(config.agentName);
|
|
574
650
|
lazyCreatorAgent.delete(childWorkflowId);
|
|
575
651
|
}
|
|
652
|
+
if (isSnapshotBaseCreator) {
|
|
653
|
+
persistentBaseSnapshotCreating.delete(config.agentName);
|
|
654
|
+
}
|
|
576
655
|
if (!toolResponse) {
|
|
577
656
|
return {
|
|
578
657
|
toolResponse: "Subagent workflow returned no response",
|
|
@@ -608,22 +687,60 @@ function createSubagentHandler(subagents) {
|
|
|
608
687
|
};
|
|
609
688
|
};
|
|
610
689
|
const destroySubagentSandboxes = async () => {
|
|
611
|
-
const
|
|
690
|
+
const entries = [...pendingDestroys.values()];
|
|
612
691
|
pendingDestroys.clear();
|
|
613
692
|
await Promise.all(
|
|
614
|
-
|
|
693
|
+
entries.map(async ({ agentName, sandboxId }) => {
|
|
694
|
+
const ops = agentSandboxOps.get(agentName);
|
|
695
|
+
if (!ops) {
|
|
696
|
+
workflow.log.warn(
|
|
697
|
+
"Skipping sandbox destroy \u2014 no sandbox.proxy registered for agent",
|
|
698
|
+
{ agentName, sandboxId }
|
|
699
|
+
);
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
try {
|
|
703
|
+
await ops.destroySandbox(sandboxId);
|
|
704
|
+
} catch (err) {
|
|
705
|
+
workflow.log.warn("Failed to destroy subagent sandbox", {
|
|
706
|
+
agentName,
|
|
707
|
+
sandboxId,
|
|
708
|
+
error: err
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
})
|
|
712
|
+
);
|
|
713
|
+
};
|
|
714
|
+
const cleanupSubagentSnapshots = async () => {
|
|
715
|
+
const tagged = [];
|
|
716
|
+
for (const entry of threadSnapshots.values()) tagged.push(entry);
|
|
717
|
+
for (const [agentName, snapshot] of persistentBaseSnapshot.entries()) {
|
|
718
|
+
tagged.push({ agentName, snapshot });
|
|
719
|
+
}
|
|
720
|
+
threadSnapshots.clear();
|
|
721
|
+
persistentBaseSnapshot.clear();
|
|
722
|
+
await Promise.all(
|
|
723
|
+
tagged.map(async ({ agentName, snapshot }) => {
|
|
724
|
+
const ops = agentSandboxOps.get(agentName);
|
|
725
|
+
if (!ops) {
|
|
726
|
+
workflow.log.warn(
|
|
727
|
+
"Skipping snapshot delete \u2014 no sandbox.proxy registered for agent",
|
|
728
|
+
{ agentName }
|
|
729
|
+
);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
615
732
|
try {
|
|
616
|
-
await
|
|
617
|
-
await handle.result();
|
|
733
|
+
await ops.deleteSandboxSnapshot(snapshot);
|
|
618
734
|
} catch (err) {
|
|
619
|
-
workflow.log.warn("Failed to
|
|
735
|
+
workflow.log.warn("Failed to delete subagent snapshot", {
|
|
736
|
+
agentName,
|
|
620
737
|
error: err
|
|
621
738
|
});
|
|
622
739
|
}
|
|
623
740
|
})
|
|
624
741
|
);
|
|
625
742
|
};
|
|
626
|
-
return { handler, destroySubagentSandboxes };
|
|
743
|
+
return { handler, destroySubagentSandboxes, cleanupSubagentSnapshots };
|
|
627
744
|
}
|
|
628
745
|
|
|
629
746
|
// src/lib/subagent/register.ts
|
|
@@ -637,7 +754,7 @@ function buildSubagentRegistration(subagents) {
|
|
|
637
754
|
if (s.hooks) subagentHooksMap.set(s.agentName, s.hooks);
|
|
638
755
|
}
|
|
639
756
|
const resolveSubagentName = (args) => args.subagent;
|
|
640
|
-
const { handler, destroySubagentSandboxes } = createSubagentHandler(subagents);
|
|
757
|
+
const { handler, destroySubagentSandboxes, cleanupSubagentSnapshots } = createSubagentHandler(subagents);
|
|
641
758
|
const registration = {
|
|
642
759
|
name: SUBAGENT_TOOL_NAME,
|
|
643
760
|
enabled: () => getEnabled().length > 0,
|
|
@@ -661,7 +778,7 @@ function buildSubagentRegistration(subagents) {
|
|
|
661
778
|
}
|
|
662
779
|
}
|
|
663
780
|
};
|
|
664
|
-
return { registration, destroySubagentSandboxes };
|
|
781
|
+
return { registration, destroySubagentSandboxes, cleanupSubagentSnapshots };
|
|
665
782
|
}
|
|
666
783
|
var READ_SKILL_TOOL_NAME = "ReadSkill";
|
|
667
784
|
function buildReadSkillDescription(skills) {
|
|
@@ -734,9 +851,7 @@ function validateSkillNames(skills) {
|
|
|
734
851
|
const names = skills.map((s) => s.name);
|
|
735
852
|
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
|
|
736
853
|
if (dupes.length > 0) {
|
|
737
|
-
throw new Error(
|
|
738
|
-
`Duplicate skill names: ${[...new Set(dupes)].join(", ")}`
|
|
739
|
-
);
|
|
854
|
+
throw new Error(`Duplicate skill names: ${[...new Set(dupes)].join(", ")}`);
|
|
740
855
|
}
|
|
741
856
|
}
|
|
742
857
|
function buildSkillRegistration(skills) {
|
|
@@ -802,15 +917,18 @@ async function createSession({
|
|
|
802
917
|
initializeThread,
|
|
803
918
|
appendSystemMessage,
|
|
804
919
|
appendAgentMessage,
|
|
805
|
-
forkThread
|
|
920
|
+
forkThread,
|
|
921
|
+
truncateThread
|
|
806
922
|
} = threadOps;
|
|
807
923
|
const plugins = [];
|
|
808
924
|
let destroySubagentSandboxes;
|
|
925
|
+
let cleanupSubagentSnapshots;
|
|
809
926
|
if (subagents) {
|
|
810
927
|
const result = buildSubagentRegistration(subagents);
|
|
811
928
|
if (result) {
|
|
812
929
|
plugins.push(result.registration);
|
|
813
930
|
destroySubagentSandboxes = result.destroySubagentSandboxes;
|
|
931
|
+
cleanupSubagentSnapshots = result.cleanupSubagentSnapshots;
|
|
814
932
|
}
|
|
815
933
|
}
|
|
816
934
|
if (skills) {
|
|
@@ -863,6 +981,9 @@ async function createSession({
|
|
|
863
981
|
const sandboxMode = sandboxInit?.mode;
|
|
864
982
|
let sandboxId;
|
|
865
983
|
let sandboxOwned = false;
|
|
984
|
+
let baseSnapshot;
|
|
985
|
+
let exitSnapshot;
|
|
986
|
+
let freshlyCreated = false;
|
|
866
987
|
if (sandboxMode === "inherit") {
|
|
867
988
|
const inheritInit = sandboxInit;
|
|
868
989
|
sandboxId = inheritInit.sandboxId;
|
|
@@ -891,8 +1012,23 @@ async function createSession({
|
|
|
891
1012
|
nonRetryable: true
|
|
892
1013
|
});
|
|
893
1014
|
}
|
|
1015
|
+
const forkInit = sandboxInit;
|
|
894
1016
|
sandboxId = await sandboxOps.forkSandbox(
|
|
895
|
-
|
|
1017
|
+
forkInit.sandboxId,
|
|
1018
|
+
forkInit.options
|
|
1019
|
+
);
|
|
1020
|
+
sandboxOwned = true;
|
|
1021
|
+
} else if (sandboxMode === "from-snapshot") {
|
|
1022
|
+
if (!sandboxOps) {
|
|
1023
|
+
throw workflow.ApplicationFailure.create({
|
|
1024
|
+
message: "No sandboxOps provided \u2014 cannot restore sandbox",
|
|
1025
|
+
nonRetryable: true
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
const restoreInit = sandboxInit;
|
|
1029
|
+
sandboxId = await sandboxOps.restoreSandbox(
|
|
1030
|
+
restoreInit.snapshot,
|
|
1031
|
+
restoreInit.options
|
|
896
1032
|
);
|
|
897
1033
|
sandboxOwned = true;
|
|
898
1034
|
} else if (sandboxOps) {
|
|
@@ -903,9 +1039,13 @@ async function createSession({
|
|
|
903
1039
|
if (result) {
|
|
904
1040
|
sandboxId = result.sandboxId;
|
|
905
1041
|
sandboxOwned = true;
|
|
1042
|
+
freshlyCreated = true;
|
|
906
1043
|
}
|
|
907
1044
|
}
|
|
908
|
-
if (sandboxId &&
|
|
1045
|
+
if (sandboxId && sandboxOwned && freshlyCreated && sandboxShutdown === "snapshot" && sandboxOps) {
|
|
1046
|
+
baseSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
|
|
1047
|
+
}
|
|
1048
|
+
if (sandboxId && sandboxOwned && onSandboxReady) {
|
|
909
1049
|
onSandboxReady(sandboxId);
|
|
910
1050
|
}
|
|
911
1051
|
if (virtualFsConfig) {
|
|
@@ -971,18 +1111,25 @@ async function createSession({
|
|
|
971
1111
|
threadKey
|
|
972
1112
|
);
|
|
973
1113
|
let exitReason = "completed";
|
|
1114
|
+
let finalMessage = null;
|
|
974
1115
|
try {
|
|
975
1116
|
while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
|
|
976
1117
|
stateManager.incrementTurns();
|
|
977
1118
|
const currentTurn = stateManager.getTurns();
|
|
978
1119
|
workflow.log.debug("turn started", { agentName, threadId, turn: currentTurn });
|
|
979
1120
|
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
980
|
-
const {
|
|
1121
|
+
const {
|
|
1122
|
+
message,
|
|
1123
|
+
rawToolCalls,
|
|
1124
|
+
usage,
|
|
1125
|
+
threadLengthAtCall
|
|
1126
|
+
} = await runAgent({
|
|
981
1127
|
threadId,
|
|
982
1128
|
threadKey,
|
|
983
1129
|
agentName,
|
|
984
1130
|
metadata
|
|
985
1131
|
});
|
|
1132
|
+
const preAssistantLength = threadLengthAtCall;
|
|
986
1133
|
await appendAgentMessage(threadId, workflow.uuid4(), message, threadKey);
|
|
987
1134
|
if (usage) {
|
|
988
1135
|
stateManager.updateUsage(usage);
|
|
@@ -997,21 +1144,8 @@ async function createSession({
|
|
|
997
1144
|
if (!toolRouter.hasTools() || rawToolCalls.length === 0) {
|
|
998
1145
|
stateManager.complete();
|
|
999
1146
|
exitReason = "completed";
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
threadId,
|
|
1003
|
-
exitReason,
|
|
1004
|
-
turns: currentTurn,
|
|
1005
|
-
durationMs: Date.now() - sessionStartMs,
|
|
1006
|
-
usage: stateManager.getTotalUsage()
|
|
1007
|
-
});
|
|
1008
|
-
return {
|
|
1009
|
-
threadId,
|
|
1010
|
-
finalMessage: message,
|
|
1011
|
-
exitReason,
|
|
1012
|
-
usage: stateManager.getTotalUsage(),
|
|
1013
|
-
sandboxId
|
|
1014
|
-
};
|
|
1147
|
+
finalMessage = message;
|
|
1148
|
+
break;
|
|
1015
1149
|
}
|
|
1016
1150
|
const parsedToolCalls = [];
|
|
1017
1151
|
for (const tc of rawToolCalls) {
|
|
@@ -1041,6 +1175,24 @@ async function createSession({
|
|
|
1041
1175
|
stateManager.updateUsage(result.usage);
|
|
1042
1176
|
}
|
|
1043
1177
|
}
|
|
1178
|
+
const rewind = toolCallResults.rewind;
|
|
1179
|
+
if (rewind) {
|
|
1180
|
+
workflow.log.info("rewinding turn", {
|
|
1181
|
+
agentName,
|
|
1182
|
+
threadId,
|
|
1183
|
+
turn: currentTurn,
|
|
1184
|
+
toolCallId: rewind.toolCallId,
|
|
1185
|
+
toolName: rewind.toolName
|
|
1186
|
+
});
|
|
1187
|
+
if (preAssistantLength === void 0) {
|
|
1188
|
+
throw workflow.ApplicationFailure.create({
|
|
1189
|
+
message: "Rewind requested but runAgent did not report `threadLengthAtCall`; the adapter must populate it to support rewinds.",
|
|
1190
|
+
nonRetryable: true
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
await truncateThread(threadId, preAssistantLength, threadKey);
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1044
1196
|
if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
|
|
1045
1197
|
const conditionMet = await workflow.condition(
|
|
1046
1198
|
() => stateManager.getStatus() === "RUNNING",
|
|
@@ -1083,11 +1235,21 @@ async function createSession({
|
|
|
1083
1235
|
case "pause-until-parent-close":
|
|
1084
1236
|
await sandboxOps.pauseSandbox(sandboxId);
|
|
1085
1237
|
break;
|
|
1238
|
+
case "keep":
|
|
1239
|
+
case "keep-until-parent-close":
|
|
1240
|
+
break;
|
|
1241
|
+
case "snapshot":
|
|
1242
|
+
exitSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
|
|
1243
|
+
await sandboxOps.destroySandbox(sandboxId);
|
|
1244
|
+
break;
|
|
1086
1245
|
}
|
|
1087
1246
|
}
|
|
1088
1247
|
if (destroySubagentSandboxes) {
|
|
1089
1248
|
await destroySubagentSandboxes();
|
|
1090
1249
|
}
|
|
1250
|
+
if (cleanupSubagentSnapshots) {
|
|
1251
|
+
await cleanupSubagentSnapshots();
|
|
1252
|
+
}
|
|
1091
1253
|
}
|
|
1092
1254
|
workflow.log.info("session ended", {
|
|
1093
1255
|
agentName,
|
|
@@ -1095,14 +1257,18 @@ async function createSession({
|
|
|
1095
1257
|
exitReason,
|
|
1096
1258
|
turns: stateManager.getTurns(),
|
|
1097
1259
|
durationMs: Date.now() - sessionStartMs,
|
|
1098
|
-
usage: stateManager.getTotalUsage()
|
|
1260
|
+
usage: stateManager.getTotalUsage(),
|
|
1261
|
+
...baseSnapshot && { hasBaseSnapshot: true },
|
|
1262
|
+
...exitSnapshot && { hasExitSnapshot: true }
|
|
1099
1263
|
});
|
|
1100
1264
|
return {
|
|
1101
1265
|
threadId,
|
|
1102
|
-
finalMessage
|
|
1266
|
+
finalMessage,
|
|
1103
1267
|
exitReason,
|
|
1104
1268
|
usage: stateManager.getTotalUsage(),
|
|
1105
|
-
sandboxId
|
|
1269
|
+
sandboxId,
|
|
1270
|
+
...baseSnapshot && { baseSnapshot },
|
|
1271
|
+
...exitSnapshot && { snapshot: exitSnapshot }
|
|
1106
1272
|
};
|
|
1107
1273
|
}
|
|
1108
1274
|
};
|
|
@@ -1391,44 +1557,16 @@ function defineSubagentWorkflow(config, fn) {
|
|
|
1391
1557
|
...workflowInput.thread && { thread: workflowInput.thread },
|
|
1392
1558
|
...workflowInput.sandbox && { sandbox: workflowInput.sandbox },
|
|
1393
1559
|
onSandboxReady: (sandboxId) => {
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1560
|
+
const isReuse = workflowInput.sandbox?.mode === "continue";
|
|
1561
|
+
if (!isReuse) {
|
|
1562
|
+
void parentHandle.signal(childSandboxReadySignal, {
|
|
1563
|
+
childWorkflowId: workflow.workflowInfo().workflowId,
|
|
1564
|
+
sandboxId
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1398
1567
|
}
|
|
1399
1568
|
};
|
|
1400
|
-
|
|
1401
|
-
prompt,
|
|
1402
|
-
sessionInput,
|
|
1403
|
-
context ?? {}
|
|
1404
|
-
);
|
|
1405
|
-
if (effectiveShutdown === "pause-until-parent-close" || effectiveShutdown === "keep-until-parent-close") {
|
|
1406
|
-
if (!destroySandbox) {
|
|
1407
|
-
throw workflow.ApplicationFailure.create({
|
|
1408
|
-
message: `Subagent "${config.name}" has sandboxShutdown="${effectiveShutdown}" but fn did not return a destroySandbox callback`,
|
|
1409
|
-
nonRetryable: true
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
if (!result.sandboxId) {
|
|
1413
|
-
throw workflow.ApplicationFailure.create({
|
|
1414
|
-
message: `Subagent "${config.name}" has sandboxShutdown="${effectiveShutdown}" but fn did not return a sandboxId`,
|
|
1415
|
-
nonRetryable: true
|
|
1416
|
-
});
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
await parentHandle.signal(childResultSignal, {
|
|
1420
|
-
childWorkflowId: workflow.workflowInfo().workflowId,
|
|
1421
|
-
result
|
|
1422
|
-
});
|
|
1423
|
-
if (destroySandbox) {
|
|
1424
|
-
let destroyRequested = false;
|
|
1425
|
-
workflow.setHandler(destroySandboxSignal, () => {
|
|
1426
|
-
destroyRequested = true;
|
|
1427
|
-
});
|
|
1428
|
-
await workflow.condition(() => destroyRequested);
|
|
1429
|
-
await destroySandbox();
|
|
1430
|
-
}
|
|
1431
|
-
return result;
|
|
1569
|
+
return fn(prompt, sessionInput, context ?? {});
|
|
1432
1570
|
};
|
|
1433
1571
|
Object.defineProperty(workflow$1, "name", { value: config.name });
|
|
1434
1572
|
return Object.assign(workflow$1, {
|
|
@@ -1538,9 +1676,7 @@ function applyVirtualTreeMutations(stateManager, mutations) {
|
|
|
1538
1676
|
tree = tree.filter((e) => e.path !== m.path);
|
|
1539
1677
|
break;
|
|
1540
1678
|
case "update":
|
|
1541
|
-
tree = tree.map(
|
|
1542
|
-
(e) => e.path === m.path ? { ...e, ...m.entry } : e
|
|
1543
|
-
);
|
|
1679
|
+
tree = tree.map((e) => e.path === m.path ? { ...e, ...m.entry } : e);
|
|
1544
1680
|
break;
|
|
1545
1681
|
}
|
|
1546
1682
|
}
|
|
@@ -1599,7 +1735,9 @@ function formatVirtualFileTree(entries, opts = {}) {
|
|
|
1599
1735
|
// src/lib/virtual-fs/queries.ts
|
|
1600
1736
|
function hasFileWithMimeType(stateManager, pattern) {
|
|
1601
1737
|
const tree = stateManager.get("fileTree");
|
|
1602
|
-
const matchers = (Array.isArray(pattern) ? pattern : [pattern]).map(
|
|
1738
|
+
const matchers = (Array.isArray(pattern) ? pattern : [pattern]).map(
|
|
1739
|
+
buildMatcher
|
|
1740
|
+
);
|
|
1603
1741
|
return tree.some((entry) => {
|
|
1604
1742
|
const meta = entry.metadata;
|
|
1605
1743
|
const mime = meta?.mimeType;
|
|
@@ -1660,7 +1798,9 @@ function proxyVirtualFsOps(scope, options) {
|
|
|
1660
1798
|
// src/lib/skills/parse.ts
|
|
1661
1799
|
function parseSkillFile(raw) {
|
|
1662
1800
|
const trimmed = raw.replace(/^\uFEFF/, "");
|
|
1663
|
-
const match = trimmed.match(
|
|
1801
|
+
const match = trimmed.match(
|
|
1802
|
+
/^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?([\s\S]*)$/
|
|
1803
|
+
);
|
|
1664
1804
|
if (!match) {
|
|
1665
1805
|
throw new Error(
|
|
1666
1806
|
"SKILL.md must start with YAML frontmatter delimited by ---"
|
|
@@ -1932,7 +2072,9 @@ function createTaskGetHandler(stateManager) {
|
|
|
1932
2072
|
const task = stateManager.getTask(args.taskId) ?? null;
|
|
1933
2073
|
if (!task) {
|
|
1934
2074
|
return {
|
|
1935
|
-
toolResponse: JSON.stringify({
|
|
2075
|
+
toolResponse: JSON.stringify({
|
|
2076
|
+
error: `Task not found: ${args.taskId}`
|
|
2077
|
+
}),
|
|
1936
2078
|
data: null
|
|
1937
2079
|
};
|
|
1938
2080
|
}
|
|
@@ -1975,7 +2117,9 @@ function createTaskUpdateHandler(stateManager) {
|
|
|
1975
2117
|
const task = stateManager.getTask(args.taskId);
|
|
1976
2118
|
if (!task) {
|
|
1977
2119
|
return {
|
|
1978
|
-
toolResponse: JSON.stringify({
|
|
2120
|
+
toolResponse: JSON.stringify({
|
|
2121
|
+
error: `Task not found: ${args.taskId}`
|
|
2122
|
+
}),
|
|
1979
2123
|
data: null
|
|
1980
2124
|
};
|
|
1981
2125
|
}
|
|
@@ -2085,6 +2229,8 @@ var FileSystemSkillProvider = class {
|
|
|
2085
2229
|
this.fs = fs;
|
|
2086
2230
|
this.baseDir = baseDir;
|
|
2087
2231
|
}
|
|
2232
|
+
fs;
|
|
2233
|
+
baseDir;
|
|
2088
2234
|
async listSkills() {
|
|
2089
2235
|
const dirs = await this.discoverSkillDirs();
|
|
2090
2236
|
const skills = [];
|
|
@@ -2100,9 +2246,7 @@ var FileSystemSkillProvider = class {
|
|
|
2100
2246
|
return skills;
|
|
2101
2247
|
}
|
|
2102
2248
|
async getSkill(name) {
|
|
2103
|
-
const raw = await this.fs.readFile(
|
|
2104
|
-
path.join(this.baseDir, name, "SKILL.md")
|
|
2105
|
-
);
|
|
2249
|
+
const raw = await this.fs.readFile(path.join(this.baseDir, name, "SKILL.md"));
|
|
2106
2250
|
const { frontmatter, body } = parseSkillFile(raw);
|
|
2107
2251
|
if (frontmatter.name !== name) {
|
|
2108
2252
|
throw new Error(
|
|
@@ -2111,7 +2255,10 @@ var FileSystemSkillProvider = class {
|
|
|
2111
2255
|
}
|
|
2112
2256
|
const location = path.join(this.baseDir, name);
|
|
2113
2257
|
const resourcePaths = await this.discoverResources(name);
|
|
2114
|
-
const resourceContents = await this.readResourceContents(
|
|
2258
|
+
const resourceContents = await this.readResourceContents(
|
|
2259
|
+
location,
|
|
2260
|
+
resourcePaths
|
|
2261
|
+
);
|
|
2115
2262
|
return {
|
|
2116
2263
|
...frontmatter,
|
|
2117
2264
|
instructions: body,
|
|
@@ -2131,7 +2278,10 @@ var FileSystemSkillProvider = class {
|
|
|
2131
2278
|
const { frontmatter, body } = parseSkillFile(raw);
|
|
2132
2279
|
const location = path.join(this.baseDir, dir);
|
|
2133
2280
|
const resourcePaths = await this.discoverResources(dir);
|
|
2134
|
-
const resourceContents = await this.readResourceContents(
|
|
2281
|
+
const resourceContents = await this.readResourceContents(
|
|
2282
|
+
location,
|
|
2283
|
+
resourcePaths
|
|
2284
|
+
);
|
|
2135
2285
|
skills.push({
|
|
2136
2286
|
...frontmatter,
|
|
2137
2287
|
instructions: body,
|
|
@@ -2264,6 +2414,20 @@ function createThreadManager(config) {
|
|
|
2264
2414
|
},
|
|
2265
2415
|
async delete() {
|
|
2266
2416
|
await redis.del(redisKey, metaKey);
|
|
2417
|
+
},
|
|
2418
|
+
async length() {
|
|
2419
|
+
await assertThreadExists();
|
|
2420
|
+
return redis.llen(redisKey);
|
|
2421
|
+
},
|
|
2422
|
+
async truncate(length) {
|
|
2423
|
+
await assertThreadExists();
|
|
2424
|
+
if (length <= 0) {
|
|
2425
|
+
await redis.del(redisKey);
|
|
2426
|
+
await redis.expire(metaKey, THREAD_TTL_SECONDS);
|
|
2427
|
+
} else {
|
|
2428
|
+
await redis.ltrim(redisKey, 0, length - 1);
|
|
2429
|
+
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
2430
|
+
}
|
|
2267
2431
|
}
|
|
2268
2432
|
};
|
|
2269
2433
|
}
|
|
@@ -2305,6 +2469,7 @@ var SandboxManager = class {
|
|
|
2305
2469
|
this.provider = provider;
|
|
2306
2470
|
this.hooks = options?.hooks ?? {};
|
|
2307
2471
|
}
|
|
2472
|
+
provider;
|
|
2308
2473
|
hooks;
|
|
2309
2474
|
async create(options, ctx) {
|
|
2310
2475
|
let providerOptions = options;
|
|
@@ -2333,7 +2498,7 @@ var SandboxManager = class {
|
|
|
2333
2498
|
}
|
|
2334
2499
|
const { sandbox } = await this.provider.create(providerOptions);
|
|
2335
2500
|
if (this.hooks.onPostCreate) {
|
|
2336
|
-
await this.hooks.onPostCreate(sandbox
|
|
2501
|
+
await this.hooks.onPostCreate(sandbox, ctx ?? {});
|
|
2337
2502
|
}
|
|
2338
2503
|
return { sandboxId: sandbox.id };
|
|
2339
2504
|
}
|
|
@@ -2349,15 +2514,18 @@ var SandboxManager = class {
|
|
|
2349
2514
|
async resume(id) {
|
|
2350
2515
|
await this.provider.resume(id);
|
|
2351
2516
|
}
|
|
2352
|
-
async snapshot(id) {
|
|
2353
|
-
return this.provider.snapshot(id);
|
|
2517
|
+
async snapshot(id, options) {
|
|
2518
|
+
return this.provider.snapshot(id, options);
|
|
2354
2519
|
}
|
|
2355
|
-
async restore(snapshot) {
|
|
2356
|
-
const sandbox = await this.provider.restore(snapshot);
|
|
2520
|
+
async restore(snapshot, options) {
|
|
2521
|
+
const sandbox = await this.provider.restore(snapshot, options);
|
|
2357
2522
|
return sandbox.id;
|
|
2358
2523
|
}
|
|
2359
|
-
async
|
|
2360
|
-
|
|
2524
|
+
async deleteSnapshot(snapshot) {
|
|
2525
|
+
await this.provider.deleteSnapshot(snapshot);
|
|
2526
|
+
}
|
|
2527
|
+
async fork(sandboxId, options) {
|
|
2528
|
+
const sandbox = await this.provider.fork(sandboxId, options);
|
|
2361
2529
|
return sandbox.id;
|
|
2362
2530
|
}
|
|
2363
2531
|
/**
|
|
@@ -2395,11 +2563,17 @@ var SandboxManager = class {
|
|
|
2395
2563
|
resumeSandbox: async (sandboxId) => {
|
|
2396
2564
|
await this.resume(sandboxId);
|
|
2397
2565
|
},
|
|
2398
|
-
snapshotSandbox: async (sandboxId) => {
|
|
2399
|
-
return this.snapshot(sandboxId);
|
|
2566
|
+
snapshotSandbox: async (sandboxId, options) => {
|
|
2567
|
+
return this.snapshot(sandboxId, options);
|
|
2568
|
+
},
|
|
2569
|
+
restoreSandbox: async (snapshot, options) => {
|
|
2570
|
+
return this.restore(snapshot, options);
|
|
2571
|
+
},
|
|
2572
|
+
deleteSandboxSnapshot: async (snapshot) => {
|
|
2573
|
+
await this.deleteSnapshot(snapshot);
|
|
2400
2574
|
},
|
|
2401
|
-
forkSandbox: async (sandboxId) => {
|
|
2402
|
-
return this.fork(sandboxId);
|
|
2575
|
+
forkSandbox: async (sandboxId, options) => {
|
|
2576
|
+
return this.fork(sandboxId, options);
|
|
2403
2577
|
}
|
|
2404
2578
|
};
|
|
2405
2579
|
const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
@@ -2513,6 +2687,8 @@ var VirtualFileSystem = class {
|
|
|
2513
2687
|
]) : []
|
|
2514
2688
|
);
|
|
2515
2689
|
}
|
|
2690
|
+
resolver;
|
|
2691
|
+
ctx;
|
|
2516
2692
|
workspaceBase;
|
|
2517
2693
|
entries;
|
|
2518
2694
|
directories;
|