zeitlich 0.2.36 → 0.2.37
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-Bb-nAjwQ.d.ts} +2 -2
- package/dist/{activities-hd4aNnZE.d.cts → activities-vkI4_3CC.d.cts} +2 -2
- package/dist/adapters/sandbox/bedrock/index.cjs +14 -11
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +4 -3
- package/dist/adapters/sandbox/bedrock/index.d.ts +4 -3
- package/dist/adapters/sandbox/bedrock/index.js +14 -11
- 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 +8 -0
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +2 -1
- package/dist/adapters/sandbox/daytona/index.d.ts +2 -1
- package/dist/adapters/sandbox/daytona/index.js +8 -0
- 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 +59 -10
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +5 -3
- package/dist/adapters/sandbox/e2b/index.d.ts +5 -3
- package/dist/adapters/sandbox/e2b/index.js +59 -10
- 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 +5 -0
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +2 -1
- package/dist/adapters/sandbox/inmemory/index.d.ts +2 -1
- package/dist/adapters/sandbox/inmemory/index.js +5 -0
- 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 +71 -36
- 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 +71 -36
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +5 -1
- 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 +5 -1
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +50 -25
- 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 +50 -25
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +5 -1
- 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 +5 -1
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +34 -7
- 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 +34 -7
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +5 -1
- 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 +5 -1
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +206 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -11
- package/dist/index.d.ts +17 -11
- package/dist/index.js +207 -121
- package/dist/index.js.map +1 -1
- package/dist/{proxy-BjdFGPTm.d.ts → proxy-0smGKvx8.d.ts} +1 -1
- package/dist/{proxy-7RnVaPdJ.d.cts → proxy-DEtowJyd.d.cts} +1 -1
- package/dist/{thread-manager-DjN5JYul.d.ts → thread-manager-3fszQih4.d.ts} +2 -2
- package/dist/{thread-manager-CbpiGq1L.d.ts → thread-manager-C-C4pI2z.d.ts} +2 -2
- package/dist/{thread-manager-BBzNgQWH.d.cts → thread-manager-CzYln2OC.d.cts} +2 -2
- package/dist/{thread-manager-DzXm9eeI.d.cts → thread-manager-D4vgzYrh.d.cts} +2 -2
- package/dist/{types-yiXmqedU.d.ts → types-B37hKoWA.d.ts} +1 -1
- package/dist/{types-DQ1l_gXL.d.cts → types-BO7Yju20.d.cts} +63 -14
- package/dist/{types-wiGLvxWf.d.ts → types-CNuWnvy9.d.ts} +1 -1
- package/dist/{types-CADc5V_P.d.ts → types-CPKDl-y_.d.ts} +63 -14
- package/dist/{types-Mc_4BCfT.d.cts → types-D08CXPh8.d.cts} +1 -1
- package/dist/{types-CBH54cwr.d.cts → types-DWEUmYAJ.d.cts} +1 -1
- package/dist/{types-DxCpFNv_.d.cts → types-tQL9njTu.d.cts} +25 -0
- package/dist/{types-DxCpFNv_.d.ts → types-tQL9njTu.d.ts} +25 -0
- package/dist/{workflow-P2pTSfKu.d.ts → workflow-CjXHbZZc.d.ts} +2 -2
- package/dist/{workflow-DhtWRovz.d.cts → workflow-Do_lzJpT.d.cts} +2 -2
- package/dist/workflow.cjs +182 -114
- 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 +183 -115
- package/dist/workflow.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/sandbox/bedrock/filesystem.ts +6 -12
- package/src/adapters/sandbox/bedrock/index.ts +10 -8
- package/src/adapters/sandbox/bedrock/proxy.ts +2 -0
- package/src/adapters/sandbox/daytona/index.ts +6 -0
- 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 +63 -12
- package/src/adapters/sandbox/e2b/proxy.ts +2 -0
- package/src/adapters/sandbox/inmemory/index.ts +5 -0
- package/src/adapters/sandbox/inmemory/proxy.ts +2 -0
- package/src/adapters/thread/anthropic/activities.ts +49 -26
- package/src/adapters/thread/anthropic/model-invoker.ts +15 -6
- 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 +60 -46
- package/src/adapters/thread/google-genai/activities.ts +7 -2
- package/src/adapters/thread/google-genai/model-invoker.ts +26 -8
- 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 +54 -33
- package/src/adapters/thread/langchain/activities.ts +46 -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 +3 -3
- 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 +20 -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 +9 -1
- package/src/lib/model/proxy.ts +2 -2
- package/src/lib/observability/hooks.ts +4 -5
- package/src/lib/observability/index.ts +1 -4
- package/src/lib/sandbox/manager.ts +21 -4
- 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 +35 -1
- package/src/lib/session/session-edge-cases.integration.test.ts +51 -13
- package/src/lib/session/session.integration.test.ts +139 -0
- package/src/lib/session/session.ts +50 -19
- package/src/lib/session/types.ts +13 -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 +438 -156
- 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/proxy.ts +3 -4
- package/src/lib/thread/types.ts +11 -3
- package/src/lib/tool-router/index.ts +1 -5
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +1 -1
- package/src/lib/tool-router/router.ts +3 -2
- package/src/lib/tool-router/types.ts +11 -3
- 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 +20 -7
- package/tsup.config.ts +9 -6
- package/src/lib/.env +0 -1
- package/src/tools/bash/.env +0 -1
|
@@ -3,7 +3,10 @@ import { toTree } from "./tree";
|
|
|
3
3
|
import type { SandboxFileSystem, DirentEntry } from "./types";
|
|
4
4
|
|
|
5
5
|
function createMockFs(
|
|
6
|
-
structure: Record<
|
|
6
|
+
structure: Record<
|
|
7
|
+
string,
|
|
8
|
+
{ isDir: boolean; isLink?: boolean; linkTarget?: string }
|
|
9
|
+
>
|
|
7
10
|
): SandboxFileSystem {
|
|
8
11
|
return {
|
|
9
12
|
workspaceBase: "/",
|
|
@@ -21,13 +24,17 @@ function createMockFs(
|
|
|
21
24
|
readdir: async (dir: string) => {
|
|
22
25
|
const prefix = dir.endsWith("/") ? dir : dir + "/";
|
|
23
26
|
return Object.keys(structure)
|
|
24
|
-
.filter(
|
|
27
|
+
.filter(
|
|
28
|
+
(p) => p.startsWith(prefix) && !p.slice(prefix.length).includes("/")
|
|
29
|
+
)
|
|
25
30
|
.map((p) => p.slice(prefix.length));
|
|
26
31
|
},
|
|
27
32
|
readdirWithFileTypes: async (dir: string): Promise<DirentEntry[]> => {
|
|
28
33
|
const prefix = dir.endsWith("/") ? dir : dir + "/";
|
|
29
34
|
return Object.entries(structure)
|
|
30
|
-
.filter(
|
|
35
|
+
.filter(
|
|
36
|
+
([p]) => p.startsWith(prefix) && !p.slice(prefix.length).includes("/")
|
|
37
|
+
)
|
|
31
38
|
.map(([p, meta]) => ({
|
|
32
39
|
name: p.slice(prefix.length),
|
|
33
40
|
isFile: !meta.isDir && !meta.isLink,
|
package/src/lib/sandbox/types.ts
CHANGED
|
@@ -17,6 +17,21 @@ export interface FileStat {
|
|
|
17
17
|
mtime: Date;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Network & lifecycle
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
export interface SandboxNetworkConfig {
|
|
25
|
+
allowOut?: string[];
|
|
26
|
+
denyOut?: string[];
|
|
27
|
+
allowPublicTraffic?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface SandboxLifecycleConfig {
|
|
31
|
+
onTimeout: "kill" | "pause";
|
|
32
|
+
autoResume?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
/**
|
|
21
36
|
* Provider-agnostic filesystem interface.
|
|
22
37
|
*
|
|
@@ -114,6 +129,16 @@ export interface SandboxCreateOptions {
|
|
|
114
129
|
initialFiles?: Record<string, string | Uint8Array>;
|
|
115
130
|
/** Environment variables available inside the sandbox */
|
|
116
131
|
env?: Record<string, string>;
|
|
132
|
+
/** Key-value metadata surfaced via provider list/query APIs */
|
|
133
|
+
metadata?: Record<string, string>;
|
|
134
|
+
/** Sandbox idle timeout in milliseconds */
|
|
135
|
+
timeoutMs?: number;
|
|
136
|
+
/** Enable or disable outbound internet access */
|
|
137
|
+
allowInternetAccess?: boolean;
|
|
138
|
+
/** Outbound network allow/deny rules */
|
|
139
|
+
network?: SandboxNetworkConfig;
|
|
140
|
+
/** Sandbox timeout behaviour */
|
|
141
|
+
lifecycle?: SandboxLifecycleConfig;
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
export interface SandboxCreateResult {
|
|
@@ -135,6 +160,8 @@ export interface SandboxProvider<
|
|
|
135
160
|
resume(sandboxId: string): Promise<void>;
|
|
136
161
|
snapshot(sandboxId: string): Promise<SandboxSnapshot>;
|
|
137
162
|
restore(snapshot: SandboxSnapshot): Promise<Sandbox>;
|
|
163
|
+
/** Delete a previously captured snapshot. No-op if already deleted. */
|
|
164
|
+
deleteSnapshot(snapshot: SandboxSnapshot): Promise<void>;
|
|
138
165
|
fork(sandboxId: string): Promise<Sandbox>;
|
|
139
166
|
}
|
|
140
167
|
|
|
@@ -155,6 +182,10 @@ export interface SandboxOps<
|
|
|
155
182
|
/** Resume a paused sandbox. No-op if already running. */
|
|
156
183
|
resumeSandbox(sandboxId: string): Promise<void>;
|
|
157
184
|
snapshotSandbox(sandboxId: string): Promise<SandboxSnapshot>;
|
|
185
|
+
/** Create a fresh sandbox from a previously captured snapshot. */
|
|
186
|
+
restoreSandbox(snapshot: SandboxSnapshot): Promise<string>;
|
|
187
|
+
/** Delete a previously captured snapshot. No-op if already deleted. */
|
|
188
|
+
deleteSandboxSnapshot(snapshot: SandboxSnapshot): Promise<void>;
|
|
158
189
|
forkSandbox(sandboxId: string): Promise<string>;
|
|
159
190
|
}
|
|
160
191
|
|
|
@@ -172,7 +203,10 @@ export type PrefixedSandboxOps<
|
|
|
172
203
|
TOptions extends SandboxCreateOptions = SandboxCreateOptions,
|
|
173
204
|
TCtx = unknown,
|
|
174
205
|
> = {
|
|
175
|
-
[K in keyof SandboxOps<
|
|
206
|
+
[K in keyof SandboxOps<
|
|
207
|
+
TOptions,
|
|
208
|
+
TCtx
|
|
209
|
+
> as `${TPrefix}${Capitalize<K & string>}`]: SandboxOps<TOptions, TCtx>[K];
|
|
176
210
|
};
|
|
177
211
|
|
|
178
212
|
// ============================================================================
|
|
@@ -42,7 +42,13 @@ vi.mock("@temporalio/workflow", () => {
|
|
|
42
42
|
uuid4: () =>
|
|
43
43
|
`00000000-0000-0000-0000-${String(++idCounter).padStart(12, "0")}`,
|
|
44
44
|
ApplicationFailure: MockApplicationFailure,
|
|
45
|
-
log: {
|
|
45
|
+
log: {
|
|
46
|
+
trace: () => {},
|
|
47
|
+
debug: () => {},
|
|
48
|
+
info: () => {},
|
|
49
|
+
warn: () => {},
|
|
50
|
+
error: () => {},
|
|
51
|
+
},
|
|
46
52
|
};
|
|
47
53
|
});
|
|
48
54
|
|
|
@@ -61,7 +67,9 @@ type TurnScript = {
|
|
|
61
67
|
* Wraps every method on a ThreadOps object so it also has `.executeWithOptions()`,
|
|
62
68
|
* matching Temporal's `ActivityInterfaceFor<ThreadOps>` shape.
|
|
63
69
|
*/
|
|
64
|
-
function toActivityInterface<TContent = string>(
|
|
70
|
+
function toActivityInterface<TContent = string>(
|
|
71
|
+
raw: ThreadOps<TContent>
|
|
72
|
+
): ActivityInterfaceFor<ThreadOps<TContent>> {
|
|
65
73
|
const result = {} as Record<string, unknown>;
|
|
66
74
|
for (const [key, fn] of Object.entries(raw)) {
|
|
67
75
|
const wrapped = (...args: unknown[]) =>
|
|
@@ -433,6 +441,8 @@ describe("createSession edge cases", () => {
|
|
|
433
441
|
createdAt: new Date().toISOString(),
|
|
434
442
|
}),
|
|
435
443
|
forkSandbox: async () => "forked-sandbox-id",
|
|
444
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
445
|
+
deleteSandboxSnapshot: async () => {},
|
|
436
446
|
pauseSandbox: async () => {},
|
|
437
447
|
resumeSandbox: async () => {},
|
|
438
448
|
};
|
|
@@ -476,6 +486,8 @@ describe("createSession edge cases", () => {
|
|
|
476
486
|
createdAt: new Date().toISOString(),
|
|
477
487
|
}),
|
|
478
488
|
forkSandbox: async () => "forked-sandbox-id",
|
|
489
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
490
|
+
deleteSandboxSnapshot: async () => {},
|
|
479
491
|
pauseSandbox: async () => {},
|
|
480
492
|
resumeSandbox: async () => {},
|
|
481
493
|
};
|
|
@@ -765,7 +777,11 @@ describe("createSession edge cases", () => {
|
|
|
765
777
|
},
|
|
766
778
|
});
|
|
767
779
|
|
|
768
|
-
const session = await createSession<
|
|
780
|
+
const session = await createSession<
|
|
781
|
+
Record<string, never>,
|
|
782
|
+
unknown,
|
|
783
|
+
TestContent
|
|
784
|
+
>({
|
|
769
785
|
agentName: "TestAgent",
|
|
770
786
|
thread: { mode: "new", threadId: "thread-1" },
|
|
771
787
|
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
@@ -940,6 +956,8 @@ describe("createSession edge cases", () => {
|
|
|
940
956
|
destroySandbox: async () => {},
|
|
941
957
|
snapshotSandbox: snapshotSpy,
|
|
942
958
|
forkSandbox: async () => "forked-sandbox-id",
|
|
959
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
960
|
+
deleteSandboxSnapshot: async () => {},
|
|
943
961
|
pauseSandbox: async () => {},
|
|
944
962
|
resumeSandbox: async () => {},
|
|
945
963
|
};
|
|
@@ -1040,6 +1058,8 @@ describe("createSession edge cases", () => {
|
|
|
1040
1058
|
createdAt: new Date().toISOString(),
|
|
1041
1059
|
}),
|
|
1042
1060
|
forkSandbox: async () => "forked-sb",
|
|
1061
|
+
restoreSandbox: async () => "restored-sb",
|
|
1062
|
+
deleteSandboxSnapshot: async () => {},
|
|
1043
1063
|
};
|
|
1044
1064
|
|
|
1045
1065
|
const session = await createSession({
|
|
@@ -1074,6 +1094,8 @@ describe("createSession edge cases", () => {
|
|
|
1074
1094
|
createdAt: new Date().toISOString(),
|
|
1075
1095
|
}),
|
|
1076
1096
|
forkSandbox: async () => "forked-sb",
|
|
1097
|
+
restoreSandbox: async () => "restored-sb",
|
|
1098
|
+
deleteSandboxSnapshot: async () => {},
|
|
1077
1099
|
};
|
|
1078
1100
|
|
|
1079
1101
|
const session = await createSession({
|
|
@@ -1119,6 +1141,8 @@ describe("createSession edge cases", () => {
|
|
|
1119
1141
|
createdAt: new Date().toISOString(),
|
|
1120
1142
|
}),
|
|
1121
1143
|
forkSandbox: async () => "forked-sb",
|
|
1144
|
+
restoreSandbox: async () => "restored-sb",
|
|
1145
|
+
deleteSandboxSnapshot: async () => {},
|
|
1122
1146
|
};
|
|
1123
1147
|
|
|
1124
1148
|
const session = await createSession({
|
|
@@ -1166,6 +1190,8 @@ describe("createSession edge cases", () => {
|
|
|
1166
1190
|
sandboxLog.push(`fork:${id}`);
|
|
1167
1191
|
return `forked-from-${id}`;
|
|
1168
1192
|
},
|
|
1193
|
+
restoreSandbox: async () => "restored-sb",
|
|
1194
|
+
deleteSandboxSnapshot: async () => {},
|
|
1169
1195
|
};
|
|
1170
1196
|
|
|
1171
1197
|
const session = await createSession({
|
|
@@ -1186,7 +1212,9 @@ describe("createSession edge cases", () => {
|
|
|
1186
1212
|
|
|
1187
1213
|
expect(sandboxLog).toContain("fork:paused-sb-1");
|
|
1188
1214
|
expect(sandboxLog).not.toContain("create");
|
|
1189
|
-
expect((result as { sandboxId?: string }).sandboxId).toBe(
|
|
1215
|
+
expect((result as { sandboxId?: string }).sandboxId).toBe(
|
|
1216
|
+
"forked-from-paused-sb-1"
|
|
1217
|
+
);
|
|
1190
1218
|
expect(sandboxLog).toContain("destroy:forked-from-paused-sb-1");
|
|
1191
1219
|
});
|
|
1192
1220
|
|
|
@@ -1210,6 +1238,8 @@ describe("createSession edge cases", () => {
|
|
|
1210
1238
|
createdAt: new Date().toISOString(),
|
|
1211
1239
|
}),
|
|
1212
1240
|
forkSandbox: async () => "forked-sb",
|
|
1241
|
+
restoreSandbox: async () => "restored-sb",
|
|
1242
|
+
deleteSandboxSnapshot: async () => {},
|
|
1213
1243
|
};
|
|
1214
1244
|
|
|
1215
1245
|
const session = await createSession({
|
|
@@ -1253,6 +1283,8 @@ describe("createSession edge cases", () => {
|
|
|
1253
1283
|
createdAt: new Date().toISOString(),
|
|
1254
1284
|
}),
|
|
1255
1285
|
forkSandbox: async () => "forked-sb",
|
|
1286
|
+
restoreSandbox: async () => "restored-sb",
|
|
1287
|
+
deleteSandboxSnapshot: async () => {},
|
|
1256
1288
|
};
|
|
1257
1289
|
|
|
1258
1290
|
const session = await createSession({
|
|
@@ -1297,6 +1329,8 @@ describe("createSession edge cases", () => {
|
|
|
1297
1329
|
createdAt: new Date().toISOString(),
|
|
1298
1330
|
}),
|
|
1299
1331
|
forkSandbox: async () => "forked-sb",
|
|
1332
|
+
restoreSandbox: async () => "restored-sb",
|
|
1333
|
+
deleteSandboxSnapshot: async () => {},
|
|
1300
1334
|
};
|
|
1301
1335
|
|
|
1302
1336
|
const session = await createSession({
|
|
@@ -1370,9 +1404,7 @@ describe("createSession edge cases", () => {
|
|
|
1370
1404
|
|
|
1371
1405
|
const session = await createSession({
|
|
1372
1406
|
agentName: "TestAgent",
|
|
1373
|
-
runAgent: createScriptedRunAgent([
|
|
1374
|
-
{ message: "done", toolCalls: [] },
|
|
1375
|
-
]),
|
|
1407
|
+
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
1376
1408
|
threadOps: ops,
|
|
1377
1409
|
buildContextMessage: () => "go",
|
|
1378
1410
|
});
|
|
@@ -1413,6 +1445,8 @@ describe("createSession edge cases", () => {
|
|
|
1413
1445
|
createdAt: new Date().toISOString(),
|
|
1414
1446
|
}),
|
|
1415
1447
|
forkSandbox: async () => "forked-sb",
|
|
1448
|
+
restoreSandbox: async () => "restored-sb",
|
|
1449
|
+
deleteSandboxSnapshot: async () => {},
|
|
1416
1450
|
};
|
|
1417
1451
|
|
|
1418
1452
|
const session = await createSession({
|
|
@@ -1431,9 +1465,7 @@ describe("createSession edge cases", () => {
|
|
|
1431
1465
|
initialState: { systemPrompt: "test" },
|
|
1432
1466
|
});
|
|
1433
1467
|
|
|
1434
|
-
await expect(session.runSession({ stateManager })).rejects.toThrow(
|
|
1435
|
-
"crash"
|
|
1436
|
-
);
|
|
1468
|
+
await expect(session.runSession({ stateManager })).rejects.toThrow("crash");
|
|
1437
1469
|
|
|
1438
1470
|
expect(sandboxLog).toContain("pause:sb-err");
|
|
1439
1471
|
expect(sandboxLog).not.toContain("destroy:sb-err");
|
|
@@ -1461,6 +1493,8 @@ describe("createSession edge cases", () => {
|
|
|
1461
1493
|
createdAt: new Date().toISOString(),
|
|
1462
1494
|
}),
|
|
1463
1495
|
forkSandbox: async () => "forked-sb",
|
|
1496
|
+
restoreSandbox: async () => "restored-sb",
|
|
1497
|
+
deleteSandboxSnapshot: async () => {},
|
|
1464
1498
|
};
|
|
1465
1499
|
|
|
1466
1500
|
const session = await createSession({
|
|
@@ -1503,6 +1537,8 @@ describe("createSession edge cases", () => {
|
|
|
1503
1537
|
createdAt: new Date().toISOString(),
|
|
1504
1538
|
}),
|
|
1505
1539
|
forkSandbox: async () => "forked-sb",
|
|
1540
|
+
restoreSandbox: async () => "restored-sb",
|
|
1541
|
+
deleteSandboxSnapshot: async () => {},
|
|
1506
1542
|
};
|
|
1507
1543
|
|
|
1508
1544
|
const session = await createSession({
|
|
@@ -1521,9 +1557,7 @@ describe("createSession edge cases", () => {
|
|
|
1521
1557
|
initialState: { systemPrompt: "test" },
|
|
1522
1558
|
});
|
|
1523
1559
|
|
|
1524
|
-
await expect(session.runSession({ stateManager })).rejects.toThrow(
|
|
1525
|
-
"crash"
|
|
1526
|
-
);
|
|
1560
|
+
await expect(session.runSession({ stateManager })).rejects.toThrow("crash");
|
|
1527
1561
|
|
|
1528
1562
|
expect(sandboxLog).not.toContain("pause:sb-keep-err");
|
|
1529
1563
|
expect(sandboxLog).not.toContain("destroy:sb-keep-err");
|
|
@@ -1553,6 +1587,8 @@ describe("createSession edge cases", () => {
|
|
|
1553
1587
|
createdAt: new Date().toISOString(),
|
|
1554
1588
|
}),
|
|
1555
1589
|
forkSandbox: async () => "forked-sb",
|
|
1590
|
+
restoreSandbox: async () => "restored-sb",
|
|
1591
|
+
deleteSandboxSnapshot: async () => {},
|
|
1556
1592
|
};
|
|
1557
1593
|
|
|
1558
1594
|
const session = await createSession({
|
|
@@ -1598,6 +1634,8 @@ describe("createSession edge cases", () => {
|
|
|
1598
1634
|
createdAt: new Date().toISOString(),
|
|
1599
1635
|
}),
|
|
1600
1636
|
forkSandbox: async () => "forked-sb",
|
|
1637
|
+
restoreSandbox: async () => "restored-sb",
|
|
1638
|
+
deleteSandboxSnapshot: async () => {},
|
|
1601
1639
|
};
|
|
1602
1640
|
|
|
1603
1641
|
const session = await createSession({
|
|
@@ -517,6 +517,8 @@ describe("createSession integration", () => {
|
|
|
517
517
|
createdAt: new Date().toISOString(),
|
|
518
518
|
}),
|
|
519
519
|
forkSandbox: async () => "forked-sandbox-id",
|
|
520
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
521
|
+
deleteSandboxSnapshot: async () => {},
|
|
520
522
|
pauseSandbox: async () => {},
|
|
521
523
|
resumeSandbox: async () => {},
|
|
522
524
|
};
|
|
@@ -559,6 +561,8 @@ describe("createSession integration", () => {
|
|
|
559
561
|
createdAt: new Date().toISOString(),
|
|
560
562
|
}),
|
|
561
563
|
forkSandbox: async () => "forked-sandbox-id",
|
|
564
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
565
|
+
deleteSandboxSnapshot: async () => {},
|
|
562
566
|
pauseSandbox: async () => {},
|
|
563
567
|
resumeSandbox: async () => {},
|
|
564
568
|
};
|
|
@@ -610,6 +614,8 @@ describe("createSession integration", () => {
|
|
|
610
614
|
createdAt: new Date().toISOString(),
|
|
611
615
|
}),
|
|
612
616
|
forkSandbox: async () => "forked-sb",
|
|
617
|
+
restoreSandbox: async () => "restored-sb",
|
|
618
|
+
deleteSandboxSnapshot: async () => {},
|
|
613
619
|
};
|
|
614
620
|
|
|
615
621
|
const session = await createSession({
|
|
@@ -822,6 +828,8 @@ describe("createSession integration", () => {
|
|
|
822
828
|
createdAt: new Date().toISOString(),
|
|
823
829
|
}),
|
|
824
830
|
forkSandbox: async () => "forked-sandbox-id",
|
|
831
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
832
|
+
deleteSandboxSnapshot: async () => {},
|
|
825
833
|
pauseSandbox: async () => {},
|
|
826
834
|
resumeSandbox: async () => {},
|
|
827
835
|
};
|
|
@@ -873,6 +881,8 @@ describe("createSession integration", () => {
|
|
|
873
881
|
createdAt: new Date().toISOString(),
|
|
874
882
|
}),
|
|
875
883
|
forkSandbox: async () => "forked-sandbox-id",
|
|
884
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
885
|
+
deleteSandboxSnapshot: async () => {},
|
|
876
886
|
pauseSandbox: async () => {},
|
|
877
887
|
resumeSandbox: async () => {},
|
|
878
888
|
};
|
|
@@ -949,4 +959,133 @@ describe("createSession integration", () => {
|
|
|
949
959
|
expect(result.usage.totalInputTokens).toBe(180);
|
|
950
960
|
expect(result.usage.totalOutputTokens).toBe(90);
|
|
951
961
|
});
|
|
962
|
+
|
|
963
|
+
// --- Snapshot-driven shutdown ---
|
|
964
|
+
|
|
965
|
+
it("captures base + exit snapshot and destroys sandbox on sandboxShutdown=snapshot", async () => {
|
|
966
|
+
const { ops } = createMockThreadOps();
|
|
967
|
+
const sandboxLog: string[] = [];
|
|
968
|
+
let snapCounter = 0;
|
|
969
|
+
|
|
970
|
+
const sandboxOps: SandboxOps = {
|
|
971
|
+
createSandbox: async () => {
|
|
972
|
+
sandboxLog.push("create");
|
|
973
|
+
return { sandboxId: "sb-snap" };
|
|
974
|
+
},
|
|
975
|
+
destroySandbox: async (id: string) => {
|
|
976
|
+
sandboxLog.push(`destroy:${id}`);
|
|
977
|
+
},
|
|
978
|
+
pauseSandbox: async () => {
|
|
979
|
+
sandboxLog.push("pause");
|
|
980
|
+
},
|
|
981
|
+
resumeSandbox: async () => {},
|
|
982
|
+
snapshotSandbox: async (id: string) => {
|
|
983
|
+
snapCounter += 1;
|
|
984
|
+
sandboxLog.push(`snapshot:${id}`);
|
|
985
|
+
return {
|
|
986
|
+
sandboxId: id,
|
|
987
|
+
providerId: "test",
|
|
988
|
+
data: { tag: `snap-${snapCounter}` },
|
|
989
|
+
createdAt: new Date().toISOString(),
|
|
990
|
+
};
|
|
991
|
+
},
|
|
992
|
+
restoreSandbox: async () => "restored-sb",
|
|
993
|
+
deleteSandboxSnapshot: async () => {},
|
|
994
|
+
forkSandbox: async () => "forked-sb",
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
const session = await createSession({
|
|
998
|
+
agentName: "TestAgent",
|
|
999
|
+
thread: { mode: "new", threadId: "thread-snap" },
|
|
1000
|
+
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
1001
|
+
threadOps: ops,
|
|
1002
|
+
buildContextMessage: () => "go",
|
|
1003
|
+
sandboxOps,
|
|
1004
|
+
sandboxShutdown: "snapshot",
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
const stateManager = createAgentStateManager({
|
|
1008
|
+
initialState: { systemPrompt: "test" },
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
const result = await session.runSession({ stateManager });
|
|
1012
|
+
|
|
1013
|
+
expect(result.exitReason).toBe("completed");
|
|
1014
|
+
expect(result.sandboxId).toBe("sb-snap");
|
|
1015
|
+
expect(result.baseSnapshot?.data).toEqual({ tag: "snap-1" });
|
|
1016
|
+
expect(result.snapshot?.data).toEqual({ tag: "snap-2" });
|
|
1017
|
+
expect(sandboxLog).toEqual([
|
|
1018
|
+
"create",
|
|
1019
|
+
"snapshot:sb-snap",
|
|
1020
|
+
"snapshot:sb-snap",
|
|
1021
|
+
"destroy:sb-snap",
|
|
1022
|
+
]);
|
|
1023
|
+
expect(sandboxLog).not.toContain("pause");
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
it("restores a sandbox when sandbox.mode=from-snapshot and skips base snapshot", async () => {
|
|
1027
|
+
const { ops } = createMockThreadOps();
|
|
1028
|
+
const sandboxLog: string[] = [];
|
|
1029
|
+
const priorSnapshot = {
|
|
1030
|
+
sandboxId: "sb-prior",
|
|
1031
|
+
providerId: "test",
|
|
1032
|
+
data: { tag: "prior" },
|
|
1033
|
+
createdAt: new Date().toISOString(),
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
const sandboxOps: SandboxOps = {
|
|
1037
|
+
createSandbox: async () => {
|
|
1038
|
+
sandboxLog.push("create");
|
|
1039
|
+
return { sandboxId: "sb-should-not-be-created" };
|
|
1040
|
+
},
|
|
1041
|
+
destroySandbox: async (id: string) => {
|
|
1042
|
+
sandboxLog.push(`destroy:${id}`);
|
|
1043
|
+
},
|
|
1044
|
+
pauseSandbox: async () => {},
|
|
1045
|
+
resumeSandbox: async () => {},
|
|
1046
|
+
snapshotSandbox: async (id: string) => {
|
|
1047
|
+
sandboxLog.push(`snapshot:${id}`);
|
|
1048
|
+
return {
|
|
1049
|
+
sandboxId: id,
|
|
1050
|
+
providerId: "test",
|
|
1051
|
+
data: { tag: "exit" },
|
|
1052
|
+
createdAt: new Date().toISOString(),
|
|
1053
|
+
};
|
|
1054
|
+
},
|
|
1055
|
+
restoreSandbox: async (snap) => {
|
|
1056
|
+
sandboxLog.push(`restore:${(snap.data as { tag: string }).tag}`);
|
|
1057
|
+
return "sb-restored";
|
|
1058
|
+
},
|
|
1059
|
+
deleteSandboxSnapshot: async () => {},
|
|
1060
|
+
forkSandbox: async () => "forked-sb",
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
const session = await createSession({
|
|
1064
|
+
agentName: "TestAgent",
|
|
1065
|
+
thread: { mode: "new", threadId: "thread-restore" },
|
|
1066
|
+
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
1067
|
+
threadOps: ops,
|
|
1068
|
+
buildContextMessage: () => "go",
|
|
1069
|
+
sandboxOps,
|
|
1070
|
+
sandbox: { mode: "from-snapshot", snapshot: priorSnapshot },
|
|
1071
|
+
sandboxShutdown: "snapshot",
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
const stateManager = createAgentStateManager({
|
|
1075
|
+
initialState: { systemPrompt: "test" },
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
const result = await session.runSession({ stateManager });
|
|
1079
|
+
|
|
1080
|
+
expect(result.sandboxId).toBe("sb-restored");
|
|
1081
|
+
// No base snapshot because the sandbox was restored, not freshly created.
|
|
1082
|
+
expect(result.baseSnapshot).toBeUndefined();
|
|
1083
|
+
expect(result.snapshot?.data).toEqual({ tag: "exit" });
|
|
1084
|
+
expect(sandboxLog).toEqual([
|
|
1085
|
+
"restore:prior",
|
|
1086
|
+
"snapshot:sb-restored",
|
|
1087
|
+
"destroy:sb-restored",
|
|
1088
|
+
]);
|
|
1089
|
+
expect(sandboxLog).not.toContain("create");
|
|
1090
|
+
});
|
|
952
1091
|
});
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "@temporalio/workflow";
|
|
8
8
|
import type { SessionExitReason } from "../types";
|
|
9
9
|
import type { SessionConfig, ZeitlichSession } from "./types";
|
|
10
|
-
import type { SandboxOps } from "../sandbox/types";
|
|
10
|
+
import type { SandboxOps, SandboxSnapshot } from "../sandbox/types";
|
|
11
11
|
import type {
|
|
12
12
|
AgentState,
|
|
13
13
|
AgentStateManager,
|
|
@@ -146,12 +146,14 @@ export async function createSession<
|
|
|
146
146
|
|
|
147
147
|
const plugins: ToolMap[string][] = [];
|
|
148
148
|
let destroySubagentSandboxes: (() => Promise<void>) | undefined;
|
|
149
|
+
let cleanupSubagentSnapshots: (() => Promise<void>) | undefined;
|
|
149
150
|
|
|
150
151
|
if (subagents) {
|
|
151
152
|
const result = buildSubagentRegistration(subagents);
|
|
152
153
|
if (result) {
|
|
153
154
|
plugins.push(result.registration);
|
|
154
155
|
destroySubagentSandboxes = result.destroySubagentSandboxes;
|
|
156
|
+
cleanupSubagentSnapshots = result.cleanupSubagentSnapshots;
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
159
|
if (skills) {
|
|
@@ -210,10 +212,13 @@ export async function createSession<
|
|
|
210
212
|
}
|
|
211
213
|
);
|
|
212
214
|
|
|
213
|
-
// --- Sandbox lifecycle: create, continue, fork, or inherit
|
|
215
|
+
// --- Sandbox lifecycle: create, continue, fork, from-snapshot, or inherit ---
|
|
214
216
|
const sandboxMode = sandboxInit?.mode;
|
|
215
217
|
let sandboxId: string | undefined;
|
|
216
218
|
let sandboxOwned = false;
|
|
219
|
+
let baseSnapshot: SandboxSnapshot | undefined;
|
|
220
|
+
let exitSnapshot: SandboxSnapshot | undefined;
|
|
221
|
+
let freshlyCreated = false;
|
|
217
222
|
|
|
218
223
|
if (sandboxMode === "inherit") {
|
|
219
224
|
const inheritInit = sandboxInit as {
|
|
@@ -252,6 +257,18 @@ export async function createSession<
|
|
|
252
257
|
(sandboxInit as { mode: "fork"; sandboxId: string }).sandboxId
|
|
253
258
|
);
|
|
254
259
|
sandboxOwned = true;
|
|
260
|
+
} else if (sandboxMode === "from-snapshot") {
|
|
261
|
+
if (!sandboxOps) {
|
|
262
|
+
throw ApplicationFailure.create({
|
|
263
|
+
message: "No sandboxOps provided — cannot restore sandbox",
|
|
264
|
+
nonRetryable: true,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
const snap = (
|
|
268
|
+
sandboxInit as { mode: "from-snapshot"; snapshot: SandboxSnapshot }
|
|
269
|
+
).snapshot;
|
|
270
|
+
sandboxId = await sandboxOps.restoreSandbox(snap);
|
|
271
|
+
sandboxOwned = true;
|
|
255
272
|
} else if (sandboxOps) {
|
|
256
273
|
const skillFiles = skills ? collectSkillFiles(skills) : undefined;
|
|
257
274
|
const ctx = (sandboxInit as { mode: "new"; ctx?: unknown } | undefined)
|
|
@@ -263,10 +280,24 @@ export async function createSession<
|
|
|
263
280
|
if (result) {
|
|
264
281
|
sandboxId = result.sandboxId;
|
|
265
282
|
sandboxOwned = true;
|
|
283
|
+
freshlyCreated = true;
|
|
266
284
|
}
|
|
267
285
|
}
|
|
268
286
|
|
|
269
|
-
|
|
287
|
+
// Capture a base snapshot immediately after seeding so it can be reused
|
|
288
|
+
// as a template for future runs that want to skip the (potentially
|
|
289
|
+
// expensive) seed step.
|
|
290
|
+
if (
|
|
291
|
+
sandboxId &&
|
|
292
|
+
sandboxOwned &&
|
|
293
|
+
freshlyCreated &&
|
|
294
|
+
sandboxShutdown === "snapshot" &&
|
|
295
|
+
sandboxOps
|
|
296
|
+
) {
|
|
297
|
+
baseSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (sandboxId && sandboxOwned && onSandboxReady) {
|
|
270
301
|
onSandboxReady(sandboxId);
|
|
271
302
|
}
|
|
272
303
|
|
|
@@ -347,6 +378,7 @@ export async function createSession<
|
|
|
347
378
|
);
|
|
348
379
|
|
|
349
380
|
let exitReason: SessionExitReason = "completed";
|
|
381
|
+
let finalMessage: M | null = null;
|
|
350
382
|
|
|
351
383
|
try {
|
|
352
384
|
while (
|
|
@@ -385,21 +417,8 @@ export async function createSession<
|
|
|
385
417
|
if (!toolRouter.hasTools() || rawToolCalls.length === 0) {
|
|
386
418
|
stateManager.complete();
|
|
387
419
|
exitReason = "completed";
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
threadId,
|
|
391
|
-
exitReason,
|
|
392
|
-
turns: currentTurn,
|
|
393
|
-
durationMs: Date.now() - sessionStartMs,
|
|
394
|
-
usage: stateManager.getTotalUsage(),
|
|
395
|
-
});
|
|
396
|
-
return {
|
|
397
|
-
threadId,
|
|
398
|
-
finalMessage: message,
|
|
399
|
-
exitReason,
|
|
400
|
-
usage: stateManager.getTotalUsage(),
|
|
401
|
-
sandboxId,
|
|
402
|
-
} as Awaited<ReturnType<ZeitlichSession<M, boolean>["runSession"]>>;
|
|
420
|
+
finalMessage = message;
|
|
421
|
+
break;
|
|
403
422
|
}
|
|
404
423
|
|
|
405
424
|
const parsedToolCalls: ParsedToolCallUnion<T>[] = [];
|
|
@@ -480,12 +499,20 @@ export async function createSession<
|
|
|
480
499
|
case "keep":
|
|
481
500
|
case "keep-until-parent-close":
|
|
482
501
|
break;
|
|
502
|
+
case "snapshot":
|
|
503
|
+
exitSnapshot = await sandboxOps.snapshotSandbox(sandboxId);
|
|
504
|
+
await sandboxOps.destroySandbox(sandboxId);
|
|
505
|
+
break;
|
|
483
506
|
}
|
|
484
507
|
}
|
|
485
508
|
|
|
486
509
|
if (destroySubagentSandboxes) {
|
|
487
510
|
await destroySubagentSandboxes();
|
|
488
511
|
}
|
|
512
|
+
|
|
513
|
+
if (cleanupSubagentSnapshots) {
|
|
514
|
+
await cleanupSubagentSnapshots();
|
|
515
|
+
}
|
|
489
516
|
}
|
|
490
517
|
|
|
491
518
|
log.info("session ended", {
|
|
@@ -495,14 +522,18 @@ export async function createSession<
|
|
|
495
522
|
turns: stateManager.getTurns(),
|
|
496
523
|
durationMs: Date.now() - sessionStartMs,
|
|
497
524
|
usage: stateManager.getTotalUsage(),
|
|
525
|
+
...(baseSnapshot && { hasBaseSnapshot: true }),
|
|
526
|
+
...(exitSnapshot && { hasExitSnapshot: true }),
|
|
498
527
|
});
|
|
499
528
|
|
|
500
529
|
return {
|
|
501
530
|
threadId,
|
|
502
|
-
finalMessage
|
|
531
|
+
finalMessage,
|
|
503
532
|
exitReason,
|
|
504
533
|
usage: stateManager.getTotalUsage(),
|
|
505
534
|
sandboxId,
|
|
535
|
+
...(baseSnapshot && { baseSnapshot }),
|
|
536
|
+
...(exitSnapshot && { snapshot: exitSnapshot }),
|
|
506
537
|
} as Awaited<ReturnType<ZeitlichSession<M, boolean>["runSession"]>>;
|
|
507
538
|
},
|
|
508
539
|
};
|
package/src/lib/session/types.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { Duration } from "@temporalio/common";
|
|
2
|
-
import type {
|
|
3
|
-
SessionExitReason,
|
|
4
|
-
ToolResultConfig,
|
|
5
|
-
} from "../types";
|
|
2
|
+
import type { SessionExitReason, ToolResultConfig } from "../types";
|
|
6
3
|
import type {
|
|
7
4
|
ToolMap,
|
|
8
5
|
ToolCallResultUnion,
|
|
@@ -11,7 +8,7 @@ import type {
|
|
|
11
8
|
import type { Hooks } from "../hooks/types";
|
|
12
9
|
import type { SubagentConfig } from "../subagent/types";
|
|
13
10
|
import type { Skill } from "../skills/types";
|
|
14
|
-
import type { SandboxOps } from "../sandbox/types";
|
|
11
|
+
import type { SandboxOps, SandboxSnapshot } from "../sandbox/types";
|
|
15
12
|
import type { VirtualFsOps } from "../virtual-fs/types";
|
|
16
13
|
import type { RunAgentActivity } from "../model/types";
|
|
17
14
|
import type { AgentStateManager, JsonSerializable } from "../state/types";
|
|
@@ -219,6 +216,17 @@ export type SessionResult<
|
|
|
219
216
|
finalMessage: M | null;
|
|
220
217
|
exitReason: SessionExitReason;
|
|
221
218
|
usage: ReturnType<AgentStateManager<TState>["getTotalUsage"]>;
|
|
219
|
+
/**
|
|
220
|
+
* Snapshot captured on exit when `sandboxShutdown === "snapshot"`.
|
|
221
|
+
*/
|
|
222
|
+
snapshot?: SandboxSnapshot;
|
|
223
|
+
/**
|
|
224
|
+
* Snapshot captured immediately after sandbox seeding (before the agent
|
|
225
|
+
* loop starts) when `sandbox.mode === "new"` and
|
|
226
|
+
* `sandboxShutdown === "snapshot"`. Intended as a reusable "base" for new
|
|
227
|
+
* threads that want to skip re-seeding.
|
|
228
|
+
*/
|
|
229
|
+
baseSnapshot?: SandboxSnapshot;
|
|
222
230
|
} & (HasSandbox extends true
|
|
223
231
|
? { sandboxId: string }
|
|
224
232
|
: { sandboxId?: undefined });
|