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.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineSignal, uuid4, setHandler, defineUpdate, ApplicationFailure, log, condition, defineQuery, proxySinks, workflowInfo, proxyActivities, getExternalWorkflowHandle,
|
|
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
|
|
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
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
|
267
|
-
if (
|
|
268
|
-
|
|
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
|
|
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
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
setHandler(
|
|
428
|
-
|
|
429
|
-
(
|
|
430
|
-
|
|
431
|
-
|
|
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
|
|
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
|
|
684
|
+
const entries = [...pendingDestroys.values()];
|
|
606
685
|
pendingDestroys.clear();
|
|
607
686
|
await Promise.all(
|
|
608
|
-
|
|
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
|
|
611
|
-
await handle.result();
|
|
727
|
+
await ops.deleteSandboxSnapshot(snapshot);
|
|
612
728
|
} catch (err) {
|
|
613
|
-
log.warn("Failed to
|
|
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
|
-
|
|
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 &&
|
|
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 {
|
|
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
|
-
|
|
995
|
-
|
|
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
|
|
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
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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({
|
|
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({
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
2354
|
-
|
|
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;
|