zeitlich 0.2.36 → 0.2.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -92
- package/dist/{activities-BVI2lTwr.d.ts → activities-BKhMtKDd.d.ts} +4 -2
- package/dist/{activities-hd4aNnZE.d.cts → activities-CDcwkRZs.d.cts} +4 -2
- package/dist/adapters/sandbox/bedrock/index.cjs +17 -14
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +7 -6
- package/dist/adapters/sandbox/bedrock/index.d.ts +7 -6
- package/dist/adapters/sandbox/bedrock/index.js +17 -14
- package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.cjs +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
- package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
- package/dist/adapters/sandbox/bedrock/workflow.js +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.js.map +1 -1
- package/dist/adapters/sandbox/daytona/index.cjs +11 -3
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +5 -4
- package/dist/adapters/sandbox/daytona/index.d.ts +5 -4
- package/dist/adapters/sandbox/daytona/index.js +11 -3
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.cjs +2 -0
- package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.js +2 -0
- package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
- package/dist/adapters/sandbox/e2b/index.cjs +73 -12
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +26 -4
- package/dist/adapters/sandbox/e2b/index.d.ts +26 -4
- package/dist/adapters/sandbox/e2b/index.js +73 -12
- package/dist/adapters/sandbox/e2b/index.js.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.cjs +2 -0
- package/dist/adapters/sandbox/e2b/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.js +2 -0
- package/dist/adapters/sandbox/e2b/workflow.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +8 -3
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +5 -4
- package/dist/adapters/sandbox/inmemory/index.d.ts +5 -4
- package/dist/adapters/sandbox/inmemory/index.js +8 -3
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs +2 -0
- package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.js +2 -0
- package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
- package/dist/adapters/thread/anthropic/index.cjs +94 -39
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +5 -5
- package/dist/adapters/thread/anthropic/index.d.ts +5 -5
- package/dist/adapters/thread/anthropic/index.js +94 -39
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +7 -2
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -5
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -5
- package/dist/adapters/thread/anthropic/workflow.js +7 -2
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +77 -28
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -5
- package/dist/adapters/thread/google-genai/index.d.ts +5 -5
- package/dist/adapters/thread/google-genai/index.js +77 -28
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +7 -2
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -5
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -5
- package/dist/adapters/thread/google-genai/workflow.js +7 -2
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +57 -10
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +5 -5
- package/dist/adapters/thread/langchain/index.d.ts +5 -5
- package/dist/adapters/thread/langchain/index.js +57 -10
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +7 -2
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -5
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -5
- package/dist/adapters/thread/langchain/workflow.js +7 -2
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +322 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -14
- package/dist/index.d.ts +20 -14
- package/dist/index.js +323 -147
- package/dist/index.js.map +1 -1
- package/dist/{proxy-BjdFGPTm.d.ts → proxy-CUlKSvZS.d.ts} +1 -1
- package/dist/{proxy-7RnVaPdJ.d.cts → proxy-D_3x7RN4.d.cts} +1 -1
- package/dist/{thread-manager-CbpiGq1L.d.ts → thread-manager-CVu7o2cs.d.ts} +4 -2
- package/dist/{thread-manager-DzXm9eeI.d.cts → thread-manager-HSwyh28L.d.cts} +4 -2
- package/dist/{thread-manager-BBzNgQWH.d.cts → thread-manager-c1gPopAG.d.ts} +4 -2
- package/dist/{thread-manager-DjN5JYul.d.ts → thread-manager-wGi-LqIP.d.cts} +4 -2
- package/dist/{types-Mc_4BCfT.d.cts → types-BH_IRryz.d.ts} +10 -1
- package/dist/{types-yiXmqedU.d.ts → types-BaOw4hKI.d.cts} +10 -1
- package/dist/{types-DQ1l_gXL.d.cts → types-C06FwR96.d.cts} +121 -17
- package/dist/{types-wiGLvxWf.d.ts → types-DAsQ21Rt.d.ts} +1 -1
- package/dist/{types-CADc5V_P.d.ts → types-DNr31FzL.d.ts} +121 -17
- package/dist/{types-CBH54cwr.d.cts → types-lm8tMNJQ.d.cts} +1 -1
- package/dist/{types-DxCpFNv_.d.cts → types-yx0LzPGn.d.cts} +44 -5
- package/dist/{types-DxCpFNv_.d.ts → types-yx0LzPGn.d.ts} +44 -5
- package/dist/{workflow-DhtWRovz.d.cts → workflow-CSCkpwAL.d.ts} +2 -2
- package/dist/{workflow-P2pTSfKu.d.ts → workflow-DuvMZ8Vm.d.cts} +2 -2
- package/dist/workflow.cjs +274 -130
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +3 -3
- package/dist/workflow.d.ts +3 -3
- package/dist/workflow.js +275 -131
- package/dist/workflow.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/sandbox/bedrock/filesystem.ts +6 -12
- package/src/adapters/sandbox/bedrock/index.ts +22 -11
- package/src/adapters/sandbox/bedrock/proxy.ts +2 -0
- package/src/adapters/sandbox/daytona/index.ts +18 -3
- package/src/adapters/sandbox/daytona/proxy.ts +2 -0
- package/src/adapters/sandbox/e2b/filesystem.ts +5 -4
- package/src/adapters/sandbox/e2b/index.ts +87 -14
- package/src/adapters/sandbox/e2b/proxy.ts +2 -0
- package/src/adapters/sandbox/e2b/types.ts +16 -0
- package/src/adapters/sandbox/inmemory/index.ts +17 -3
- package/src/adapters/sandbox/inmemory/proxy.ts +2 -0
- package/src/adapters/thread/anthropic/activities.ts +58 -26
- package/src/adapters/thread/anthropic/model-invoker.ts +18 -7
- package/src/adapters/thread/anthropic/proxy.ts +6 -2
- package/src/adapters/thread/anthropic/thread-manager.test.ts +26 -7
- package/src/adapters/thread/anthropic/thread-manager.ts +63 -46
- package/src/adapters/thread/google-genai/activities.ts +20 -2
- package/src/adapters/thread/google-genai/model-invoker.ts +27 -7
- package/src/adapters/thread/google-genai/proxy.ts +6 -2
- package/src/adapters/thread/google-genai/thread-manager.test.ts +13 -3
- package/src/adapters/thread/google-genai/thread-manager.ts +57 -33
- package/src/adapters/thread/langchain/activities.ts +55 -24
- package/src/adapters/thread/langchain/hooks.test.ts +36 -49
- package/src/adapters/thread/langchain/hooks.ts +18 -5
- package/src/adapters/thread/langchain/model-invoker.ts +5 -4
- package/src/adapters/thread/langchain/proxy.ts +6 -2
- package/src/adapters/thread/langchain/thread-manager.test.ts +5 -1
- package/src/adapters/thread/langchain/thread-manager.ts +23 -9
- package/src/index.ts +4 -1
- package/src/lib/activity.ts +16 -6
- package/src/lib/hooks/types.ts +6 -6
- package/src/lib/lifecycle.ts +18 -3
- package/src/lib/model/proxy.ts +2 -2
- package/src/lib/model/types.ts +10 -0
- package/src/lib/observability/hooks.ts +4 -5
- package/src/lib/observability/index.ts +1 -4
- package/src/lib/sandbox/manager.ts +45 -20
- package/src/lib/sandbox/node-fs.ts +3 -6
- package/src/lib/sandbox/sandbox.test.ts +36 -3
- package/src/lib/sandbox/tree.integration.test.ts +10 -3
- package/src/lib/sandbox/types.ts +60 -6
- package/src/lib/session/session-edge-cases.integration.test.ts +316 -14
- package/src/lib/session/session.integration.test.ts +161 -1
- package/src/lib/session/session.ts +106 -21
- package/src/lib/session/types.ts +25 -5
- package/src/lib/skills/fs-provider.ts +12 -8
- package/src/lib/skills/handler.ts +1 -1
- package/src/lib/skills/parse.ts +3 -1
- package/src/lib/skills/register.ts +1 -3
- package/src/lib/skills/skills.integration.test.ts +25 -15
- package/src/lib/state/manager.integration.test.ts +12 -2
- package/src/lib/subagent/define.ts +1 -1
- package/src/lib/subagent/handler.ts +186 -71
- package/src/lib/subagent/index.ts +1 -5
- package/src/lib/subagent/register.ts +3 -2
- package/src/lib/subagent/signals.ts +1 -10
- package/src/lib/subagent/subagent.integration.test.ts +526 -248
- package/src/lib/subagent/tool.ts +4 -3
- package/src/lib/subagent/types.ts +50 -20
- package/src/lib/subagent/workflow.ts +9 -49
- package/src/lib/thread/id.test.ts +1 -1
- package/src/lib/thread/id.ts +1 -2
- package/src/lib/thread/manager.ts +18 -0
- package/src/lib/thread/proxy.ts +4 -4
- package/src/lib/thread/types.ts +20 -3
- package/src/lib/tool-router/index.ts +3 -5
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +93 -1
- package/src/lib/tool-router/router.integration.test.ts +12 -0
- package/src/lib/tool-router/router.ts +90 -16
- package/src/lib/tool-router/types.ts +45 -4
- package/src/lib/tool-router/with-sandbox.ts +19 -5
- package/src/lib/virtual-fs/filesystem.ts +1 -1
- package/src/lib/virtual-fs/index.ts +5 -1
- package/src/lib/virtual-fs/mutations.ts +2 -4
- package/src/lib/virtual-fs/queries.ts +9 -5
- package/src/lib/virtual-fs/types.ts +4 -1
- package/src/lib/virtual-fs/virtual-fs.test.ts +9 -11
- package/src/lib/workflow.test.ts +7 -4
- package/src/lib/workflow.ts +1 -5
- package/src/tools/ask-user-question/tool.ts +1 -3
- package/src/tools/glob/handler.ts +1 -4
- package/src/tools/task-get/handler.ts +4 -5
- package/src/tools/task-list/handler.ts +1 -4
- package/src/tools/task-update/handler.ts +4 -5
- package/src/workflow.ts +22 -7
- package/tsup.config.ts +9 -6
- package/src/lib/.env +0 -1
- package/src/tools/bash/.env +0 -1
package/src/lib/model/types.ts
CHANGED
|
@@ -8,6 +8,16 @@ export interface AgentResponse<M = unknown> {
|
|
|
8
8
|
message: M;
|
|
9
9
|
rawToolCalls: RawToolCall[];
|
|
10
10
|
usage?: TokenUsage;
|
|
11
|
+
/**
|
|
12
|
+
* Number of stored messages in the thread at the moment the LLM was
|
|
13
|
+
* invoked — i.e. *before* the assistant message is appended. The
|
|
14
|
+
* session uses this as a rewind snapshot so it can roll the thread
|
|
15
|
+
* back to this exact state if a tool requests a rewind.
|
|
16
|
+
*
|
|
17
|
+
* Adapters compute this for free from the array of stored messages
|
|
18
|
+
* they load when preparing the payload.
|
|
19
|
+
*/
|
|
20
|
+
threadLengthAtCall?: number;
|
|
11
21
|
}
|
|
12
22
|
|
|
13
23
|
/**
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { proxySinks } from "@temporalio/workflow";
|
|
2
2
|
import type { ZeitlichObservabilitySinks } from "./sinks";
|
|
3
|
-
import type {
|
|
4
|
-
SessionStartHook,
|
|
5
|
-
SessionEndHook,
|
|
6
|
-
} from "../hooks/types";
|
|
3
|
+
import type { SessionStartHook, SessionEndHook } from "../hooks/types";
|
|
7
4
|
import type {
|
|
8
5
|
PostToolUseHook,
|
|
9
6
|
PostToolUseFailureHook,
|
|
@@ -39,7 +36,9 @@ export interface ObservabilityHooks {
|
|
|
39
36
|
*
|
|
40
37
|
* @param agentName - Agent name attached to every emitted event
|
|
41
38
|
*/
|
|
42
|
-
export function createObservabilityHooks(
|
|
39
|
+
export function createObservabilityHooks(
|
|
40
|
+
agentName: string
|
|
41
|
+
): ObservabilityHooks {
|
|
43
42
|
const { zeitlichMetrics } = proxySinks<ZeitlichObservabilitySinks>();
|
|
44
43
|
let sessionStartMs = Date.now();
|
|
45
44
|
|
|
@@ -50,8 +50,12 @@ export interface SandboxManagerHooks<
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Called after a sandbox has been successfully created.
|
|
53
|
+
*
|
|
54
|
+
* Receives the live {@link Sandbox} instance so the hook can run setup
|
|
55
|
+
* commands, seed files, or capture identifiers without an extra
|
|
56
|
+
* `provider.get()` round-trip.
|
|
53
57
|
*/
|
|
54
|
-
onPostCreate?: (
|
|
58
|
+
onPostCreate?: (sandbox: Sandbox, ctx: TCtx) => Promise<void>;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
/**
|
|
@@ -87,8 +91,9 @@ export interface SandboxManagerHooks<
|
|
|
87
91
|
* for (const p of filePaths) files[p] = await db.readFile(projectId, p);
|
|
88
92
|
* return { modifiedOptions: { initialFiles: files } };
|
|
89
93
|
* },
|
|
90
|
-
* onPostCreate: async (
|
|
91
|
-
* console.log("Sandbox created:",
|
|
94
|
+
* onPostCreate: async (sandbox) => {
|
|
95
|
+
* console.log("Sandbox created:", sandbox.id);
|
|
96
|
+
* await sandbox.exec("git init");
|
|
92
97
|
* },
|
|
93
98
|
* },
|
|
94
99
|
* },
|
|
@@ -115,9 +120,7 @@ export class SandboxManager<
|
|
|
115
120
|
async create(
|
|
116
121
|
options?: TOptions,
|
|
117
122
|
ctx?: TCtx
|
|
118
|
-
): Promise<{
|
|
119
|
-
sandboxId: string;
|
|
120
|
-
} | null> {
|
|
123
|
+
): Promise<{ sandboxId: string } | null> {
|
|
121
124
|
let providerOptions = options;
|
|
122
125
|
|
|
123
126
|
if (this.hooks.onPreCreate) {
|
|
@@ -148,7 +151,7 @@ export class SandboxManager<
|
|
|
148
151
|
const { sandbox } = await this.provider.create(providerOptions);
|
|
149
152
|
|
|
150
153
|
if (this.hooks.onPostCreate) {
|
|
151
|
-
await this.hooks.onPostCreate(sandbox
|
|
154
|
+
await this.hooks.onPostCreate(sandbox, ctx ?? ({} as TCtx));
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
return { sandboxId: sandbox.id };
|
|
@@ -170,17 +173,24 @@ export class SandboxManager<
|
|
|
170
173
|
await this.provider.resume(id);
|
|
171
174
|
}
|
|
172
175
|
|
|
173
|
-
async snapshot(id: string): Promise<SandboxSnapshot> {
|
|
174
|
-
return this.provider.snapshot(id);
|
|
176
|
+
async snapshot(id: string, options?: TOptions): Promise<SandboxSnapshot> {
|
|
177
|
+
return this.provider.snapshot(id, options);
|
|
175
178
|
}
|
|
176
179
|
|
|
177
|
-
async restore(
|
|
178
|
-
|
|
180
|
+
async restore(
|
|
181
|
+
snapshot: SandboxSnapshot,
|
|
182
|
+
options?: TOptions
|
|
183
|
+
): Promise<string> {
|
|
184
|
+
const sandbox = await this.provider.restore(snapshot, options);
|
|
179
185
|
return sandbox.id;
|
|
180
186
|
}
|
|
181
187
|
|
|
182
|
-
async
|
|
183
|
-
|
|
188
|
+
async deleteSnapshot(snapshot: SandboxSnapshot): Promise<void> {
|
|
189
|
+
await this.provider.deleteSnapshot(snapshot);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async fork(sandboxId: string, options?: TOptions): Promise<string> {
|
|
193
|
+
const sandbox = await this.provider.fork(sandboxId, options);
|
|
184
194
|
return sandbox.id;
|
|
185
195
|
}
|
|
186
196
|
|
|
@@ -212,9 +222,7 @@ export class SandboxManager<
|
|
|
212
222
|
createSandbox: async (
|
|
213
223
|
options?: TOptions,
|
|
214
224
|
ctx?: TCtx
|
|
215
|
-
): Promise<{
|
|
216
|
-
sandboxId: string;
|
|
217
|
-
} | null> => {
|
|
225
|
+
): Promise<{ sandboxId: string } | null> => {
|
|
218
226
|
return this.create(options, ctx);
|
|
219
227
|
},
|
|
220
228
|
destroySandbox: async (sandboxId: string): Promise<void> => {
|
|
@@ -229,11 +237,28 @@ export class SandboxManager<
|
|
|
229
237
|
resumeSandbox: async (sandboxId: string): Promise<void> => {
|
|
230
238
|
await this.resume(sandboxId);
|
|
231
239
|
},
|
|
232
|
-
snapshotSandbox: async (
|
|
233
|
-
|
|
240
|
+
snapshotSandbox: async (
|
|
241
|
+
sandboxId: string,
|
|
242
|
+
options?: TOptions
|
|
243
|
+
): Promise<SandboxSnapshot> => {
|
|
244
|
+
return this.snapshot(sandboxId, options);
|
|
245
|
+
},
|
|
246
|
+
restoreSandbox: async (
|
|
247
|
+
snapshot: SandboxSnapshot,
|
|
248
|
+
options?: TOptions
|
|
249
|
+
): Promise<string> => {
|
|
250
|
+
return this.restore(snapshot, options);
|
|
251
|
+
},
|
|
252
|
+
deleteSandboxSnapshot: async (
|
|
253
|
+
snapshot: SandboxSnapshot
|
|
254
|
+
): Promise<void> => {
|
|
255
|
+
await this.deleteSnapshot(snapshot);
|
|
234
256
|
},
|
|
235
|
-
forkSandbox: async (
|
|
236
|
-
|
|
257
|
+
forkSandbox: async (
|
|
258
|
+
sandboxId: string,
|
|
259
|
+
options?: TOptions
|
|
260
|
+
): Promise<string> => {
|
|
261
|
+
return this.fork(sandboxId, options);
|
|
237
262
|
},
|
|
238
263
|
};
|
|
239
264
|
const cap = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);
|
|
@@ -65,10 +65,7 @@ export class NodeFsSandboxFileSystem implements SandboxFileSystem {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
async mkdir(
|
|
69
|
-
path: string,
|
|
70
|
-
options?: { recursive?: boolean },
|
|
71
|
-
): Promise<void> {
|
|
68
|
+
async mkdir(path: string, options?: { recursive?: boolean }): Promise<void> {
|
|
72
69
|
await fsp.mkdir(this.abs(path), options);
|
|
73
70
|
}
|
|
74
71
|
|
|
@@ -88,7 +85,7 @@ export class NodeFsSandboxFileSystem implements SandboxFileSystem {
|
|
|
88
85
|
|
|
89
86
|
async rm(
|
|
90
87
|
path: string,
|
|
91
|
-
options?: { recursive?: boolean; force?: boolean }
|
|
88
|
+
options?: { recursive?: boolean; force?: boolean }
|
|
92
89
|
): Promise<void> {
|
|
93
90
|
await fsp.rm(this.abs(path), options);
|
|
94
91
|
}
|
|
@@ -96,7 +93,7 @@ export class NodeFsSandboxFileSystem implements SandboxFileSystem {
|
|
|
96
93
|
async cp(
|
|
97
94
|
src: string,
|
|
98
95
|
dest: string,
|
|
99
|
-
options?: { recursive?: boolean }
|
|
96
|
+
options?: { recursive?: boolean }
|
|
100
97
|
): Promise<void> {
|
|
101
98
|
await fsp.cp(this.abs(src), this.abs(dest), options);
|
|
102
99
|
}
|
|
@@ -157,18 +157,21 @@ describe("SandboxManager", () => {
|
|
|
157
157
|
expect(await sandbox.fs.readFile("/file.txt")).toBe("explicit");
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
-
it("onPostCreate hook receives
|
|
160
|
+
it("onPostCreate hook receives the live sandbox", async () => {
|
|
161
161
|
let capturedId: string | undefined;
|
|
162
162
|
const mgr = new SandboxManager(new InMemorySandboxProvider(), {
|
|
163
163
|
hooks: {
|
|
164
|
-
onPostCreate: async (
|
|
165
|
-
capturedId =
|
|
164
|
+
onPostCreate: async (sandbox) => {
|
|
165
|
+
capturedId = sandbox.id;
|
|
166
|
+
await sandbox.fs.writeFile("/hook.txt", "written-by-hook");
|
|
166
167
|
},
|
|
167
168
|
},
|
|
168
169
|
});
|
|
169
170
|
|
|
170
171
|
const { sandboxId } = await mustCreate(mgr);
|
|
171
172
|
expect(capturedId).toBe(sandboxId);
|
|
173
|
+
const sandbox = await mgr.getSandbox(sandboxId);
|
|
174
|
+
expect(await sandbox.fs.readFile("/hook.txt")).toBe("written-by-hook");
|
|
172
175
|
});
|
|
173
176
|
|
|
174
177
|
it("onPostCreate hook does not run when creation is skipped", async () => {
|
|
@@ -192,6 +195,8 @@ describe("SandboxManager", () => {
|
|
|
192
195
|
expect(activities.inMemoryTestCreateSandbox).toBeTypeOf("function");
|
|
193
196
|
expect(activities.inMemoryTestDestroySandbox).toBeTypeOf("function");
|
|
194
197
|
expect(activities.inMemoryTestSnapshotSandbox).toBeTypeOf("function");
|
|
198
|
+
expect(activities.inMemoryTestRestoreSandbox).toBeTypeOf("function");
|
|
199
|
+
expect(activities.inMemoryTestDeleteSandboxSnapshot).toBeTypeOf("function");
|
|
195
200
|
|
|
196
201
|
const result = await activities.inMemoryTestCreateSandbox();
|
|
197
202
|
expect(result).not.toBeNull();
|
|
@@ -203,6 +208,34 @@ describe("SandboxManager", () => {
|
|
|
203
208
|
SandboxNotFoundError
|
|
204
209
|
);
|
|
205
210
|
});
|
|
211
|
+
|
|
212
|
+
it("restoreSandbox activity creates a new sandbox from a snapshot", async () => {
|
|
213
|
+
const activities = manager.createActivities("Test");
|
|
214
|
+
|
|
215
|
+
const created = await activities.inMemoryTestCreateSandbox({
|
|
216
|
+
initialFiles: { "/greeting.txt": "hello" },
|
|
217
|
+
});
|
|
218
|
+
const { sandboxId } = created as { sandboxId: string };
|
|
219
|
+
|
|
220
|
+
const snapshot = await activities.inMemoryTestSnapshotSandbox(sandboxId);
|
|
221
|
+
await activities.inMemoryTestDestroySandbox(sandboxId);
|
|
222
|
+
|
|
223
|
+
const restoredId = await activities.inMemoryTestRestoreSandbox(snapshot);
|
|
224
|
+
const restored = await manager.getSandbox(restoredId);
|
|
225
|
+
expect(await restored.fs.readFile("/greeting.txt")).toBe("hello");
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("deleteSandboxSnapshot activity is a no-op for in-memory snapshots", async () => {
|
|
229
|
+
const activities = manager.createActivities("Test");
|
|
230
|
+
|
|
231
|
+
const created = await activities.inMemoryTestCreateSandbox();
|
|
232
|
+
const { sandboxId } = created as { sandboxId: string };
|
|
233
|
+
|
|
234
|
+
const snapshot = await activities.inMemoryTestSnapshotSandbox(sandboxId);
|
|
235
|
+
await expect(
|
|
236
|
+
activities.inMemoryTestDeleteSandboxSnapshot(snapshot)
|
|
237
|
+
).resolves.toBeUndefined();
|
|
238
|
+
});
|
|
206
239
|
});
|
|
207
240
|
|
|
208
241
|
describe("InMemorySandboxProvider", () => {
|
|
@@ -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 {
|
|
@@ -133,9 +158,23 @@ export interface SandboxProvider<
|
|
|
133
158
|
pause(sandboxId: string, ttlSeconds?: number): Promise<void>;
|
|
134
159
|
/** Resume a paused sandbox. No-op if already running. */
|
|
135
160
|
resume(sandboxId: string): Promise<void>;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Capture a snapshot of a running sandbox. `options` is a per-call override
|
|
163
|
+
* merged on top of the provider's static defaults.
|
|
164
|
+
*/
|
|
165
|
+
snapshot(sandboxId: string, options?: TOptions): Promise<SandboxSnapshot>;
|
|
166
|
+
/**
|
|
167
|
+
* Restore a sandbox from a snapshot. `options` is a per-call override
|
|
168
|
+
* merged on top of the provider's static defaults.
|
|
169
|
+
*/
|
|
170
|
+
restore(snapshot: SandboxSnapshot, options?: TOptions): Promise<Sandbox>;
|
|
171
|
+
/** Delete a previously captured snapshot. No-op if already deleted. */
|
|
172
|
+
deleteSnapshot(snapshot: SandboxSnapshot): Promise<void>;
|
|
173
|
+
/**
|
|
174
|
+
* Fork a running sandbox into a new one. `options` is a per-call override
|
|
175
|
+
* merged on top of the provider's static defaults.
|
|
176
|
+
*/
|
|
177
|
+
fork(sandboxId: string, options?: TOptions): Promise<Sandbox>;
|
|
139
178
|
}
|
|
140
179
|
|
|
141
180
|
// ============================================================================
|
|
@@ -154,8 +193,20 @@ export interface SandboxOps<
|
|
|
154
193
|
pauseSandbox(sandboxId: string): Promise<void>;
|
|
155
194
|
/** Resume a paused sandbox. No-op if already running. */
|
|
156
195
|
resumeSandbox(sandboxId: string): Promise<void>;
|
|
157
|
-
|
|
158
|
-
|
|
196
|
+
/** Capture a snapshot. `options` is a per-call override merged on top of provider defaults. */
|
|
197
|
+
snapshotSandbox(
|
|
198
|
+
sandboxId: string,
|
|
199
|
+
options?: TOptions
|
|
200
|
+
): Promise<SandboxSnapshot>;
|
|
201
|
+
/** Create a fresh sandbox from a snapshot. `options` is a per-call override merged on top of provider defaults. */
|
|
202
|
+
restoreSandbox(
|
|
203
|
+
snapshot: SandboxSnapshot,
|
|
204
|
+
options?: TOptions
|
|
205
|
+
): Promise<string>;
|
|
206
|
+
/** Delete a previously captured snapshot. No-op if already deleted. */
|
|
207
|
+
deleteSandboxSnapshot(snapshot: SandboxSnapshot): Promise<void>;
|
|
208
|
+
/** Fork a running sandbox. `options` is a per-call override merged on top of provider defaults. */
|
|
209
|
+
forkSandbox(sandboxId: string, options?: TOptions): Promise<string>;
|
|
159
210
|
}
|
|
160
211
|
|
|
161
212
|
/**
|
|
@@ -172,7 +223,10 @@ export type PrefixedSandboxOps<
|
|
|
172
223
|
TOptions extends SandboxCreateOptions = SandboxCreateOptions,
|
|
173
224
|
TCtx = unknown,
|
|
174
225
|
> = {
|
|
175
|
-
[K in keyof SandboxOps<
|
|
226
|
+
[K in keyof SandboxOps<
|
|
227
|
+
TOptions,
|
|
228
|
+
TCtx
|
|
229
|
+
> as `${TPrefix}${Capitalize<K & string>}`]: SandboxOps<TOptions, TCtx>[K];
|
|
176
230
|
};
|
|
177
231
|
|
|
178
232
|
// ============================================================================
|