zeitlich 0.2.37 → 0.2.39
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 +18 -0
- package/dist/{activities-Bb-nAjwQ.d.ts → activities-Bmu7XnaG.d.ts} +4 -4
- package/dist/{activities-vkI4_3CC.d.cts → activities-ByBFLvm2.d.cts} +4 -4
- package/dist/adapter-id-BB-mmrts.d.cts +17 -0
- package/dist/adapter-id-BB-mmrts.d.ts +17 -0
- package/dist/adapter-id-CMwVrVqv.d.cts +17 -0
- package/dist/adapter-id-CMwVrVqv.d.ts +17 -0
- package/dist/adapter-id-CbY2zeSt.d.cts +17 -0
- package/dist/adapter-id-CbY2zeSt.d.ts +17 -0
- package/dist/adapters/sandbox/bedrock/index.cjs +3 -3
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +6 -6
- package/dist/adapters/sandbox/bedrock/index.d.ts +6 -6
- package/dist/adapters/sandbox/bedrock/index.js +3 -3
- package/dist/adapters/sandbox/bedrock/index.js.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/daytona/index.cjs +3 -3
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +4 -4
- package/dist/adapters/sandbox/daytona/index.d.ts +4 -4
- package/dist/adapters/sandbox/daytona/index.js +3 -3
- package/dist/adapters/sandbox/daytona/index.js.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/e2b/index.cjs +26 -14
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +24 -4
- package/dist/adapters/sandbox/e2b/index.d.ts +24 -4
- package/dist/adapters/sandbox/e2b/index.js +26 -14
- package/dist/adapters/sandbox/e2b/index.js.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/inmemory/index.cjs +3 -3
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +4 -4
- package/dist/adapters/sandbox/inmemory/index.d.ts +4 -4
- package/dist/adapters/sandbox/inmemory/index.js +3 -3
- package/dist/adapters/sandbox/inmemory/index.js.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/thread/anthropic/index.cjs +150 -13
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +9 -8
- package/dist/adapters/thread/anthropic/index.d.ts +9 -8
- package/dist/adapters/thread/anthropic/index.js +150 -14
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +9 -3
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +6 -5
- package/dist/adapters/thread/anthropic/workflow.d.ts +6 -5
- package/dist/adapters/thread/anthropic/workflow.js +9 -4
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +154 -13
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +6 -5
- package/dist/adapters/thread/google-genai/index.d.ts +6 -5
- package/dist/adapters/thread/google-genai/index.js +154 -14
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +9 -3
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +6 -5
- package/dist/adapters/thread/google-genai/workflow.d.ts +6 -5
- package/dist/adapters/thread/google-genai/workflow.js +9 -4
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/index.cjs +16 -0
- package/dist/adapters/thread/index.cjs.map +1 -0
- package/dist/adapters/thread/index.d.cts +34 -0
- package/dist/adapters/thread/index.d.ts +34 -0
- package/dist/adapters/thread/index.js +12 -0
- package/dist/adapters/thread/index.js.map +1 -0
- package/dist/adapters/thread/langchain/index.cjs +149 -14
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +9 -8
- package/dist/adapters/thread/langchain/index.d.ts +9 -8
- package/dist/adapters/thread/langchain/index.js +149 -15
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +9 -3
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +6 -5
- package/dist/adapters/thread/langchain/workflow.d.ts +6 -5
- package/dist/adapters/thread/langchain/workflow.js +9 -4
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +367 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +365 -61
- package/dist/index.js.map +1 -1
- package/dist/{proxy-DEtowJyd.d.cts → proxy-BAKzNGRq.d.cts} +1 -1
- package/dist/{proxy-0smGKvx8.d.ts → proxy-DO_MXbY4.d.ts} +1 -1
- package/dist/{thread-manager-C-C4pI2z.d.ts → thread-manager-CcRXasqs.d.ts} +2 -2
- package/dist/{thread-manager-D4vgzYrh.d.cts → thread-manager-ClwSaUnj.d.cts} +2 -2
- package/dist/{thread-manager-3fszQih4.d.ts → thread-manager-D-7lp1JK.d.ts} +2 -2
- package/dist/{thread-manager-CzYln2OC.d.cts → thread-manager-Y8Ucf0Tf.d.cts} +2 -2
- package/dist/{types-CPKDl-y_.d.ts → types-Bcbiq8iv.d.cts} +195 -22
- package/dist/{types-CNuWnvy9.d.ts → types-DAsQ21Rt.d.ts} +1 -1
- package/dist/{types-B37hKoWA.d.ts → types-DpHTX-iO.d.ts} +58 -1
- package/dist/{types-BO7Yju20.d.cts → types-Dt8-HBBT.d.ts} +195 -22
- package/dist/{types-D08CXPh8.d.cts → types-hFFi-Zd9.d.cts} +58 -1
- package/dist/{types-DWEUmYAJ.d.cts → types-lm8tMNJQ.d.cts} +1 -1
- package/dist/{types-tQL9njTu.d.cts → types-yx0LzPGn.d.cts} +21 -7
- package/dist/{types-tQL9njTu.d.ts → types-yx0LzPGn.d.ts} +21 -7
- package/dist/{workflow-CjXHbZZc.d.ts → workflow-Bmf9EtDW.d.ts} +83 -3
- package/dist/{workflow-Do_lzJpT.d.cts → workflow-Bx9utBwb.d.cts} +83 -3
- package/dist/workflow.cjs +266 -39
- 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 +264 -41
- package/dist/workflow.js.map +1 -1
- package/package.json +12 -2
- package/src/adapters/sandbox/bedrock/index.ts +12 -3
- package/src/adapters/sandbox/daytona/index.ts +12 -3
- package/src/adapters/sandbox/e2b/index.ts +36 -14
- package/src/adapters/sandbox/e2b/types.ts +16 -0
- package/src/adapters/sandbox/inmemory/index.ts +12 -3
- package/src/adapters/thread/adapter-id.test.ts +42 -0
- package/src/adapters/thread/anthropic/activities.ts +40 -5
- package/src/adapters/thread/anthropic/adapter-id.ts +16 -0
- package/src/adapters/thread/anthropic/fork-transform.test.ts +291 -0
- package/src/adapters/thread/anthropic/index.ts +3 -0
- package/src/adapters/thread/anthropic/model-invoker.ts +7 -1
- package/src/adapters/thread/anthropic/proxy.ts +3 -2
- package/src/adapters/thread/anthropic/thread-manager.ts +27 -1
- package/src/adapters/thread/google-genai/activities.ts +44 -5
- package/src/adapters/thread/google-genai/adapter-id.ts +16 -0
- package/src/adapters/thread/google-genai/fork-transform.test.ts +149 -0
- package/src/adapters/thread/google-genai/index.ts +3 -0
- package/src/adapters/thread/google-genai/model-invoker.ts +8 -2
- package/src/adapters/thread/google-genai/proxy.ts +3 -2
- package/src/adapters/thread/google-genai/thread-manager.ts +27 -1
- package/src/adapters/thread/index.ts +39 -0
- package/src/adapters/thread/langchain/activities.ts +40 -5
- package/src/adapters/thread/langchain/adapter-id.ts +16 -0
- package/src/adapters/thread/langchain/fork-transform.test.ts +142 -0
- package/src/adapters/thread/langchain/index.ts +3 -0
- package/src/adapters/thread/langchain/model-invoker.ts +7 -1
- package/src/adapters/thread/langchain/proxy.ts +3 -2
- package/src/adapters/thread/langchain/thread-manager.ts +27 -1
- package/src/lib/lifecycle.ts +14 -5
- package/src/lib/model/types.ts +7 -0
- package/src/lib/sandbox/manager.ts +26 -18
- package/src/lib/sandbox/types.ts +27 -7
- package/src/lib/session/session-edge-cases.integration.test.ts +336 -4
- package/src/lib/session/session.integration.test.ts +192 -2
- package/src/lib/session/session.ts +102 -8
- package/src/lib/session/types.ts +66 -3
- package/src/lib/state/index.ts +1 -0
- package/src/lib/state/manager.integration.test.ts +109 -0
- package/src/lib/state/manager.ts +38 -8
- package/src/lib/state/types.ts +25 -0
- package/src/lib/subagent/handler.ts +124 -11
- package/src/lib/subagent/index.ts +5 -1
- package/src/lib/subagent/subagent.integration.test.ts +628 -104
- package/src/lib/subagent/types.ts +63 -14
- package/src/lib/subagent/workflow.ts +29 -2
- package/src/lib/thread/index.ts +5 -0
- package/src/lib/thread/keys.test.ts +101 -0
- package/src/lib/thread/keys.ts +94 -0
- package/src/lib/thread/manager.test.ts +139 -0
- package/src/lib/thread/manager.ts +105 -9
- package/src/lib/thread/proxy.ts +3 -0
- package/src/lib/thread/types.ts +64 -1
- package/src/lib/tool-router/index.ts +2 -0
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +92 -0
- package/src/lib/tool-router/router.integration.test.ts +12 -0
- package/src/lib/tool-router/router.ts +89 -16
- package/src/lib/tool-router/types.ts +42 -1
- package/src/lib/types.ts +12 -0
- package/src/workflow.ts +14 -1
- package/tsup.config.ts +1 -0
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);
|
|
@@ -398,6 +444,7 @@ function createSubagentTool(subagents) {
|
|
|
398
444
|
var childSandboxReadySignal = workflow.defineSignal("childSandboxReady");
|
|
399
445
|
|
|
400
446
|
// src/lib/subagent/handler.ts
|
|
447
|
+
var DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT = "1h";
|
|
401
448
|
function resolveSandboxConfig(config) {
|
|
402
449
|
if (!config || config === "none") {
|
|
403
450
|
return { source: "none", init: "per-call", continuation: "fork" };
|
|
@@ -429,17 +476,28 @@ function createSubagentHandler(subagents) {
|
|
|
429
476
|
const threadSandboxes = /* @__PURE__ */ new Map();
|
|
430
477
|
const persistentSandboxes = /* @__PURE__ */ new Map();
|
|
431
478
|
const persistentSandboxCreating = /* @__PURE__ */ new Set();
|
|
479
|
+
const persistentSandboxCreationError = /* @__PURE__ */ new Map();
|
|
432
480
|
const lazyCreatorAgent = /* @__PURE__ */ new Map();
|
|
481
|
+
const snapshotBaseCreatorAgent = /* @__PURE__ */ new Map();
|
|
433
482
|
const threadSnapshots = /* @__PURE__ */ new Map();
|
|
434
483
|
const persistentBaseSnapshot = /* @__PURE__ */ new Map();
|
|
435
484
|
const persistentBaseSnapshotCreating = /* @__PURE__ */ new Set();
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
lazyCreatorAgent.
|
|
485
|
+
const persistentBaseSnapshotCreationError = /* @__PURE__ */ new Map();
|
|
486
|
+
workflow.setHandler(
|
|
487
|
+
childSandboxReadySignal,
|
|
488
|
+
({ childWorkflowId, sandboxId, baseSnapshot }) => {
|
|
489
|
+
const lazyAgent = lazyCreatorAgent.get(childWorkflowId);
|
|
490
|
+
if (lazyAgent && !persistentSandboxes.has(lazyAgent)) {
|
|
491
|
+
persistentSandboxes.set(lazyAgent, sandboxId);
|
|
492
|
+
lazyCreatorAgent.delete(childWorkflowId);
|
|
493
|
+
}
|
|
494
|
+
const snapAgent = snapshotBaseCreatorAgent.get(childWorkflowId);
|
|
495
|
+
if (snapAgent && baseSnapshot && !persistentBaseSnapshot.has(snapAgent)) {
|
|
496
|
+
persistentBaseSnapshot.set(snapAgent, baseSnapshot);
|
|
497
|
+
snapshotBaseCreatorAgent.delete(childWorkflowId);
|
|
498
|
+
}
|
|
441
499
|
}
|
|
442
|
-
|
|
500
|
+
);
|
|
443
501
|
const handler = async (args, context) => {
|
|
444
502
|
const config = subagents.find((s) => s.agentName === args.subagent);
|
|
445
503
|
if (!config) {
|
|
@@ -495,8 +553,20 @@ function createSubagentHandler(subagents) {
|
|
|
495
553
|
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
496
554
|
if (!baseSnap) {
|
|
497
555
|
if (persistentBaseSnapshotCreating.has(config.agentName)) {
|
|
498
|
-
await workflow.condition(
|
|
556
|
+
await workflow.condition(
|
|
557
|
+
() => persistentBaseSnapshot.has(config.agentName) || persistentBaseSnapshotCreationError.has(config.agentName) || !persistentBaseSnapshotCreating.has(config.agentName)
|
|
558
|
+
);
|
|
559
|
+
const creatorErr = persistentBaseSnapshotCreationError.get(
|
|
560
|
+
config.agentName
|
|
561
|
+
);
|
|
562
|
+
if (creatorErr !== void 0) {
|
|
563
|
+
throw creatorErr;
|
|
564
|
+
}
|
|
499
565
|
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
566
|
+
if (!baseSnap) {
|
|
567
|
+
persistentBaseSnapshotCreating.add(config.agentName);
|
|
568
|
+
isSnapshotBaseCreator = true;
|
|
569
|
+
}
|
|
500
570
|
} else {
|
|
501
571
|
persistentBaseSnapshotCreating.add(config.agentName);
|
|
502
572
|
isSnapshotBaseCreator = true;
|
|
@@ -514,8 +584,20 @@ function createSubagentHandler(subagents) {
|
|
|
514
584
|
baseSandboxId = persistentSandboxes.get(config.agentName);
|
|
515
585
|
if (!baseSandboxId) {
|
|
516
586
|
if (persistentSandboxCreating.has(config.agentName)) {
|
|
517
|
-
await workflow.condition(
|
|
587
|
+
await workflow.condition(
|
|
588
|
+
() => persistentSandboxes.has(config.agentName) || persistentSandboxCreationError.has(config.agentName) || !persistentSandboxCreating.has(config.agentName)
|
|
589
|
+
);
|
|
590
|
+
const creatorErr = persistentSandboxCreationError.get(
|
|
591
|
+
config.agentName
|
|
592
|
+
);
|
|
593
|
+
if (creatorErr !== void 0) {
|
|
594
|
+
throw creatorErr;
|
|
595
|
+
}
|
|
518
596
|
baseSandboxId = persistentSandboxes.get(config.agentName);
|
|
597
|
+
if (!baseSandboxId) {
|
|
598
|
+
persistentSandboxCreating.add(config.agentName);
|
|
599
|
+
isLazyCreator = true;
|
|
600
|
+
}
|
|
519
601
|
} else {
|
|
520
602
|
persistentSandboxCreating.add(config.agentName);
|
|
521
603
|
isLazyCreator = true;
|
|
@@ -544,6 +626,12 @@ function createSubagentHandler(subagents) {
|
|
|
544
626
|
};
|
|
545
627
|
const resolvedContext = config.context === void 0 ? void 0 : typeof config.context === "function" ? config.context() : config.context;
|
|
546
628
|
const childOpts = {
|
|
629
|
+
// Apply a bounded run timeout by default so a child workflow that
|
|
630
|
+
// fails to initialize or otherwise never reaches a terminal state
|
|
631
|
+
// cannot hang the parent's `Subagent` tool call forever. Callers can
|
|
632
|
+
// raise, lower, or disable it via `workflowOptions.workflowRunTimeout`.
|
|
633
|
+
workflowRunTimeout: DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT,
|
|
634
|
+
...config.workflowOptions ?? {},
|
|
547
635
|
workflowId: childWorkflowId,
|
|
548
636
|
args: resolvedContext === void 0 ? [args.prompt, workflowInput] : [args.prompt, workflowInput, resolvedContext],
|
|
549
637
|
taskQueue: config.taskQueue ?? parentTaskQueue
|
|
@@ -551,13 +639,39 @@ function createSubagentHandler(subagents) {
|
|
|
551
639
|
if (isLazyCreator) {
|
|
552
640
|
lazyCreatorAgent.set(childWorkflowId, config.agentName);
|
|
553
641
|
}
|
|
642
|
+
if (isSnapshotBaseCreator) {
|
|
643
|
+
snapshotBaseCreatorAgent.set(childWorkflowId, config.agentName);
|
|
644
|
+
}
|
|
554
645
|
workflow.log.info("subagent spawned", {
|
|
555
646
|
subagent: config.agentName,
|
|
556
647
|
childWorkflowId,
|
|
557
648
|
threadMode,
|
|
558
649
|
sandboxSource: sandboxCfg.source
|
|
559
650
|
});
|
|
560
|
-
|
|
651
|
+
let childResult;
|
|
652
|
+
try {
|
|
653
|
+
childResult = await workflow.executeChild(
|
|
654
|
+
config.workflow,
|
|
655
|
+
childOpts
|
|
656
|
+
);
|
|
657
|
+
} catch (err) {
|
|
658
|
+
workflow.log.warn("subagent failed", {
|
|
659
|
+
subagent: config.agentName,
|
|
660
|
+
childWorkflowId,
|
|
661
|
+
error: err instanceof Error ? err.message : String(err)
|
|
662
|
+
});
|
|
663
|
+
if (isLazyCreator) {
|
|
664
|
+
persistentSandboxCreating.delete(config.agentName);
|
|
665
|
+
persistentSandboxCreationError.set(config.agentName, err);
|
|
666
|
+
lazyCreatorAgent.delete(childWorkflowId);
|
|
667
|
+
}
|
|
668
|
+
if (isSnapshotBaseCreator) {
|
|
669
|
+
persistentBaseSnapshotCreating.delete(config.agentName);
|
|
670
|
+
persistentBaseSnapshotCreationError.set(config.agentName, err);
|
|
671
|
+
snapshotBaseCreatorAgent.delete(childWorkflowId);
|
|
672
|
+
}
|
|
673
|
+
throw err;
|
|
674
|
+
}
|
|
561
675
|
const effectiveShutdown = sandboxShutdownOverride ?? sandboxCfg.shutdown ?? "destroy";
|
|
562
676
|
workflow.log.info("subagent completed", {
|
|
563
677
|
subagent: config.agentName,
|
|
@@ -601,10 +715,13 @@ function createSubagentHandler(subagents) {
|
|
|
601
715
|
}
|
|
602
716
|
if (isLazyCreator) {
|
|
603
717
|
persistentSandboxCreating.delete(config.agentName);
|
|
718
|
+
persistentSandboxCreationError.delete(config.agentName);
|
|
604
719
|
lazyCreatorAgent.delete(childWorkflowId);
|
|
605
720
|
}
|
|
606
721
|
if (isSnapshotBaseCreator) {
|
|
607
722
|
persistentBaseSnapshotCreating.delete(config.agentName);
|
|
723
|
+
persistentBaseSnapshotCreationError.delete(config.agentName);
|
|
724
|
+
snapshotBaseCreatorAgent.delete(childWorkflowId);
|
|
608
725
|
}
|
|
609
726
|
if (!toolResponse) {
|
|
610
727
|
return {
|
|
@@ -847,6 +964,7 @@ async function createSession({
|
|
|
847
964
|
sandbox: sandboxInit,
|
|
848
965
|
sandboxShutdown = "destroy",
|
|
849
966
|
onSandboxReady,
|
|
967
|
+
onSessionExit,
|
|
850
968
|
virtualFs: virtualFsConfig,
|
|
851
969
|
virtualFsOps
|
|
852
970
|
}) {
|
|
@@ -871,7 +989,9 @@ async function createSession({
|
|
|
871
989
|
initializeThread,
|
|
872
990
|
appendSystemMessage,
|
|
873
991
|
appendAgentMessage,
|
|
874
|
-
forkThread
|
|
992
|
+
forkThread,
|
|
993
|
+
loadThreadState,
|
|
994
|
+
saveThreadState
|
|
875
995
|
} = threadOps;
|
|
876
996
|
const plugins = [];
|
|
877
997
|
let destroySubagentSandboxes;
|
|
@@ -965,8 +1085,10 @@ async function createSession({
|
|
|
965
1085
|
nonRetryable: true
|
|
966
1086
|
});
|
|
967
1087
|
}
|
|
1088
|
+
const forkInit = sandboxInit;
|
|
968
1089
|
sandboxId = await sandboxOps.forkSandbox(
|
|
969
|
-
|
|
1090
|
+
forkInit.sandboxId,
|
|
1091
|
+
forkInit.options
|
|
970
1092
|
);
|
|
971
1093
|
sandboxOwned = true;
|
|
972
1094
|
} else if (sandboxMode === "from-snapshot") {
|
|
@@ -976,8 +1098,11 @@ async function createSession({
|
|
|
976
1098
|
nonRetryable: true
|
|
977
1099
|
});
|
|
978
1100
|
}
|
|
979
|
-
const
|
|
980
|
-
sandboxId = await sandboxOps.restoreSandbox(
|
|
1101
|
+
const restoreInit = sandboxInit;
|
|
1102
|
+
sandboxId = await sandboxOps.restoreSandbox(
|
|
1103
|
+
restoreInit.snapshot,
|
|
1104
|
+
restoreInit.options
|
|
1105
|
+
);
|
|
981
1106
|
sandboxOwned = true;
|
|
982
1107
|
} else if (sandboxOps) {
|
|
983
1108
|
const skillFiles = skills ? collectSkillFiles(skills) : void 0;
|
|
@@ -994,7 +1119,10 @@ async function createSession({
|
|
|
994
1119
|
baseSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
|
|
995
1120
|
}
|
|
996
1121
|
if (sandboxId && sandboxOwned && onSandboxReady) {
|
|
997
|
-
onSandboxReady(
|
|
1122
|
+
onSandboxReady({
|
|
1123
|
+
sandboxId,
|
|
1124
|
+
...baseSnapshot && { baseSnapshot }
|
|
1125
|
+
});
|
|
998
1126
|
}
|
|
999
1127
|
if (virtualFsConfig) {
|
|
1000
1128
|
if (!virtualFsOps) {
|
|
@@ -1037,9 +1165,20 @@ async function createSession({
|
|
|
1037
1165
|
});
|
|
1038
1166
|
const sessionStartMs = Date.now();
|
|
1039
1167
|
const systemPrompt = stateManager.getSystemPrompt();
|
|
1168
|
+
const rehydrateFromSlice = (slice) => {
|
|
1169
|
+
stateManager.mergeUpdate({
|
|
1170
|
+
tasks: new Map(slice.tasks),
|
|
1171
|
+
...slice.custom
|
|
1172
|
+
});
|
|
1173
|
+
};
|
|
1040
1174
|
if (threadMode === "fork" && sourceThreadId) {
|
|
1041
1175
|
await forkThread(sourceThreadId, threadId, threadKey);
|
|
1042
|
-
|
|
1176
|
+
const forkedSlice = await loadThreadState(threadId, threadKey);
|
|
1177
|
+
if (forkedSlice) rehydrateFromSlice(forkedSlice);
|
|
1178
|
+
} else if (threadMode === "continue") {
|
|
1179
|
+
const continuedSlice = await loadThreadState(threadId, threadKey);
|
|
1180
|
+
if (continuedSlice) rehydrateFromSlice(continuedSlice);
|
|
1181
|
+
} else {
|
|
1043
1182
|
if (appendSystemPrompt) {
|
|
1044
1183
|
if (systemPrompt == null || typeof systemPrompt === "string" && systemPrompt.trim() === "") {
|
|
1045
1184
|
throw workflow.ApplicationFailure.create({
|
|
@@ -1061,18 +1200,21 @@ async function createSession({
|
|
|
1061
1200
|
let exitReason = "completed";
|
|
1062
1201
|
let finalMessage = null;
|
|
1063
1202
|
try {
|
|
1203
|
+
let assistantId;
|
|
1064
1204
|
while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
|
|
1065
1205
|
stateManager.incrementTurns();
|
|
1066
1206
|
const currentTurn = stateManager.getTurns();
|
|
1067
1207
|
workflow.log.debug("turn started", { agentName, threadId, turn: currentTurn });
|
|
1068
1208
|
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
1209
|
+
assistantId ??= workflow.uuid4();
|
|
1069
1210
|
const { message, rawToolCalls, usage } = await runAgent({
|
|
1070
1211
|
threadId,
|
|
1071
1212
|
threadKey,
|
|
1072
1213
|
agentName,
|
|
1073
|
-
metadata
|
|
1214
|
+
metadata,
|
|
1215
|
+
assistantMessageId: assistantId
|
|
1074
1216
|
});
|
|
1075
|
-
await appendAgentMessage(threadId,
|
|
1217
|
+
await appendAgentMessage(threadId, assistantId, message, threadKey);
|
|
1076
1218
|
if (usage) {
|
|
1077
1219
|
stateManager.updateUsage(usage);
|
|
1078
1220
|
}
|
|
@@ -1117,6 +1259,18 @@ async function createSession({
|
|
|
1117
1259
|
stateManager.updateUsage(result.usage);
|
|
1118
1260
|
}
|
|
1119
1261
|
}
|
|
1262
|
+
const rewind = toolCallResults.rewind;
|
|
1263
|
+
if (rewind) {
|
|
1264
|
+
workflow.log.info("rewinding turn", {
|
|
1265
|
+
agentName,
|
|
1266
|
+
threadId,
|
|
1267
|
+
turn: currentTurn,
|
|
1268
|
+
toolCallId: rewind.toolCallId,
|
|
1269
|
+
toolName: rewind.toolName
|
|
1270
|
+
});
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
assistantId = void 0;
|
|
1120
1274
|
if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
|
|
1121
1275
|
const conditionMet = await workflow.condition(
|
|
1122
1276
|
() => stateManager.getStatus() === "RUNNING",
|
|
@@ -1149,6 +1303,19 @@ async function createSession({
|
|
|
1149
1303
|
});
|
|
1150
1304
|
throw workflow.ApplicationFailure.fromError(error);
|
|
1151
1305
|
} finally {
|
|
1306
|
+
try {
|
|
1307
|
+
await saveThreadState(
|
|
1308
|
+
threadId,
|
|
1309
|
+
stateManager.getPersistedSlice(),
|
|
1310
|
+
threadKey
|
|
1311
|
+
);
|
|
1312
|
+
} catch (persistError) {
|
|
1313
|
+
workflow.log.warn("failed to persist thread state", {
|
|
1314
|
+
agentName,
|
|
1315
|
+
threadId,
|
|
1316
|
+
error: persistError instanceof Error ? persistError.message : String(persistError)
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1152
1319
|
await callSessionEnd(exitReason, stateManager.getTurns());
|
|
1153
1320
|
if (sandboxOwned && sandboxId && sandboxOps) {
|
|
1154
1321
|
switch (sandboxShutdown) {
|
|
@@ -1185,6 +1352,12 @@ async function createSession({
|
|
|
1185
1352
|
...baseSnapshot && { hasBaseSnapshot: true },
|
|
1186
1353
|
...exitSnapshot && { hasExitSnapshot: true }
|
|
1187
1354
|
});
|
|
1355
|
+
if (onSessionExit) {
|
|
1356
|
+
onSessionExit({
|
|
1357
|
+
...sandboxId && { sandboxId },
|
|
1358
|
+
...exitSnapshot && { snapshot: exitSnapshot }
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1188
1361
|
return {
|
|
1189
1362
|
threadId,
|
|
1190
1363
|
finalMessage,
|
|
@@ -1213,6 +1386,18 @@ function defineWorkflow(config, fn) {
|
|
|
1213
1386
|
return workflow;
|
|
1214
1387
|
}
|
|
1215
1388
|
|
|
1389
|
+
// src/lib/thread/keys.ts
|
|
1390
|
+
var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
1391
|
+
function getThreadListKey(threadKey, threadId) {
|
|
1392
|
+
return `${threadKey}:thread:${threadId}`;
|
|
1393
|
+
}
|
|
1394
|
+
function getThreadMetaKey(threadKey, threadId) {
|
|
1395
|
+
return `${threadKey}:meta:thread:${threadId}`;
|
|
1396
|
+
}
|
|
1397
|
+
function getThreadStateKey(threadKey, threadId) {
|
|
1398
|
+
return `${threadKey}:state:thread:${threadId}`;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1216
1401
|
// src/lib/types.ts
|
|
1217
1402
|
function isTerminalStatus(status) {
|
|
1218
1403
|
return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
|
|
@@ -1232,11 +1417,19 @@ function createAgentStateManager({
|
|
|
1232
1417
|
let systemPrompt = initialState?.systemPrompt;
|
|
1233
1418
|
const tasks = new Map(initialState?.tasks);
|
|
1234
1419
|
const {
|
|
1235
|
-
status:
|
|
1236
|
-
version:
|
|
1237
|
-
turns:
|
|
1238
|
-
tasks:
|
|
1239
|
-
tools:
|
|
1420
|
+
status: _status,
|
|
1421
|
+
version: _version,
|
|
1422
|
+
turns: _turns,
|
|
1423
|
+
tasks: _tasks,
|
|
1424
|
+
tools: _tools,
|
|
1425
|
+
systemPrompt: _systemPrompt,
|
|
1426
|
+
fileTree: _fileTree,
|
|
1427
|
+
inlineFiles: _inlineFiles,
|
|
1428
|
+
virtualFsCtx: _virtualFsCtx,
|
|
1429
|
+
totalInputTokens: _totalInputTokens,
|
|
1430
|
+
totalOutputTokens: _totalOutputTokens,
|
|
1431
|
+
cachedWriteTokens: _cachedWriteTokens,
|
|
1432
|
+
cachedReadTokens: _cachedReadTokens,
|
|
1240
1433
|
...custom
|
|
1241
1434
|
} = initialState ?? {};
|
|
1242
1435
|
const customState = custom;
|
|
@@ -1316,7 +1509,14 @@ function createAgentStateManager({
|
|
|
1316
1509
|
version++;
|
|
1317
1510
|
},
|
|
1318
1511
|
mergeUpdate(update) {
|
|
1319
|
-
|
|
1512
|
+
const { tasks: nextTasks, ...rest } = update;
|
|
1513
|
+
if (nextTasks) {
|
|
1514
|
+
tasks.clear();
|
|
1515
|
+
for (const [id, task] of nextTasks) {
|
|
1516
|
+
tasks.set(id, task);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
Object.assign(customState, rest);
|
|
1320
1520
|
version++;
|
|
1321
1521
|
},
|
|
1322
1522
|
getCurrentState() {
|
|
@@ -1354,6 +1554,12 @@ function createAgentStateManager({
|
|
|
1354
1554
|
}
|
|
1355
1555
|
return deleted;
|
|
1356
1556
|
},
|
|
1557
|
+
getPersistedSlice() {
|
|
1558
|
+
return {
|
|
1559
|
+
tasks: Array.from(tasks.entries()),
|
|
1560
|
+
custom: { ...customState }
|
|
1561
|
+
};
|
|
1562
|
+
},
|
|
1357
1563
|
updateUsage(usage) {
|
|
1358
1564
|
totalInputTokens += usage.inputTokens ?? 0;
|
|
1359
1565
|
totalOutputTokens += usage.outputTokens ?? 0;
|
|
@@ -1475,22 +1681,42 @@ function defineSubagentWorkflow(config, fn) {
|
|
|
1475
1681
|
});
|
|
1476
1682
|
}
|
|
1477
1683
|
const parentHandle = workflow.getExternalWorkflowHandle(parent.workflowId);
|
|
1684
|
+
let capturedSandboxId;
|
|
1685
|
+
let capturedSnapshot;
|
|
1686
|
+
let capturedBaseSnapshot;
|
|
1687
|
+
let capturedThreadId;
|
|
1478
1688
|
const sessionInput = {
|
|
1479
1689
|
agentName: config.name,
|
|
1480
1690
|
sandboxShutdown: effectiveShutdown,
|
|
1481
1691
|
...workflowInput.thread && { thread: workflowInput.thread },
|
|
1482
1692
|
...workflowInput.sandbox && { sandbox: workflowInput.sandbox },
|
|
1483
|
-
onSandboxReady: (sandboxId) => {
|
|
1693
|
+
onSandboxReady: ({ sandboxId, baseSnapshot }) => {
|
|
1694
|
+
capturedBaseSnapshot = baseSnapshot;
|
|
1484
1695
|
const isReuse = workflowInput.sandbox?.mode === "continue";
|
|
1485
1696
|
if (!isReuse) {
|
|
1486
1697
|
void parentHandle.signal(childSandboxReadySignal, {
|
|
1487
1698
|
childWorkflowId: workflow.workflowInfo().workflowId,
|
|
1488
|
-
sandboxId
|
|
1699
|
+
sandboxId,
|
|
1700
|
+
...baseSnapshot && { baseSnapshot }
|
|
1489
1701
|
});
|
|
1490
1702
|
}
|
|
1703
|
+
},
|
|
1704
|
+
onSessionExit: ({ sandboxId, snapshot, threadId }) => {
|
|
1705
|
+
capturedSandboxId = sandboxId;
|
|
1706
|
+
capturedSnapshot = snapshot;
|
|
1707
|
+
capturedThreadId = threadId;
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
const result = await fn(prompt, sessionInput, context ?? {});
|
|
1711
|
+
return {
|
|
1712
|
+
...result,
|
|
1713
|
+
...capturedThreadId !== void 0 && { threadId: capturedThreadId },
|
|
1714
|
+
...capturedSandboxId !== void 0 && { sandboxId: capturedSandboxId },
|
|
1715
|
+
...capturedSnapshot !== void 0 && { snapshot: capturedSnapshot },
|
|
1716
|
+
...capturedBaseSnapshot !== void 0 && {
|
|
1717
|
+
baseSnapshot: capturedBaseSnapshot
|
|
1491
1718
|
}
|
|
1492
1719
|
};
|
|
1493
|
-
return fn(prompt, sessionInput, context ?? {});
|
|
1494
1720
|
};
|
|
1495
1721
|
Object.defineProperty(workflow$1, "name", { value: config.name });
|
|
1496
1722
|
return Object.assign(workflow$1, {
|
|
@@ -2260,7 +2486,6 @@ var FileSystemSkillProvider = class {
|
|
|
2260
2486
|
};
|
|
2261
2487
|
|
|
2262
2488
|
// src/lib/thread/manager.ts
|
|
2263
|
-
var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
2264
2489
|
var APPEND_IDEMPOTENT_SCRIPT = `
|
|
2265
2490
|
if redis.call('EXISTS', KEYS[1]) == 1 then
|
|
2266
2491
|
return 0
|
|
@@ -2272,8 +2497,8 @@ redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
|
|
|
2272
2497
|
redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
|
|
2273
2498
|
return 1
|
|
2274
2499
|
`;
|
|
2275
|
-
function
|
|
2276
|
-
return
|
|
2500
|
+
function getDedupKey(threadId, id) {
|
|
2501
|
+
return `dedup:${id}:thread:${threadId}`;
|
|
2277
2502
|
}
|
|
2278
2503
|
function createThreadManager(config) {
|
|
2279
2504
|
const {
|
|
@@ -2284,8 +2509,9 @@ function createThreadManager(config) {
|
|
|
2284
2509
|
deserialize = (raw) => JSON.parse(raw),
|
|
2285
2510
|
idOf
|
|
2286
2511
|
} = config;
|
|
2287
|
-
const redisKey =
|
|
2288
|
-
const metaKey =
|
|
2512
|
+
const redisKey = getThreadListKey(key, threadId);
|
|
2513
|
+
const metaKey = getThreadMetaKey(key, threadId);
|
|
2514
|
+
const stateKey = getThreadStateKey(key, threadId);
|
|
2289
2515
|
async function assertThreadExists() {
|
|
2290
2516
|
const exists = await redis.exists(metaKey);
|
|
2291
2517
|
if (!exists) {
|
|
@@ -2307,7 +2533,7 @@ function createThreadManager(config) {
|
|
|
2307
2533
|
await assertThreadExists();
|
|
2308
2534
|
if (idOf) {
|
|
2309
2535
|
const dedupId = messages.map(idOf).join(":");
|
|
2310
|
-
const dedupKey =
|
|
2536
|
+
const dedupKey = getDedupKey(threadId, dedupId);
|
|
2311
2537
|
await redis.eval(
|
|
2312
2538
|
APPEND_IDEMPOTENT_SCRIPT,
|
|
2313
2539
|
2,
|
|
@@ -2324,20 +2550,98 @@ function createThreadManager(config) {
|
|
|
2324
2550
|
async fork(newThreadId) {
|
|
2325
2551
|
await assertThreadExists();
|
|
2326
2552
|
const data = await redis.lrange(redisKey, 0, -1);
|
|
2553
|
+
const stateRaw = await redis.get(stateKey);
|
|
2327
2554
|
const forked = createThreadManager({
|
|
2328
2555
|
...config,
|
|
2329
2556
|
threadId: newThreadId
|
|
2330
2557
|
});
|
|
2331
2558
|
await forked.initialize();
|
|
2332
2559
|
if (data.length > 0) {
|
|
2333
|
-
const newKey =
|
|
2560
|
+
const newKey = getThreadListKey(key, newThreadId);
|
|
2334
2561
|
await redis.rpush(newKey, ...data);
|
|
2335
2562
|
await redis.expire(newKey, THREAD_TTL_SECONDS);
|
|
2336
2563
|
}
|
|
2564
|
+
if (stateRaw != null) {
|
|
2565
|
+
const newStateKey = getThreadStateKey(key, newThreadId);
|
|
2566
|
+
await redis.set(newStateKey, stateRaw, "EX", THREAD_TTL_SECONDS);
|
|
2567
|
+
}
|
|
2337
2568
|
return forked;
|
|
2338
2569
|
},
|
|
2570
|
+
async replaceAll(messages) {
|
|
2571
|
+
await assertThreadExists();
|
|
2572
|
+
if (!idOf) {
|
|
2573
|
+
throw new Error(
|
|
2574
|
+
"replaceAll requires the thread manager to be configured with `idOf`"
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
const existing = await redis.lrange(redisKey, 0, -1);
|
|
2578
|
+
const existingIds = existing.map((raw) => idOf(deserialize(raw))).filter((id) => typeof id === "string");
|
|
2579
|
+
await redis.del(redisKey);
|
|
2580
|
+
if (existingIds.length > 0) {
|
|
2581
|
+
await redis.del(
|
|
2582
|
+
...existingIds.map((id) => getDedupKey(threadId, id))
|
|
2583
|
+
);
|
|
2584
|
+
}
|
|
2585
|
+
if (messages.length > 0) {
|
|
2586
|
+
await redis.rpush(redisKey, ...messages.map(serialize));
|
|
2587
|
+
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
2588
|
+
}
|
|
2589
|
+
await redis.expire(metaKey, THREAD_TTL_SECONDS);
|
|
2590
|
+
},
|
|
2339
2591
|
async delete() {
|
|
2340
|
-
await redis.del(redisKey, metaKey);
|
|
2592
|
+
await redis.del(redisKey, metaKey, stateKey);
|
|
2593
|
+
},
|
|
2594
|
+
async loadState() {
|
|
2595
|
+
const raw = await redis.get(stateKey);
|
|
2596
|
+
if (raw == null) return null;
|
|
2597
|
+
return JSON.parse(raw);
|
|
2598
|
+
},
|
|
2599
|
+
async saveState(state) {
|
|
2600
|
+
await assertThreadExists();
|
|
2601
|
+
await redis.set(
|
|
2602
|
+
stateKey,
|
|
2603
|
+
JSON.stringify(state),
|
|
2604
|
+
"EX",
|
|
2605
|
+
THREAD_TTL_SECONDS
|
|
2606
|
+
);
|
|
2607
|
+
},
|
|
2608
|
+
async deleteState() {
|
|
2609
|
+
await redis.del(stateKey);
|
|
2610
|
+
},
|
|
2611
|
+
async length() {
|
|
2612
|
+
await assertThreadExists();
|
|
2613
|
+
return redis.llen(redisKey);
|
|
2614
|
+
},
|
|
2615
|
+
async truncateFromId(messageId) {
|
|
2616
|
+
await assertThreadExists();
|
|
2617
|
+
if (!idOf) {
|
|
2618
|
+
throw new Error(
|
|
2619
|
+
"truncateFromId requires the thread manager to be configured with `idOf`"
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
const data = await redis.lrange(redisKey, 0, -1);
|
|
2623
|
+
let idx = -1;
|
|
2624
|
+
const removedIds = [];
|
|
2625
|
+
for (let i = 0; i < data.length; i++) {
|
|
2626
|
+
const raw = data[i];
|
|
2627
|
+
if (raw === void 0) continue;
|
|
2628
|
+
const id = idOf(deserialize(raw));
|
|
2629
|
+
if (idx === -1 && id === messageId) idx = i;
|
|
2630
|
+
if (idx !== -1) removedIds.push(id);
|
|
2631
|
+
}
|
|
2632
|
+
if (idx === -1) return;
|
|
2633
|
+
if (idx === 0) {
|
|
2634
|
+
await redis.del(redisKey);
|
|
2635
|
+
await redis.expire(metaKey, THREAD_TTL_SECONDS);
|
|
2636
|
+
} else {
|
|
2637
|
+
await redis.ltrim(redisKey, 0, idx - 1);
|
|
2638
|
+
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
2639
|
+
}
|
|
2640
|
+
if (removedIds.length > 0) {
|
|
2641
|
+
await redis.del(
|
|
2642
|
+
...removedIds.map((id) => getDedupKey(threadId, id))
|
|
2643
|
+
);
|
|
2644
|
+
}
|
|
2341
2645
|
}
|
|
2342
2646
|
};
|
|
2343
2647
|
}
|
|
@@ -2424,18 +2728,18 @@ var SandboxManager = class {
|
|
|
2424
2728
|
async resume(id) {
|
|
2425
2729
|
await this.provider.resume(id);
|
|
2426
2730
|
}
|
|
2427
|
-
async snapshot(id) {
|
|
2428
|
-
return this.provider.snapshot(id);
|
|
2731
|
+
async snapshot(id, options) {
|
|
2732
|
+
return this.provider.snapshot(id, options);
|
|
2429
2733
|
}
|
|
2430
|
-
async restore(snapshot) {
|
|
2431
|
-
const sandbox = await this.provider.restore(snapshot);
|
|
2734
|
+
async restore(snapshot, options) {
|
|
2735
|
+
const sandbox = await this.provider.restore(snapshot, options);
|
|
2432
2736
|
return sandbox.id;
|
|
2433
2737
|
}
|
|
2434
2738
|
async deleteSnapshot(snapshot) {
|
|
2435
2739
|
await this.provider.deleteSnapshot(snapshot);
|
|
2436
2740
|
}
|
|
2437
|
-
async fork(sandboxId) {
|
|
2438
|
-
const sandbox = await this.provider.fork(sandboxId);
|
|
2741
|
+
async fork(sandboxId, options) {
|
|
2742
|
+
const sandbox = await this.provider.fork(sandboxId, options);
|
|
2439
2743
|
return sandbox.id;
|
|
2440
2744
|
}
|
|
2441
2745
|
/**
|
|
@@ -2473,17 +2777,17 @@ var SandboxManager = class {
|
|
|
2473
2777
|
resumeSandbox: async (sandboxId) => {
|
|
2474
2778
|
await this.resume(sandboxId);
|
|
2475
2779
|
},
|
|
2476
|
-
snapshotSandbox: async (sandboxId) => {
|
|
2477
|
-
return this.snapshot(sandboxId);
|
|
2780
|
+
snapshotSandbox: async (sandboxId, options) => {
|
|
2781
|
+
return this.snapshot(sandboxId, options);
|
|
2478
2782
|
},
|
|
2479
|
-
restoreSandbox: async (snapshot) => {
|
|
2480
|
-
return this.restore(snapshot);
|
|
2783
|
+
restoreSandbox: async (snapshot, options) => {
|
|
2784
|
+
return this.restore(snapshot, options);
|
|
2481
2785
|
},
|
|
2482
2786
|
deleteSandboxSnapshot: async (snapshot) => {
|
|
2483
2787
|
await this.deleteSnapshot(snapshot);
|
|
2484
2788
|
},
|
|
2485
|
-
forkSandbox: async (sandboxId) => {
|
|
2486
|
-
return this.fork(sandboxId);
|
|
2789
|
+
forkSandbox: async (sandboxId, options) => {
|
|
2790
|
+
return this.fork(sandboxId, options);
|
|
2487
2791
|
}
|
|
2488
2792
|
};
|
|
2489
2793
|
const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
@@ -3152,11 +3456,13 @@ var toTree = async (fs, opts = {}) => {
|
|
|
3152
3456
|
return base + subtree;
|
|
3153
3457
|
};
|
|
3154
3458
|
|
|
3459
|
+
exports.DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT = DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT;
|
|
3155
3460
|
exports.FileSystemSkillProvider = FileSystemSkillProvider;
|
|
3156
3461
|
exports.NodeFsSandboxFileSystem = NodeFsSandboxFileSystem;
|
|
3157
3462
|
exports.SandboxManager = SandboxManager;
|
|
3158
3463
|
exports.SandboxNotFoundError = SandboxNotFoundError;
|
|
3159
3464
|
exports.SandboxNotSupportedError = SandboxNotSupportedError;
|
|
3465
|
+
exports.THREAD_TTL_SECONDS = THREAD_TTL_SECONDS;
|
|
3160
3466
|
exports.VirtualFileSystem = VirtualFileSystem;
|
|
3161
3467
|
exports.applyVirtualTreeMutations = applyVirtualTreeMutations;
|
|
3162
3468
|
exports.askUserQuestionTool = askUserQuestionTool;
|
|
@@ -3188,6 +3494,8 @@ exports.filesWithMimeType = filesWithMimeType;
|
|
|
3188
3494
|
exports.formatVirtualFileTree = formatVirtualFileTree;
|
|
3189
3495
|
exports.getActivityContext = getActivityContext;
|
|
3190
3496
|
exports.getShortId = getShortId;
|
|
3497
|
+
exports.getThreadListKey = getThreadListKey;
|
|
3498
|
+
exports.getThreadMetaKey = getThreadMetaKey;
|
|
3191
3499
|
exports.globHandler = globHandler;
|
|
3192
3500
|
exports.globTool = globTool;
|
|
3193
3501
|
exports.grepTool = grepTool;
|