zeitlich 0.2.38 → 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-BKhMtKDd.d.ts → activities-Bmu7XnaG.d.ts} +4 -6
- package/dist/{activities-CDcwkRZs.d.cts → activities-ByBFLvm2.d.cts} +4 -6
- 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/thread/anthropic/index.cjs +140 -23
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +8 -7
- package/dist/adapters/thread/anthropic/index.d.ts +8 -7
- package/dist/adapters/thread/anthropic/index.js +140 -24
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +8 -3
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -4
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -4
- package/dist/adapters/thread/anthropic/workflow.js +8 -4
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +140 -23
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -4
- package/dist/adapters/thread/google-genai/index.d.ts +5 -4
- package/dist/adapters/thread/google-genai/index.js +140 -24
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +8 -3
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -4
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -4
- package/dist/adapters/thread/google-genai/workflow.js +8 -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 +139 -24
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +8 -7
- package/dist/adapters/thread/langchain/index.d.ts +8 -7
- package/dist/adapters/thread/langchain/index.js +139 -25
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +8 -3
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -4
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -4
- package/dist/adapters/thread/langchain/workflow.js +8 -4
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +266 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +263 -49
- package/dist/index.js.map +1 -1
- package/dist/{proxy-D_3x7RN4.d.cts → proxy-BAKzNGRq.d.cts} +1 -1
- package/dist/{proxy-CUlKSvZS.d.ts → proxy-DO_MXbY4.d.ts} +1 -1
- package/dist/{thread-manager-CVu7o2cs.d.ts → thread-manager-CcRXasqs.d.ts} +2 -4
- package/dist/{thread-manager-HSwyh28L.d.cts → thread-manager-ClwSaUnj.d.cts} +2 -4
- package/dist/{thread-manager-c1gPopAG.d.ts → thread-manager-D-7lp1JK.d.ts} +2 -4
- package/dist/{thread-manager-wGi-LqIP.d.cts → thread-manager-Y8Ucf0Tf.d.cts} +2 -4
- package/dist/{types-C06FwR96.d.cts → types-Bcbiq8iv.d.cts} +162 -44
- package/dist/{types-BH_IRryz.d.ts → types-DpHTX-iO.d.ts} +54 -6
- package/dist/{types-DNr31FzL.d.ts → types-Dt8-HBBT.d.ts} +162 -44
- package/dist/{types-BaOw4hKI.d.cts → types-hFFi-Zd9.d.cts} +54 -6
- package/dist/{workflow-CSCkpwAL.d.ts → workflow-Bmf9EtDW.d.ts} +82 -2
- package/dist/{workflow-DuvMZ8Vm.d.cts → workflow-Bx9utBwb.d.cts} +82 -2
- package/dist/workflow.cjs +188 -37
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -2
- package/dist/workflow.d.ts +2 -2
- package/dist/workflow.js +185 -38
- package/dist/workflow.js.map +1 -1
- package/package.json +11 -1
- package/src/adapters/thread/adapter-id.test.ts +42 -0
- package/src/adapters/thread/anthropic/activities.ts +33 -7
- 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 +8 -4
- package/src/adapters/thread/anthropic/proxy.ts +3 -2
- package/src/adapters/thread/anthropic/thread-manager.ts +27 -4
- package/src/adapters/thread/google-genai/activities.ts +33 -7
- 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 +7 -3
- package/src/adapters/thread/google-genai/proxy.ts +3 -2
- package/src/adapters/thread/google-genai/thread-manager.ts +27 -4
- package/src/adapters/thread/index.ts +39 -0
- package/src/adapters/thread/langchain/activities.ts +33 -7
- 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 +8 -3
- package/src/adapters/thread/langchain/proxy.ts +3 -2
- package/src/adapters/thread/langchain/thread-manager.ts +27 -4
- package/src/lib/lifecycle.ts +3 -1
- package/src/lib/model/types.ts +7 -10
- package/src/lib/session/session-edge-cases.integration.test.ts +131 -63
- package/src/lib/session/session.integration.test.ts +174 -5
- package/src/lib/session/session.ts +68 -28
- package/src/lib/session/types.ts +60 -9
- 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 +528 -0
- 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 +92 -14
- package/src/lib/thread/proxy.ts +2 -0
- package/src/lib/thread/types.ts +60 -6
- package/src/lib/tool-router/types.ts +16 -8
- package/src/lib/types.ts +12 -0
- package/src/workflow.ts +12 -1
- package/tsup.config.ts +1 -0
package/dist/index.cjs
CHANGED
|
@@ -444,6 +444,7 @@ function createSubagentTool(subagents) {
|
|
|
444
444
|
var childSandboxReadySignal = workflow.defineSignal("childSandboxReady");
|
|
445
445
|
|
|
446
446
|
// src/lib/subagent/handler.ts
|
|
447
|
+
var DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT = "1h";
|
|
447
448
|
function resolveSandboxConfig(config) {
|
|
448
449
|
if (!config || config === "none") {
|
|
449
450
|
return { source: "none", init: "per-call", continuation: "fork" };
|
|
@@ -475,17 +476,28 @@ function createSubagentHandler(subagents) {
|
|
|
475
476
|
const threadSandboxes = /* @__PURE__ */ new Map();
|
|
476
477
|
const persistentSandboxes = /* @__PURE__ */ new Map();
|
|
477
478
|
const persistentSandboxCreating = /* @__PURE__ */ new Set();
|
|
479
|
+
const persistentSandboxCreationError = /* @__PURE__ */ new Map();
|
|
478
480
|
const lazyCreatorAgent = /* @__PURE__ */ new Map();
|
|
481
|
+
const snapshotBaseCreatorAgent = /* @__PURE__ */ new Map();
|
|
479
482
|
const threadSnapshots = /* @__PURE__ */ new Map();
|
|
480
483
|
const persistentBaseSnapshot = /* @__PURE__ */ new Map();
|
|
481
484
|
const persistentBaseSnapshotCreating = /* @__PURE__ */ new Set();
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
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
|
+
}
|
|
487
499
|
}
|
|
488
|
-
|
|
500
|
+
);
|
|
489
501
|
const handler = async (args, context) => {
|
|
490
502
|
const config = subagents.find((s) => s.agentName === args.subagent);
|
|
491
503
|
if (!config) {
|
|
@@ -541,8 +553,20 @@ function createSubagentHandler(subagents) {
|
|
|
541
553
|
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
542
554
|
if (!baseSnap) {
|
|
543
555
|
if (persistentBaseSnapshotCreating.has(config.agentName)) {
|
|
544
|
-
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
|
+
}
|
|
545
565
|
baseSnap = persistentBaseSnapshot.get(config.agentName);
|
|
566
|
+
if (!baseSnap) {
|
|
567
|
+
persistentBaseSnapshotCreating.add(config.agentName);
|
|
568
|
+
isSnapshotBaseCreator = true;
|
|
569
|
+
}
|
|
546
570
|
} else {
|
|
547
571
|
persistentBaseSnapshotCreating.add(config.agentName);
|
|
548
572
|
isSnapshotBaseCreator = true;
|
|
@@ -560,8 +584,20 @@ function createSubagentHandler(subagents) {
|
|
|
560
584
|
baseSandboxId = persistentSandboxes.get(config.agentName);
|
|
561
585
|
if (!baseSandboxId) {
|
|
562
586
|
if (persistentSandboxCreating.has(config.agentName)) {
|
|
563
|
-
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
|
+
}
|
|
564
596
|
baseSandboxId = persistentSandboxes.get(config.agentName);
|
|
597
|
+
if (!baseSandboxId) {
|
|
598
|
+
persistentSandboxCreating.add(config.agentName);
|
|
599
|
+
isLazyCreator = true;
|
|
600
|
+
}
|
|
565
601
|
} else {
|
|
566
602
|
persistentSandboxCreating.add(config.agentName);
|
|
567
603
|
isLazyCreator = true;
|
|
@@ -590,6 +626,12 @@ function createSubagentHandler(subagents) {
|
|
|
590
626
|
};
|
|
591
627
|
const resolvedContext = config.context === void 0 ? void 0 : typeof config.context === "function" ? config.context() : config.context;
|
|
592
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 ?? {},
|
|
593
635
|
workflowId: childWorkflowId,
|
|
594
636
|
args: resolvedContext === void 0 ? [args.prompt, workflowInput] : [args.prompt, workflowInput, resolvedContext],
|
|
595
637
|
taskQueue: config.taskQueue ?? parentTaskQueue
|
|
@@ -597,13 +639,39 @@ function createSubagentHandler(subagents) {
|
|
|
597
639
|
if (isLazyCreator) {
|
|
598
640
|
lazyCreatorAgent.set(childWorkflowId, config.agentName);
|
|
599
641
|
}
|
|
642
|
+
if (isSnapshotBaseCreator) {
|
|
643
|
+
snapshotBaseCreatorAgent.set(childWorkflowId, config.agentName);
|
|
644
|
+
}
|
|
600
645
|
workflow.log.info("subagent spawned", {
|
|
601
646
|
subagent: config.agentName,
|
|
602
647
|
childWorkflowId,
|
|
603
648
|
threadMode,
|
|
604
649
|
sandboxSource: sandboxCfg.source
|
|
605
650
|
});
|
|
606
|
-
|
|
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
|
+
}
|
|
607
675
|
const effectiveShutdown = sandboxShutdownOverride ?? sandboxCfg.shutdown ?? "destroy";
|
|
608
676
|
workflow.log.info("subagent completed", {
|
|
609
677
|
subagent: config.agentName,
|
|
@@ -647,10 +715,13 @@ function createSubagentHandler(subagents) {
|
|
|
647
715
|
}
|
|
648
716
|
if (isLazyCreator) {
|
|
649
717
|
persistentSandboxCreating.delete(config.agentName);
|
|
718
|
+
persistentSandboxCreationError.delete(config.agentName);
|
|
650
719
|
lazyCreatorAgent.delete(childWorkflowId);
|
|
651
720
|
}
|
|
652
721
|
if (isSnapshotBaseCreator) {
|
|
653
722
|
persistentBaseSnapshotCreating.delete(config.agentName);
|
|
723
|
+
persistentBaseSnapshotCreationError.delete(config.agentName);
|
|
724
|
+
snapshotBaseCreatorAgent.delete(childWorkflowId);
|
|
654
725
|
}
|
|
655
726
|
if (!toolResponse) {
|
|
656
727
|
return {
|
|
@@ -893,6 +964,7 @@ async function createSession({
|
|
|
893
964
|
sandbox: sandboxInit,
|
|
894
965
|
sandboxShutdown = "destroy",
|
|
895
966
|
onSandboxReady,
|
|
967
|
+
onSessionExit,
|
|
896
968
|
virtualFs: virtualFsConfig,
|
|
897
969
|
virtualFsOps
|
|
898
970
|
}) {
|
|
@@ -918,7 +990,8 @@ async function createSession({
|
|
|
918
990
|
appendSystemMessage,
|
|
919
991
|
appendAgentMessage,
|
|
920
992
|
forkThread,
|
|
921
|
-
|
|
993
|
+
loadThreadState,
|
|
994
|
+
saveThreadState
|
|
922
995
|
} = threadOps;
|
|
923
996
|
const plugins = [];
|
|
924
997
|
let destroySubagentSandboxes;
|
|
@@ -1046,7 +1119,10 @@ async function createSession({
|
|
|
1046
1119
|
baseSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
|
|
1047
1120
|
}
|
|
1048
1121
|
if (sandboxId && sandboxOwned && onSandboxReady) {
|
|
1049
|
-
onSandboxReady(
|
|
1122
|
+
onSandboxReady({
|
|
1123
|
+
sandboxId,
|
|
1124
|
+
...baseSnapshot && { baseSnapshot }
|
|
1125
|
+
});
|
|
1050
1126
|
}
|
|
1051
1127
|
if (virtualFsConfig) {
|
|
1052
1128
|
if (!virtualFsOps) {
|
|
@@ -1089,9 +1165,20 @@ async function createSession({
|
|
|
1089
1165
|
});
|
|
1090
1166
|
const sessionStartMs = Date.now();
|
|
1091
1167
|
const systemPrompt = stateManager.getSystemPrompt();
|
|
1168
|
+
const rehydrateFromSlice = (slice) => {
|
|
1169
|
+
stateManager.mergeUpdate({
|
|
1170
|
+
tasks: new Map(slice.tasks),
|
|
1171
|
+
...slice.custom
|
|
1172
|
+
});
|
|
1173
|
+
};
|
|
1092
1174
|
if (threadMode === "fork" && sourceThreadId) {
|
|
1093
1175
|
await forkThread(sourceThreadId, threadId, threadKey);
|
|
1094
|
-
|
|
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 {
|
|
1095
1182
|
if (appendSystemPrompt) {
|
|
1096
1183
|
if (systemPrompt == null || typeof systemPrompt === "string" && systemPrompt.trim() === "") {
|
|
1097
1184
|
throw workflow.ApplicationFailure.create({
|
|
@@ -1113,24 +1200,21 @@ async function createSession({
|
|
|
1113
1200
|
let exitReason = "completed";
|
|
1114
1201
|
let finalMessage = null;
|
|
1115
1202
|
try {
|
|
1203
|
+
let assistantId;
|
|
1116
1204
|
while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
|
|
1117
1205
|
stateManager.incrementTurns();
|
|
1118
1206
|
const currentTurn = stateManager.getTurns();
|
|
1119
1207
|
workflow.log.debug("turn started", { agentName, threadId, turn: currentTurn });
|
|
1120
1208
|
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
rawToolCalls,
|
|
1124
|
-
usage,
|
|
1125
|
-
threadLengthAtCall
|
|
1126
|
-
} = await runAgent({
|
|
1209
|
+
assistantId ??= workflow.uuid4();
|
|
1210
|
+
const { message, rawToolCalls, usage } = await runAgent({
|
|
1127
1211
|
threadId,
|
|
1128
1212
|
threadKey,
|
|
1129
1213
|
agentName,
|
|
1130
|
-
metadata
|
|
1214
|
+
metadata,
|
|
1215
|
+
assistantMessageId: assistantId
|
|
1131
1216
|
});
|
|
1132
|
-
|
|
1133
|
-
await appendAgentMessage(threadId, workflow.uuid4(), message, threadKey);
|
|
1217
|
+
await appendAgentMessage(threadId, assistantId, message, threadKey);
|
|
1134
1218
|
if (usage) {
|
|
1135
1219
|
stateManager.updateUsage(usage);
|
|
1136
1220
|
}
|
|
@@ -1184,15 +1268,9 @@ async function createSession({
|
|
|
1184
1268
|
toolCallId: rewind.toolCallId,
|
|
1185
1269
|
toolName: rewind.toolName
|
|
1186
1270
|
});
|
|
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
1271
|
continue;
|
|
1195
1272
|
}
|
|
1273
|
+
assistantId = void 0;
|
|
1196
1274
|
if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
|
|
1197
1275
|
const conditionMet = await workflow.condition(
|
|
1198
1276
|
() => stateManager.getStatus() === "RUNNING",
|
|
@@ -1225,6 +1303,19 @@ async function createSession({
|
|
|
1225
1303
|
});
|
|
1226
1304
|
throw workflow.ApplicationFailure.fromError(error);
|
|
1227
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
|
+
}
|
|
1228
1319
|
await callSessionEnd(exitReason, stateManager.getTurns());
|
|
1229
1320
|
if (sandboxOwned && sandboxId && sandboxOps) {
|
|
1230
1321
|
switch (sandboxShutdown) {
|
|
@@ -1261,6 +1352,12 @@ async function createSession({
|
|
|
1261
1352
|
...baseSnapshot && { hasBaseSnapshot: true },
|
|
1262
1353
|
...exitSnapshot && { hasExitSnapshot: true }
|
|
1263
1354
|
});
|
|
1355
|
+
if (onSessionExit) {
|
|
1356
|
+
onSessionExit({
|
|
1357
|
+
...sandboxId && { sandboxId },
|
|
1358
|
+
...exitSnapshot && { snapshot: exitSnapshot }
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1264
1361
|
return {
|
|
1265
1362
|
threadId,
|
|
1266
1363
|
finalMessage,
|
|
@@ -1289,6 +1386,18 @@ function defineWorkflow(config, fn) {
|
|
|
1289
1386
|
return workflow;
|
|
1290
1387
|
}
|
|
1291
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
|
+
|
|
1292
1401
|
// src/lib/types.ts
|
|
1293
1402
|
function isTerminalStatus(status) {
|
|
1294
1403
|
return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
|
|
@@ -1308,11 +1417,19 @@ function createAgentStateManager({
|
|
|
1308
1417
|
let systemPrompt = initialState?.systemPrompt;
|
|
1309
1418
|
const tasks = new Map(initialState?.tasks);
|
|
1310
1419
|
const {
|
|
1311
|
-
status:
|
|
1312
|
-
version:
|
|
1313
|
-
turns:
|
|
1314
|
-
tasks:
|
|
1315
|
-
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,
|
|
1316
1433
|
...custom
|
|
1317
1434
|
} = initialState ?? {};
|
|
1318
1435
|
const customState = custom;
|
|
@@ -1392,7 +1509,14 @@ function createAgentStateManager({
|
|
|
1392
1509
|
version++;
|
|
1393
1510
|
},
|
|
1394
1511
|
mergeUpdate(update) {
|
|
1395
|
-
|
|
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);
|
|
1396
1520
|
version++;
|
|
1397
1521
|
},
|
|
1398
1522
|
getCurrentState() {
|
|
@@ -1430,6 +1554,12 @@ function createAgentStateManager({
|
|
|
1430
1554
|
}
|
|
1431
1555
|
return deleted;
|
|
1432
1556
|
},
|
|
1557
|
+
getPersistedSlice() {
|
|
1558
|
+
return {
|
|
1559
|
+
tasks: Array.from(tasks.entries()),
|
|
1560
|
+
custom: { ...customState }
|
|
1561
|
+
};
|
|
1562
|
+
},
|
|
1433
1563
|
updateUsage(usage) {
|
|
1434
1564
|
totalInputTokens += usage.inputTokens ?? 0;
|
|
1435
1565
|
totalOutputTokens += usage.outputTokens ?? 0;
|
|
@@ -1551,22 +1681,42 @@ function defineSubagentWorkflow(config, fn) {
|
|
|
1551
1681
|
});
|
|
1552
1682
|
}
|
|
1553
1683
|
const parentHandle = workflow.getExternalWorkflowHandle(parent.workflowId);
|
|
1684
|
+
let capturedSandboxId;
|
|
1685
|
+
let capturedSnapshot;
|
|
1686
|
+
let capturedBaseSnapshot;
|
|
1687
|
+
let capturedThreadId;
|
|
1554
1688
|
const sessionInput = {
|
|
1555
1689
|
agentName: config.name,
|
|
1556
1690
|
sandboxShutdown: effectiveShutdown,
|
|
1557
1691
|
...workflowInput.thread && { thread: workflowInput.thread },
|
|
1558
1692
|
...workflowInput.sandbox && { sandbox: workflowInput.sandbox },
|
|
1559
|
-
onSandboxReady: (sandboxId) => {
|
|
1693
|
+
onSandboxReady: ({ sandboxId, baseSnapshot }) => {
|
|
1694
|
+
capturedBaseSnapshot = baseSnapshot;
|
|
1560
1695
|
const isReuse = workflowInput.sandbox?.mode === "continue";
|
|
1561
1696
|
if (!isReuse) {
|
|
1562
1697
|
void parentHandle.signal(childSandboxReadySignal, {
|
|
1563
1698
|
childWorkflowId: workflow.workflowInfo().workflowId,
|
|
1564
|
-
sandboxId
|
|
1699
|
+
sandboxId,
|
|
1700
|
+
...baseSnapshot && { baseSnapshot }
|
|
1565
1701
|
});
|
|
1566
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
|
|
1567
1718
|
}
|
|
1568
1719
|
};
|
|
1569
|
-
return fn(prompt, sessionInput, context ?? {});
|
|
1570
1720
|
};
|
|
1571
1721
|
Object.defineProperty(workflow$1, "name", { value: config.name });
|
|
1572
1722
|
return Object.assign(workflow$1, {
|
|
@@ -2336,7 +2486,6 @@ var FileSystemSkillProvider = class {
|
|
|
2336
2486
|
};
|
|
2337
2487
|
|
|
2338
2488
|
// src/lib/thread/manager.ts
|
|
2339
|
-
var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
2340
2489
|
var APPEND_IDEMPOTENT_SCRIPT = `
|
|
2341
2490
|
if redis.call('EXISTS', KEYS[1]) == 1 then
|
|
2342
2491
|
return 0
|
|
@@ -2348,8 +2497,8 @@ redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
|
|
|
2348
2497
|
redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
|
|
2349
2498
|
return 1
|
|
2350
2499
|
`;
|
|
2351
|
-
function
|
|
2352
|
-
return
|
|
2500
|
+
function getDedupKey(threadId, id) {
|
|
2501
|
+
return `dedup:${id}:thread:${threadId}`;
|
|
2353
2502
|
}
|
|
2354
2503
|
function createThreadManager(config) {
|
|
2355
2504
|
const {
|
|
@@ -2360,8 +2509,9 @@ function createThreadManager(config) {
|
|
|
2360
2509
|
deserialize = (raw) => JSON.parse(raw),
|
|
2361
2510
|
idOf
|
|
2362
2511
|
} = config;
|
|
2363
|
-
const redisKey =
|
|
2364
|
-
const metaKey =
|
|
2512
|
+
const redisKey = getThreadListKey(key, threadId);
|
|
2513
|
+
const metaKey = getThreadMetaKey(key, threadId);
|
|
2514
|
+
const stateKey = getThreadStateKey(key, threadId);
|
|
2365
2515
|
async function assertThreadExists() {
|
|
2366
2516
|
const exists = await redis.exists(metaKey);
|
|
2367
2517
|
if (!exists) {
|
|
@@ -2383,7 +2533,7 @@ function createThreadManager(config) {
|
|
|
2383
2533
|
await assertThreadExists();
|
|
2384
2534
|
if (idOf) {
|
|
2385
2535
|
const dedupId = messages.map(idOf).join(":");
|
|
2386
|
-
const dedupKey =
|
|
2536
|
+
const dedupKey = getDedupKey(threadId, dedupId);
|
|
2387
2537
|
await redis.eval(
|
|
2388
2538
|
APPEND_IDEMPOTENT_SCRIPT,
|
|
2389
2539
|
2,
|
|
@@ -2400,34 +2550,98 @@ function createThreadManager(config) {
|
|
|
2400
2550
|
async fork(newThreadId) {
|
|
2401
2551
|
await assertThreadExists();
|
|
2402
2552
|
const data = await redis.lrange(redisKey, 0, -1);
|
|
2553
|
+
const stateRaw = await redis.get(stateKey);
|
|
2403
2554
|
const forked = createThreadManager({
|
|
2404
2555
|
...config,
|
|
2405
2556
|
threadId: newThreadId
|
|
2406
2557
|
});
|
|
2407
2558
|
await forked.initialize();
|
|
2408
2559
|
if (data.length > 0) {
|
|
2409
|
-
const newKey =
|
|
2560
|
+
const newKey = getThreadListKey(key, newThreadId);
|
|
2410
2561
|
await redis.rpush(newKey, ...data);
|
|
2411
2562
|
await redis.expire(newKey, THREAD_TTL_SECONDS);
|
|
2412
2563
|
}
|
|
2564
|
+
if (stateRaw != null) {
|
|
2565
|
+
const newStateKey = getThreadStateKey(key, newThreadId);
|
|
2566
|
+
await redis.set(newStateKey, stateRaw, "EX", THREAD_TTL_SECONDS);
|
|
2567
|
+
}
|
|
2413
2568
|
return forked;
|
|
2414
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
|
+
},
|
|
2415
2591
|
async delete() {
|
|
2416
|
-
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);
|
|
2417
2610
|
},
|
|
2418
2611
|
async length() {
|
|
2419
2612
|
await assertThreadExists();
|
|
2420
2613
|
return redis.llen(redisKey);
|
|
2421
2614
|
},
|
|
2422
|
-
async
|
|
2615
|
+
async truncateFromId(messageId) {
|
|
2423
2616
|
await assertThreadExists();
|
|
2424
|
-
if (
|
|
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) {
|
|
2425
2634
|
await redis.del(redisKey);
|
|
2426
2635
|
await redis.expire(metaKey, THREAD_TTL_SECONDS);
|
|
2427
2636
|
} else {
|
|
2428
|
-
await redis.ltrim(redisKey, 0,
|
|
2637
|
+
await redis.ltrim(redisKey, 0, idx - 1);
|
|
2429
2638
|
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
2430
2639
|
}
|
|
2640
|
+
if (removedIds.length > 0) {
|
|
2641
|
+
await redis.del(
|
|
2642
|
+
...removedIds.map((id) => getDedupKey(threadId, id))
|
|
2643
|
+
);
|
|
2644
|
+
}
|
|
2431
2645
|
}
|
|
2432
2646
|
};
|
|
2433
2647
|
}
|
|
@@ -3242,11 +3456,13 @@ var toTree = async (fs, opts = {}) => {
|
|
|
3242
3456
|
return base + subtree;
|
|
3243
3457
|
};
|
|
3244
3458
|
|
|
3459
|
+
exports.DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT = DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT;
|
|
3245
3460
|
exports.FileSystemSkillProvider = FileSystemSkillProvider;
|
|
3246
3461
|
exports.NodeFsSandboxFileSystem = NodeFsSandboxFileSystem;
|
|
3247
3462
|
exports.SandboxManager = SandboxManager;
|
|
3248
3463
|
exports.SandboxNotFoundError = SandboxNotFoundError;
|
|
3249
3464
|
exports.SandboxNotSupportedError = SandboxNotSupportedError;
|
|
3465
|
+
exports.THREAD_TTL_SECONDS = THREAD_TTL_SECONDS;
|
|
3250
3466
|
exports.VirtualFileSystem = VirtualFileSystem;
|
|
3251
3467
|
exports.applyVirtualTreeMutations = applyVirtualTreeMutations;
|
|
3252
3468
|
exports.askUserQuestionTool = askUserQuestionTool;
|
|
@@ -3278,6 +3494,8 @@ exports.filesWithMimeType = filesWithMimeType;
|
|
|
3278
3494
|
exports.formatVirtualFileTree = formatVirtualFileTree;
|
|
3279
3495
|
exports.getActivityContext = getActivityContext;
|
|
3280
3496
|
exports.getShortId = getShortId;
|
|
3497
|
+
exports.getThreadListKey = getThreadListKey;
|
|
3498
|
+
exports.getThreadMetaKey = getThreadMetaKey;
|
|
3281
3499
|
exports.globHandler = globHandler;
|
|
3282
3500
|
exports.globTool = globTool;
|
|
3283
3501
|
exports.grepTool = grepTool;
|