zeitlich 0.2.22 → 0.2.23
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 +242 -59
- package/dist/adapters/sandbox/daytona/index.cjs +4 -1
- 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 +4 -1
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.cjs +1 -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 +1 -0
- package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +16 -2
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +3 -2
- package/dist/adapters/sandbox/inmemory/index.d.ts +3 -2
- package/dist/adapters/sandbox/inmemory/index.js +16 -2
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs +1 -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 +1 -0
- package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
- package/dist/adapters/sandbox/virtual/index.cjs +33 -9
- package/dist/adapters/sandbox/virtual/index.cjs.map +1 -1
- package/dist/adapters/sandbox/virtual/index.d.cts +6 -5
- package/dist/adapters/sandbox/virtual/index.d.ts +6 -5
- package/dist/adapters/sandbox/virtual/index.js +33 -9
- package/dist/adapters/sandbox/virtual/index.js.map +1 -1
- package/dist/adapters/sandbox/virtual/workflow.cjs +1 -0
- package/dist/adapters/sandbox/virtual/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/virtual/workflow.d.cts +3 -3
- package/dist/adapters/sandbox/virtual/workflow.d.ts +3 -3
- package/dist/adapters/sandbox/virtual/workflow.js +1 -0
- package/dist/adapters/sandbox/virtual/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +3 -3
- package/dist/adapters/thread/google-genai/index.d.ts +3 -3
- package/dist/adapters/thread/google-genai/workflow.d.cts +3 -3
- package/dist/adapters/thread/google-genai/workflow.d.ts +3 -3
- package/dist/adapters/thread/langchain/index.d.cts +3 -3
- package/dist/adapters/thread/langchain/index.d.ts +3 -3
- package/dist/adapters/thread/langchain/workflow.d.cts +3 -3
- package/dist/adapters/thread/langchain/workflow.d.ts +3 -3
- package/dist/index.cjs +247 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +245 -55
- package/dist/index.js.map +1 -1
- package/dist/{queries-Bw6WEPMw.d.cts → queries-DModcWRy.d.cts} +1 -1
- package/dist/{queries-C27raDaB.d.ts → queries-byD0jr1Y.d.ts} +1 -1
- package/dist/{types-ClsHhtwL.d.cts → types-B50pBPEV.d.ts} +159 -35
- package/dist/{types-YbL7JpEA.d.cts → types-Bll19FZJ.d.cts} +7 -0
- package/dist/{types-YbL7JpEA.d.ts → types-Bll19FZJ.d.ts} +7 -0
- package/dist/{types-BJ8itUAl.d.cts → types-BuXdFhaZ.d.cts} +6 -6
- package/dist/{types-HBosetv3.d.cts → types-ChAMwU3q.d.cts} +2 -0
- package/dist/{types-HBosetv3.d.ts → types-ChAMwU3q.d.ts} +2 -0
- package/dist/{types-C5bkx6kQ.d.ts → types-DQW8l7pY.d.cts} +159 -35
- package/dist/{types-ENYCKFBk.d.ts → types-GZ76HZSj.d.ts} +6 -6
- package/dist/workflow.cjs +241 -57
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +49 -32
- package/dist/workflow.d.ts +49 -32
- package/dist/workflow.js +239 -55
- package/dist/workflow.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/sandbox/daytona/filesystem.ts +1 -1
- package/src/adapters/sandbox/daytona/index.ts +4 -0
- package/src/adapters/sandbox/daytona/proxy.ts +4 -3
- package/src/adapters/sandbox/e2b/index.ts +5 -0
- package/src/adapters/sandbox/inmemory/index.ts +24 -4
- package/src/adapters/sandbox/inmemory/proxy.ts +2 -2
- package/src/adapters/sandbox/virtual/filesystem.ts +41 -17
- package/src/adapters/sandbox/virtual/provider.ts +4 -0
- package/src/adapters/sandbox/virtual/proxy.ts +1 -0
- package/src/adapters/sandbox/virtual/types.ts +9 -4
- package/src/lib/lifecycle.ts +57 -0
- package/src/lib/sandbox/manager.ts +13 -1
- package/src/lib/sandbox/types.ts +13 -4
- package/src/lib/session/index.ts +1 -0
- package/src/lib/session/session-edge-cases.integration.test.ts +447 -33
- package/src/lib/session/session.integration.test.ts +52 -32
- package/src/lib/session/session.ts +107 -33
- package/src/lib/session/types.ts +55 -16
- package/src/lib/subagent/define.ts +5 -4
- package/src/lib/subagent/handler.ts +139 -14
- package/src/lib/subagent/index.ts +3 -0
- package/src/lib/subagent/register.ts +10 -3
- package/src/lib/subagent/signals.ts +8 -0
- package/src/lib/subagent/subagent.integration.test.ts +853 -150
- package/src/lib/subagent/tool.ts +2 -2
- package/src/lib/subagent/types.ts +77 -19
- package/src/lib/subagent/workflow.ts +83 -12
- package/src/lib/tool-router/router.integration.test.ts +137 -4
- package/src/lib/tool-router/router.ts +13 -3
- package/src/lib/tool-router/types.ts +7 -0
- package/src/lib/workflow.test.ts +89 -21
- package/src/lib/workflow.ts +33 -18
- package/src/workflow.ts +6 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zeitlich",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.23",
|
|
4
4
|
"description": "[EXPERIMENTAL] An opinionated AI agent implementation for Temporal",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -189,7 +189,7 @@
|
|
|
189
189
|
"vitest": "^4.0.18"
|
|
190
190
|
},
|
|
191
191
|
"peerDependencies": {
|
|
192
|
-
"@daytonaio/sdk": ">=0.
|
|
192
|
+
"@daytonaio/sdk": ">=0.153.0",
|
|
193
193
|
"@e2b/code-interpreter": "^2.3.3",
|
|
194
194
|
"@google/genai": "^1.43.0",
|
|
195
195
|
"@langchain/core": ">=1.0.0",
|
|
@@ -141,6 +141,10 @@ export class DaytonaSandboxProvider implements SandboxProvider<
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
async pause(_sandboxId: string, _ttlSeconds?: number): Promise<void> {
|
|
145
|
+
throw new SandboxNotSupportedError("pause");
|
|
146
|
+
}
|
|
147
|
+
|
|
144
148
|
async fork(_sandboxId: string): Promise<Sandbox> {
|
|
145
149
|
throw new Error("Not implemented");
|
|
146
150
|
}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { proxyActivities, workflowInfo } from "@temporalio/workflow";
|
|
21
21
|
import type { SandboxOps } from "../../../lib/sandbox/types";
|
|
22
|
+
import type { DaytonaSandboxCreateOptions } from "./types";
|
|
22
23
|
|
|
23
24
|
const ADAPTER_PREFIX = "daytona";
|
|
24
25
|
|
|
@@ -41,15 +42,15 @@ export function proxyDaytonaSandboxOps(
|
|
|
41
42
|
}
|
|
42
43
|
);
|
|
43
44
|
|
|
44
|
-
const prefix =
|
|
45
|
-
`${ADAPTER_PREFIX}${resolvedScope.charAt(0).toUpperCase()}${resolvedScope.slice(1)}`;
|
|
45
|
+
const prefix = `${ADAPTER_PREFIX}${resolvedScope.charAt(0).toUpperCase()}${resolvedScope.slice(1)}`;
|
|
46
46
|
const p = (key: string): string =>
|
|
47
47
|
`${prefix}${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
48
48
|
|
|
49
49
|
return {
|
|
50
50
|
createSandbox: acts[p("createSandbox")],
|
|
51
51
|
destroySandbox: acts[p("destroySandbox")],
|
|
52
|
+
pauseSandbox: acts[p("pauseSandbox")],
|
|
52
53
|
snapshotSandbox: acts[p("snapshotSandbox")],
|
|
53
54
|
forkSandbox: acts[p("forkSandbox")],
|
|
54
|
-
} as SandboxOps
|
|
55
|
+
} as SandboxOps<DaytonaSandboxCreateOptions>;
|
|
55
56
|
}
|
|
@@ -131,6 +131,11 @@ export class E2bSandboxProvider
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
async pause(sandboxId: string, _ttlSeconds?: number): Promise<void> {
|
|
135
|
+
const sdkSandbox = await E2bSdkSandbox.connect(sandboxId);
|
|
136
|
+
await sdkSandbox.pause();
|
|
137
|
+
}
|
|
138
|
+
|
|
134
139
|
async snapshot(_sandboxId: string): Promise<SandboxSnapshot> {
|
|
135
140
|
throw new SandboxNotSupportedError("snapshot");
|
|
136
141
|
}
|
|
@@ -27,7 +27,8 @@ import { getShortId } from "../../../lib/thread/id";
|
|
|
27
27
|
|
|
28
28
|
function toSandboxFs(fs: IFileSystem): SandboxFileSystem {
|
|
29
29
|
const workspaceBase = "/";
|
|
30
|
-
const normalisePath = (path: string): string =>
|
|
30
|
+
const normalisePath = (path: string): string =>
|
|
31
|
+
fs.resolvePath(workspaceBase, path);
|
|
31
32
|
|
|
32
33
|
return {
|
|
33
34
|
workspaceBase,
|
|
@@ -68,7 +69,8 @@ function toSandboxFs(fs: IFileSystem): SandboxFileSystem {
|
|
|
68
69
|
return fs.readdirWithFileTypes(dirPath);
|
|
69
70
|
},
|
|
70
71
|
rm: (path, opts) => fs.rm(normalisePath(path), opts),
|
|
71
|
-
cp: (src, dest, opts) =>
|
|
72
|
+
cp: (src, dest, opts) =>
|
|
73
|
+
fs.cp(normalisePath(src), normalisePath(dest), opts),
|
|
72
74
|
mv: (src, dest) => fs.mv(normalisePath(src), normalisePath(dest)),
|
|
73
75
|
readlink: (path) => fs.readlink(normalisePath(path)),
|
|
74
76
|
resolvePath: (base, p) => fs.resolvePath(normalisePath(base), p),
|
|
@@ -157,6 +159,10 @@ export class InMemorySandboxProvider implements SandboxProvider {
|
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
161
|
|
|
162
|
+
async pause(_sandboxId: string, _ttlSeconds?: number): Promise<void> {
|
|
163
|
+
// In-memory: nothing to pause
|
|
164
|
+
}
|
|
165
|
+
|
|
160
166
|
async create(options?: SandboxCreateOptions): Promise<SandboxCreateResult> {
|
|
161
167
|
const id = options?.id ?? getShortId();
|
|
162
168
|
const initialFiles: InitialFiles = {};
|
|
@@ -200,8 +206,22 @@ export class InMemorySandboxProvider implements SandboxProvider {
|
|
|
200
206
|
};
|
|
201
207
|
}
|
|
202
208
|
|
|
203
|
-
async fork(
|
|
204
|
-
|
|
209
|
+
async fork(sandboxId: string): Promise<Sandbox> {
|
|
210
|
+
const sandbox = await this.get(sandboxId);
|
|
211
|
+
|
|
212
|
+
const entries = await sandbox.fs.readdirWithFileTypes("/");
|
|
213
|
+
const initialFiles: Record<string, Uint8Array> = {};
|
|
214
|
+
for (const entry of entries) {
|
|
215
|
+
if (entry.isFile) {
|
|
216
|
+
initialFiles[entry.name] = await sandbox.fs.readFileBuffer(entry.name);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const newSandbox = await this.create({
|
|
221
|
+
id: getShortId(),
|
|
222
|
+
initialFiles,
|
|
223
|
+
});
|
|
224
|
+
return newSandbox.sandbox;
|
|
205
225
|
}
|
|
206
226
|
|
|
207
227
|
async restore(snapshot: SandboxSnapshot): Promise<Sandbox> {
|
|
@@ -39,14 +39,14 @@ export function proxyInMemorySandboxOps(
|
|
|
39
39
|
}
|
|
40
40
|
);
|
|
41
41
|
|
|
42
|
-
const prefix =
|
|
43
|
-
`${ADAPTER_PREFIX}${resolvedScope.charAt(0).toUpperCase()}${resolvedScope.slice(1)}`;
|
|
42
|
+
const prefix = `${ADAPTER_PREFIX}${resolvedScope.charAt(0).toUpperCase()}${resolvedScope.slice(1)}`;
|
|
44
43
|
const p = (key: string): string =>
|
|
45
44
|
`${prefix}${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
46
45
|
|
|
47
46
|
return {
|
|
48
47
|
createSandbox: acts[p("createSandbox")],
|
|
49
48
|
destroySandbox: acts[p("destroySandbox")],
|
|
49
|
+
pauseSandbox: acts[p("pauseSandbox")],
|
|
50
50
|
snapshotSandbox: acts[p("snapshotSandbox")],
|
|
51
51
|
forkSandbox: acts[p("forkSandbox")],
|
|
52
52
|
} as SandboxOps;
|
|
@@ -29,7 +29,7 @@ function parentDir(p: string): string {
|
|
|
29
29
|
*/
|
|
30
30
|
function inferDirectories(
|
|
31
31
|
entries: { path: string }[],
|
|
32
|
-
workspaceBase: string
|
|
32
|
+
workspaceBase: string
|
|
33
33
|
): Set<string> {
|
|
34
34
|
const dirs = new Set<string>();
|
|
35
35
|
dirs.add("/");
|
|
@@ -54,8 +54,7 @@ function inferDirectories(
|
|
|
54
54
|
export class VirtualSandboxFileSystem<
|
|
55
55
|
TCtx = unknown,
|
|
56
56
|
TMeta = FileEntryMetadata,
|
|
57
|
-
> implements SandboxFileSystem
|
|
58
|
-
{
|
|
57
|
+
> implements SandboxFileSystem {
|
|
59
58
|
readonly workspaceBase: string;
|
|
60
59
|
private entries: Map<string, FileEntry<TMeta>>;
|
|
61
60
|
private directories: Set<string>;
|
|
@@ -65,11 +64,11 @@ export class VirtualSandboxFileSystem<
|
|
|
65
64
|
tree: FileEntry<TMeta>[],
|
|
66
65
|
private resolver: FileResolver<TCtx, TMeta>,
|
|
67
66
|
private ctx: TCtx,
|
|
68
|
-
workspaceBase = "/"
|
|
67
|
+
workspaceBase = "/"
|
|
69
68
|
) {
|
|
70
69
|
this.workspaceBase = normalisePath(workspaceBase);
|
|
71
70
|
this.entries = new Map(
|
|
72
|
-
tree.map((e) => [normalisePath(e.path, this.workspaceBase), e])
|
|
71
|
+
tree.map((e) => [normalisePath(e.path, this.workspaceBase), e])
|
|
73
72
|
);
|
|
74
73
|
this.directories = inferDirectories(tree, this.workspaceBase);
|
|
75
74
|
}
|
|
@@ -91,13 +90,13 @@ export class VirtualSandboxFileSystem<
|
|
|
91
90
|
async readFile(path: string): Promise<string> {
|
|
92
91
|
const entry = this.entries.get(normalisePath(path, this.workspaceBase));
|
|
93
92
|
if (!entry) throw new Error(`ENOENT: no such file: ${path}`);
|
|
94
|
-
return this.resolver.readFile(entry.id, this.ctx);
|
|
93
|
+
return this.resolver.readFile(entry.id, this.ctx, entry.metadata);
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
async readFileBuffer(path: string): Promise<Uint8Array> {
|
|
98
97
|
const entry = this.entries.get(normalisePath(path, this.workspaceBase));
|
|
99
98
|
if (!entry) throw new Error(`ENOENT: no such file: ${path}`);
|
|
100
|
-
return this.resolver.readFileBuffer(entry.id, this.ctx);
|
|
99
|
+
return this.resolver.readFileBuffer(entry.id, this.ctx, entry.metadata);
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
// --------------------------------------------------------------------------
|
|
@@ -180,7 +179,12 @@ export class VirtualSandboxFileSystem<
|
|
|
180
179
|
const existing = this.entries.get(norm);
|
|
181
180
|
|
|
182
181
|
if (existing) {
|
|
183
|
-
await this.resolver.writeFile(
|
|
182
|
+
await this.resolver.writeFile(
|
|
183
|
+
existing.id,
|
|
184
|
+
content,
|
|
185
|
+
this.ctx,
|
|
186
|
+
existing.metadata
|
|
187
|
+
);
|
|
184
188
|
const size =
|
|
185
189
|
typeof content === "string"
|
|
186
190
|
? new TextEncoder().encode(content).byteLength
|
|
@@ -209,12 +213,21 @@ export class VirtualSandboxFileSystem<
|
|
|
209
213
|
return this.writeFile(path, content);
|
|
210
214
|
}
|
|
211
215
|
|
|
212
|
-
const current = await this.resolver.readFile(
|
|
216
|
+
const current = await this.resolver.readFile(
|
|
217
|
+
existing.id,
|
|
218
|
+
this.ctx,
|
|
219
|
+
existing.metadata
|
|
220
|
+
);
|
|
213
221
|
const appended =
|
|
214
222
|
typeof content === "string"
|
|
215
223
|
? current + content
|
|
216
224
|
: current + new TextDecoder().decode(content);
|
|
217
|
-
await this.resolver.writeFile(
|
|
225
|
+
await this.resolver.writeFile(
|
|
226
|
+
existing.id,
|
|
227
|
+
appended,
|
|
228
|
+
this.ctx,
|
|
229
|
+
existing.metadata
|
|
230
|
+
);
|
|
218
231
|
|
|
219
232
|
const size = new TextEncoder().encode(appended).byteLength;
|
|
220
233
|
const updated: FileEntry<TMeta> = {
|
|
@@ -226,7 +239,10 @@ export class VirtualSandboxFileSystem<
|
|
|
226
239
|
this.mutations.push({ type: "update", path: norm, entry: updated });
|
|
227
240
|
}
|
|
228
241
|
|
|
229
|
-
async mkdir(
|
|
242
|
+
async mkdir(
|
|
243
|
+
_path: string,
|
|
244
|
+
_options?: { recursive?: boolean }
|
|
245
|
+
): Promise<void> {
|
|
230
246
|
const norm = normalisePath(_path, this.workspaceBase);
|
|
231
247
|
if (this.directories.has(norm)) return;
|
|
232
248
|
|
|
@@ -244,13 +260,13 @@ export class VirtualSandboxFileSystem<
|
|
|
244
260
|
|
|
245
261
|
async rm(
|
|
246
262
|
path: string,
|
|
247
|
-
options?: { recursive?: boolean; force?: boolean }
|
|
263
|
+
options?: { recursive?: boolean; force?: boolean }
|
|
248
264
|
): Promise<void> {
|
|
249
265
|
const norm = normalisePath(path, this.workspaceBase);
|
|
250
266
|
const entry = this.entries.get(norm);
|
|
251
267
|
|
|
252
268
|
if (entry) {
|
|
253
|
-
await this.resolver.deleteFile(entry.id, this.ctx);
|
|
269
|
+
await this.resolver.deleteFile(entry.id, this.ctx, entry.metadata);
|
|
254
270
|
this.entries.delete(norm);
|
|
255
271
|
this.mutations.push({ type: "remove", path: norm });
|
|
256
272
|
return;
|
|
@@ -263,7 +279,7 @@ export class VirtualSandboxFileSystem<
|
|
|
263
279
|
const prefix = norm === "/" ? "/" : norm + "/";
|
|
264
280
|
for (const [p, e] of this.entries) {
|
|
265
281
|
if (p.startsWith(prefix)) {
|
|
266
|
-
await this.resolver.deleteFile(e.id, this.ctx);
|
|
282
|
+
await this.resolver.deleteFile(e.id, this.ctx, e.metadata);
|
|
267
283
|
this.entries.delete(p);
|
|
268
284
|
this.mutations.push({ type: "remove", path: p });
|
|
269
285
|
}
|
|
@@ -283,14 +299,18 @@ export class VirtualSandboxFileSystem<
|
|
|
283
299
|
async cp(
|
|
284
300
|
src: string,
|
|
285
301
|
dest: string,
|
|
286
|
-
_options?: { recursive?: boolean }
|
|
302
|
+
_options?: { recursive?: boolean }
|
|
287
303
|
): Promise<void> {
|
|
288
304
|
const normSrc = normalisePath(src, this.workspaceBase);
|
|
289
305
|
const normDest = normalisePath(dest, this.workspaceBase);
|
|
290
306
|
|
|
291
307
|
const entry = this.entries.get(normSrc);
|
|
292
308
|
if (entry) {
|
|
293
|
-
const content = await this.resolver.readFile(
|
|
309
|
+
const content = await this.resolver.readFile(
|
|
310
|
+
entry.id,
|
|
311
|
+
this.ctx,
|
|
312
|
+
entry.metadata
|
|
313
|
+
);
|
|
294
314
|
await this.writeFile(normDest, content);
|
|
295
315
|
return;
|
|
296
316
|
}
|
|
@@ -306,7 +326,11 @@ export class VirtualSandboxFileSystem<
|
|
|
306
326
|
for (const [p, e] of this.entries) {
|
|
307
327
|
if (p.startsWith(prefix)) {
|
|
308
328
|
const relative = p.slice(normSrc.length);
|
|
309
|
-
const content = await this.resolver.readFile(
|
|
329
|
+
const content = await this.resolver.readFile(
|
|
330
|
+
e.id,
|
|
331
|
+
this.ctx,
|
|
332
|
+
e.metadata
|
|
333
|
+
);
|
|
310
334
|
await this.writeFile(normDest + relative, content);
|
|
311
335
|
}
|
|
312
336
|
}
|
|
@@ -90,6 +90,10 @@ export class VirtualSandboxProvider<
|
|
|
90
90
|
// No-op — no internal state to clean up
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
async pause(): Promise<void> {
|
|
94
|
+
// No-op — virtual sandbox state lives in workflow AgentState
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
async fork(_sandboxId: string): Promise<never> {
|
|
94
98
|
throw new Error("Not implemented");
|
|
95
99
|
}
|
|
@@ -46,6 +46,7 @@ export function proxyVirtualSandboxOps(
|
|
|
46
46
|
return {
|
|
47
47
|
createSandbox: acts[p("createSandbox")],
|
|
48
48
|
destroySandbox: acts[p("destroySandbox")],
|
|
49
|
+
pauseSandbox: acts[p("pauseSandbox")],
|
|
49
50
|
snapshotSandbox: acts[p("snapshotSandbox")],
|
|
50
51
|
forkSandbox: acts[p("forkSandbox")],
|
|
51
52
|
} as SandboxOps<VirtualSandboxCreateOptions<unknown>>;
|
|
@@ -56,15 +56,20 @@ export type TreeMutation<TMeta = FileEntryMetadata> =
|
|
|
56
56
|
*/
|
|
57
57
|
export interface FileResolver<TCtx = unknown, TMeta = FileEntryMetadata> {
|
|
58
58
|
resolveEntries(ctx: TCtx): Promise<FileEntry<TMeta>[]>;
|
|
59
|
-
readFile(id: string, ctx: TCtx): Promise<string>;
|
|
60
|
-
readFileBuffer(id: string, ctx: TCtx): Promise<Uint8Array>;
|
|
61
|
-
writeFile(
|
|
59
|
+
readFile(id: string, ctx: TCtx, metadata: TMeta): Promise<string>;
|
|
60
|
+
readFileBuffer(id: string, ctx: TCtx, metadata: TMeta): Promise<Uint8Array>;
|
|
61
|
+
writeFile(
|
|
62
|
+
id: string,
|
|
63
|
+
content: string | Uint8Array,
|
|
64
|
+
ctx: TCtx,
|
|
65
|
+
metadata: TMeta
|
|
66
|
+
): Promise<void>;
|
|
62
67
|
createFile(
|
|
63
68
|
path: string,
|
|
64
69
|
content: string | Uint8Array,
|
|
65
70
|
ctx: TCtx
|
|
66
71
|
): Promise<FileEntry<TMeta>>;
|
|
67
|
-
deleteFile(id: string, ctx: TCtx): Promise<void>;
|
|
72
|
+
deleteFile(id: string, ctx: TCtx, metadata: TMeta): Promise<void>;
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
// ============================================================================
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Thread lifecycle
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Thread initialization strategy.
|
|
7
|
+
*
|
|
8
|
+
* - `"new"` — start a fresh thread (optionally specify its ID).
|
|
9
|
+
* - `"continue"` — append directly to an existing thread in-place.
|
|
10
|
+
* - `"fork"` — copy all messages from an existing thread into a new one and
|
|
11
|
+
* continue there.
|
|
12
|
+
*/
|
|
13
|
+
export type ThreadInit =
|
|
14
|
+
| { mode: "new"; threadId?: string }
|
|
15
|
+
| { mode: "continue"; threadId: string }
|
|
16
|
+
| { mode: "fork"; threadId: string };
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Sandbox lifecycle
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Sandbox initialization strategy.
|
|
24
|
+
*
|
|
25
|
+
* - `"new"` — create a fresh sandbox.
|
|
26
|
+
* - `"continue"` — resume a previously-paused sandbox (this session takes
|
|
27
|
+
* ownership and the shutdown policy applies on exit).
|
|
28
|
+
* - `"fork"` — fork from an existing (or paused) sandbox; a new sandbox is
|
|
29
|
+
* created and owned by this session.
|
|
30
|
+
* - `"inherit"` — use a sandbox owned by someone else (e.g. a parent agent).
|
|
31
|
+
* The session will **not** manage its lifecycle on exit.
|
|
32
|
+
*/
|
|
33
|
+
export type SandboxInit =
|
|
34
|
+
| { mode: "new" }
|
|
35
|
+
| { mode: "continue"; sandboxId: string }
|
|
36
|
+
| { mode: "fork"; sandboxId: string }
|
|
37
|
+
| { mode: "inherit"; sandboxId: string };
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* What to do with the sandbox when the session exits.
|
|
41
|
+
*
|
|
42
|
+
* - `"destroy"` — tear down the sandbox entirely.
|
|
43
|
+
* - `"pause"` — pause the sandbox so it can be resumed later.
|
|
44
|
+
* - `"keep"` — leave the sandbox running (no-op on exit).
|
|
45
|
+
*/
|
|
46
|
+
export type SandboxShutdown = "destroy" | "pause" | "keep";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Extended shutdown options available to subagent workflows.
|
|
50
|
+
*
|
|
51
|
+
* Includes all base {@link SandboxShutdown} values plus:
|
|
52
|
+
* - `"pause-until-parent-close"` — pause the sandbox on exit, then wait for
|
|
53
|
+
* the parent workflow to signal when to destroy it.
|
|
54
|
+
*/
|
|
55
|
+
export type SubagentSandboxShutdown =
|
|
56
|
+
| SandboxShutdown
|
|
57
|
+
| "pause-until-parent-close";
|
|
@@ -28,7 +28,9 @@ export class SandboxManager<
|
|
|
28
28
|
TSandbox extends Sandbox = Sandbox,
|
|
29
29
|
TId extends string = string,
|
|
30
30
|
> {
|
|
31
|
-
constructor(
|
|
31
|
+
constructor(
|
|
32
|
+
private provider: SandboxProvider<TOptions, TSandbox> & { readonly id: TId }
|
|
33
|
+
) {}
|
|
32
34
|
|
|
33
35
|
async create(
|
|
34
36
|
options?: TOptions
|
|
@@ -45,6 +47,10 @@ export class SandboxManager<
|
|
|
45
47
|
await this.provider.destroy(id);
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
async pause(id: string, ttlSeconds?: number): Promise<void> {
|
|
51
|
+
await this.provider.pause(id, ttlSeconds);
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
async snapshot(id: string): Promise<SandboxSnapshot> {
|
|
49
55
|
return this.provider.snapshot(id);
|
|
50
56
|
}
|
|
@@ -95,6 +101,12 @@ export class SandboxManager<
|
|
|
95
101
|
destroySandbox: async (sandboxId: string): Promise<void> => {
|
|
96
102
|
await this.destroy(sandboxId);
|
|
97
103
|
},
|
|
104
|
+
pauseSandbox: async (
|
|
105
|
+
sandboxId: string,
|
|
106
|
+
ttlSeconds?: number
|
|
107
|
+
): Promise<void> => {
|
|
108
|
+
await this.pause(sandboxId, ttlSeconds);
|
|
109
|
+
},
|
|
98
110
|
snapshotSandbox: async (sandboxId: string): Promise<SandboxSnapshot> => {
|
|
99
111
|
return this.snapshot(sandboxId);
|
|
100
112
|
},
|
package/src/lib/sandbox/types.ts
CHANGED
|
@@ -35,8 +35,15 @@ export interface SandboxFileSystem {
|
|
|
35
35
|
mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
|
|
36
36
|
readdir(path: string): Promise<string[]>;
|
|
37
37
|
readdirWithFileTypes(path: string): Promise<DirentEntry[]>;
|
|
38
|
-
rm(
|
|
39
|
-
|
|
38
|
+
rm(
|
|
39
|
+
path: string,
|
|
40
|
+
options?: { recursive?: boolean; force?: boolean }
|
|
41
|
+
): Promise<void>;
|
|
42
|
+
cp(
|
|
43
|
+
src: string,
|
|
44
|
+
dest: string,
|
|
45
|
+
options?: { recursive?: boolean }
|
|
46
|
+
): Promise<void>;
|
|
40
47
|
mv(src: string, dest: string): Promise<void>;
|
|
41
48
|
readlink(path: string): Promise<string>;
|
|
42
49
|
resolvePath(base: string, path: string): string;
|
|
@@ -125,6 +132,7 @@ export interface SandboxProvider<
|
|
|
125
132
|
create(options?: TOptions): Promise<SandboxCreateResult>;
|
|
126
133
|
get(sandboxId: string): Promise<TSandbox>;
|
|
127
134
|
destroy(sandboxId: string): Promise<void>;
|
|
135
|
+
pause(sandboxId: string, ttlSeconds?: number): Promise<void>;
|
|
128
136
|
snapshot(sandboxId: string): Promise<SandboxSnapshot>;
|
|
129
137
|
restore(snapshot: SandboxSnapshot): Promise<Sandbox>;
|
|
130
138
|
fork(sandboxId: string): Promise<Sandbox>;
|
|
@@ -138,9 +146,10 @@ export interface SandboxOps<
|
|
|
138
146
|
TOptions extends SandboxCreateOptions = SandboxCreateOptions,
|
|
139
147
|
> {
|
|
140
148
|
createSandbox(
|
|
141
|
-
options?: TOptions
|
|
149
|
+
options?: TOptions
|
|
142
150
|
): Promise<{ sandboxId: string; stateUpdate?: Record<string, unknown> }>;
|
|
143
151
|
destroySandbox(sandboxId: string): Promise<void>;
|
|
152
|
+
pauseSandbox(sandboxId: string): Promise<void>;
|
|
144
153
|
snapshotSandbox(sandboxId: string): Promise<SandboxSnapshot>;
|
|
145
154
|
forkSandbox(sandboxId: string): Promise<string>;
|
|
146
155
|
}
|
|
@@ -172,7 +181,7 @@ export class SandboxNotSupportedError extends ApplicationFailure {
|
|
|
172
181
|
super(
|
|
173
182
|
`Sandbox does not support: ${operation}`,
|
|
174
183
|
"SandboxNotSupportedError",
|
|
175
|
-
true
|
|
184
|
+
true
|
|
176
185
|
);
|
|
177
186
|
}
|
|
178
187
|
}
|