zeitlich 0.2.40 → 0.2.42
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 +12 -1
- package/dist/{activities-CvUrG3YG.d.cts → activities-Coafq5zr.d.cts} +2 -2
- package/dist/{activities-CULxRzJ1.d.ts → activities-CrN-ghLo.d.ts} +2 -2
- package/dist/adapters/sandbox/daytona/index.cjs +4 -23
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +18 -86
- package/dist/adapters/sandbox/daytona/index.d.ts +18 -86
- package/dist/adapters/sandbox/daytona/index.js +4 -23
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.cjs +1 -7
- package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.cts +9 -2
- package/dist/adapters/sandbox/daytona/workflow.d.ts +9 -2
- package/dist/adapters/sandbox/daytona/workflow.js +1 -7
- package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
- package/dist/adapters/sandbox/e2b/index.cjs +21 -3
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +48 -7
- package/dist/adapters/sandbox/e2b/index.d.ts +48 -7
- package/dist/adapters/sandbox/e2b/index.js +22 -5
- package/dist/adapters/sandbox/e2b/index.js.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.cts +4 -2
- package/dist/adapters/sandbox/e2b/workflow.d.ts +4 -2
- package/dist/adapters/sandbox/e2b/workflow.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +11 -0
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +11 -3
- package/dist/adapters/sandbox/inmemory/index.d.ts +11 -3
- package/dist/adapters/sandbox/inmemory/index.js +11 -1
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.cts +4 -2
- package/dist/adapters/sandbox/inmemory/workflow.d.ts +4 -2
- package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +6 -6
- package/dist/adapters/thread/anthropic/index.d.ts +6 -6
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +6 -6
- package/dist/adapters/thread/anthropic/workflow.d.ts +6 -6
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +6 -6
- package/dist/adapters/thread/google-genai/index.d.ts +6 -6
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +6 -6
- package/dist/adapters/thread/google-genai/workflow.d.ts +6 -6
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +6 -6
- package/dist/adapters/thread/langchain/index.d.ts +6 -6
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +6 -6
- package/dist/adapters/thread/langchain/workflow.d.ts +6 -6
- package/dist/index.cjs +316 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -17
- package/dist/index.d.ts +93 -17
- package/dist/index.js +317 -120
- package/dist/index.js.map +1 -1
- package/dist/{proxy-5EbwzaY4.d.cts → proxy-Bf7uI-Hw.d.cts} +1 -1
- package/dist/{proxy-wZufFfBh.d.ts → proxy-COqA95FW.d.ts} +1 -1
- package/dist/{thread-manager-BqBAIsED.d.ts → thread-manager-BhkOyQ1I.d.ts} +2 -2
- package/dist/{thread-manager-BNiIt5r8.d.ts → thread-manager-Bi1XlbpJ.d.ts} +2 -2
- package/dist/{thread-manager-DF8WuCRs.d.cts → thread-manager-BsLO3Fgc.d.cts} +2 -2
- package/dist/{thread-manager-BoN5DOvG.d.cts → thread-manager-wRVVBFgj.d.cts} +2 -2
- package/dist/{types-C7OoY7h8.d.ts → types-BkX4HLzi.d.ts} +1 -1
- package/dist/{types-CuISs0Ub.d.cts → types-C66-BVBr.d.cts} +1 -1
- package/dist/types-CJ7tCdl6.d.cts +266 -0
- package/dist/types-CJ7tCdl6.d.ts +266 -0
- package/dist/{types-DeQH84C_.d.ts → types-CdALEF3z.d.cts} +342 -23
- package/dist/{types-Cn2r3ol3.d.cts → types-ChAy_jSP.d.ts} +342 -23
- package/dist/types-CjY93AWZ.d.cts +84 -0
- package/dist/types-gVa5XCWD.d.ts +84 -0
- package/dist/{workflow-DhplIN65.d.cts → workflow-BwT5EybR.d.ts} +7 -6
- package/dist/{workflow-C2MZZj5K.d.ts → workflow-DMmiaw6w.d.cts} +7 -6
- package/dist/workflow.cjs +138 -77
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +4 -4
- package/dist/workflow.d.ts +4 -4
- package/dist/workflow.js +139 -78
- package/dist/workflow.js.map +1 -1
- package/package.json +17 -33
- package/src/adapters/sandbox/daytona/index.ts +25 -48
- package/src/adapters/sandbox/daytona/proxy.ts +7 -8
- package/src/adapters/sandbox/e2b/README.md +81 -0
- package/src/adapters/sandbox/e2b/index.ts +53 -11
- package/src/adapters/sandbox/e2b/keep-alive.test.ts +115 -0
- package/src/adapters/sandbox/e2b/proxy.ts +3 -2
- package/src/adapters/sandbox/e2b/types.ts +34 -2
- package/src/adapters/sandbox/inmemory/index.ts +21 -1
- package/src/adapters/sandbox/inmemory/proxy.ts +7 -3
- package/src/index.ts +1 -1
- package/src/lib/activity.ts +5 -0
- package/src/lib/sandbox/capability-types.test.ts +859 -0
- package/src/lib/sandbox/index.ts +1 -0
- package/src/lib/sandbox/manager.ts +187 -31
- package/src/lib/sandbox/types.ts +189 -46
- package/src/lib/session/index.ts +1 -0
- package/src/lib/session/session.integration.test.ts +58 -0
- package/src/lib/session/session.ts +109 -50
- package/src/lib/session/types.ts +189 -8
- package/src/lib/subagent/handler.ts +66 -43
- package/src/lib/subagent/subagent.integration.test.ts +2 -0
- package/src/lib/subagent/types.ts +492 -16
- package/src/lib/subagent/workflow.ts +11 -1
- package/src/lib/tool-router/auto-append-sandbox.integration.test.ts +158 -0
- package/src/lib/tool-router/index.ts +1 -1
- package/src/lib/tool-router/with-sandbox.ts +45 -2
- package/src/lib/virtual-fs/filesystem.ts +41 -16
- package/src/lib/virtual-fs/types.ts +19 -0
- package/src/lib/virtual-fs/virtual-fs.test.ts +204 -1
- package/src/tools/read-file/handler.test.ts +83 -0
- package/src/workflow.ts +3 -0
- package/tsup.config.ts +0 -4
- package/dist/adapters/sandbox/bedrock/index.cjs +0 -457
- package/dist/adapters/sandbox/bedrock/index.cjs.map +0 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +0 -25
- package/dist/adapters/sandbox/bedrock/index.d.ts +0 -25
- package/dist/adapters/sandbox/bedrock/index.js +0 -454
- package/dist/adapters/sandbox/bedrock/index.js.map +0 -1
- package/dist/adapters/sandbox/bedrock/workflow.cjs +0 -36
- package/dist/adapters/sandbox/bedrock/workflow.cjs.map +0 -1
- package/dist/adapters/sandbox/bedrock/workflow.d.cts +0 -29
- package/dist/adapters/sandbox/bedrock/workflow.d.ts +0 -29
- package/dist/adapters/sandbox/bedrock/workflow.js +0 -34
- package/dist/adapters/sandbox/bedrock/workflow.js.map +0 -1
- package/dist/types-DAsQ21Rt.d.ts +0 -74
- package/dist/types-lm8tMNJQ.d.cts +0 -74
- package/dist/types-yx0LzPGn.d.cts +0 -173
- package/dist/types-yx0LzPGn.d.ts +0 -173
- package/src/adapters/sandbox/bedrock/filesystem.ts +0 -340
- package/src/adapters/sandbox/bedrock/index.ts +0 -274
- package/src/adapters/sandbox/bedrock/proxy.ts +0 -59
- package/src/adapters/sandbox/bedrock/types.ts +0 -24
package/src/lib/sandbox/index.ts
CHANGED
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Sandbox,
|
|
3
|
+
SandboxCapability,
|
|
3
4
|
SandboxCreateOptions,
|
|
4
5
|
SandboxOps,
|
|
5
6
|
PrefixedSandboxOps,
|
|
6
7
|
SandboxProvider,
|
|
7
8
|
SandboxSnapshot,
|
|
8
9
|
} from "./types";
|
|
10
|
+
import { SandboxNotSupportedError } from "./types";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Method names the manager treats as capability-gated, mirroring the
|
|
14
|
+
* conditional fields on {@link SandboxProvider}. The full list is used
|
|
15
|
+
* by the constructor-time consistency check below to assert that, for
|
|
16
|
+
* each gated method present on the provider at runtime, the matching
|
|
17
|
+
* capability is also declared in `supportedCapabilities` (and vice
|
|
18
|
+
* versa). This is the runtime half of the type↔runtime alignment guard
|
|
19
|
+
* the type-level constraint can't enforce on its own.
|
|
20
|
+
*/
|
|
21
|
+
const CAP_METHOD_TO_CAPABILITY: ReadonlyArray<{
|
|
22
|
+
method: string;
|
|
23
|
+
capability: SandboxCapability;
|
|
24
|
+
}> = [
|
|
25
|
+
{ method: "pause", capability: "pause" },
|
|
26
|
+
{ method: "resume", capability: "resume" },
|
|
27
|
+
{ method: "snapshot", capability: "snapshot" },
|
|
28
|
+
{ method: "deleteSnapshot", capability: "snapshot" },
|
|
29
|
+
{ method: "restore", capability: "restore" },
|
|
30
|
+
{ method: "fork", capability: "fork" },
|
|
31
|
+
];
|
|
9
32
|
|
|
10
33
|
/**
|
|
11
34
|
* Result returned by {@link SandboxManagerHooks.onPreCreate}.
|
|
@@ -61,8 +84,16 @@ export interface SandboxManagerHooks<
|
|
|
61
84
|
/**
|
|
62
85
|
* Stateless facade over a {@link SandboxProvider}.
|
|
63
86
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
87
|
+
* Generic over the same capability set (`TCaps`) as the underlying
|
|
88
|
+
* provider. The manager's lifecycle methods are always present on the
|
|
89
|
+
* class (so existing call sites compile unchanged), but
|
|
90
|
+
* {@link SandboxManager.createActivities} is capability-gated: only
|
|
91
|
+
* activities whose capability the provider declares via
|
|
92
|
+
* {@link SandboxProvider.supportedCapabilities} are wrapped, and the
|
|
93
|
+
* returned object's type omits absent ones.
|
|
94
|
+
*
|
|
95
|
+
* The default `TCaps = SandboxCapability` keeps the full method surface
|
|
96
|
+
* for existing usages that only pass `TOptions` / `TSandbox` / `TId`.
|
|
66
97
|
*
|
|
67
98
|
* Optional {@link SandboxManagerHooks} can be passed at construction time.
|
|
68
99
|
* The `onPreCreate` hook runs inside the `createSandbox` activity, receiving
|
|
@@ -105,16 +136,62 @@ export class SandboxManager<
|
|
|
105
136
|
TSandbox extends Sandbox = Sandbox,
|
|
106
137
|
TId extends string = string,
|
|
107
138
|
TCtx = unknown,
|
|
139
|
+
TCaps extends SandboxCapability = SandboxCapability,
|
|
108
140
|
> {
|
|
109
141
|
private hooks: SandboxManagerHooks<TOptions, TCtx>;
|
|
110
142
|
|
|
111
143
|
constructor(
|
|
112
|
-
private provider: SandboxProvider<TOptions, TSandbox> & {
|
|
144
|
+
private provider: SandboxProvider<TOptions, TSandbox, TCaps> & {
|
|
113
145
|
readonly id: TId;
|
|
114
146
|
},
|
|
115
147
|
options?: { hooks?: SandboxManagerHooks<TOptions, TCtx> }
|
|
116
148
|
) {
|
|
117
149
|
this.hooks = options?.hooks ?? {};
|
|
150
|
+
this.assertCapabilityRuntimeConsistency();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Verifies that the provider's runtime `supportedCapabilities` set is
|
|
155
|
+
* consistent with the gated methods physically present on the provider.
|
|
156
|
+
*
|
|
157
|
+
* Belt-and-suspenders complement to the type-level
|
|
158
|
+
* `ReadonlySet<TCaps & SandboxCapability>` constraint: TypeScript can
|
|
159
|
+
* prevent the runtime set from containing capabilities not declared in
|
|
160
|
+
* `TCaps`, but it cannot detect a provider that **declares** a cap in
|
|
161
|
+
* `TCaps` and forgets to include it in the runtime set (or that ships
|
|
162
|
+
* a method without listing its cap). Both shapes silently break
|
|
163
|
+
* activity registration, so we trip a loud failure at construction
|
|
164
|
+
* time instead.
|
|
165
|
+
*
|
|
166
|
+
* Adapters that derive both surfaces from a single `as const`
|
|
167
|
+
* capability array (the recommended pattern) pass this check by
|
|
168
|
+
* construction.
|
|
169
|
+
*/
|
|
170
|
+
private assertCapabilityRuntimeConsistency(): void {
|
|
171
|
+
const supported = this.provider
|
|
172
|
+
.supportedCapabilities as ReadonlySet<SandboxCapability>;
|
|
173
|
+
for (const { method, capability } of CAP_METHOD_TO_CAPABILITY) {
|
|
174
|
+
const hasMethod =
|
|
175
|
+
typeof (this.provider as unknown as Record<string, unknown>)[method] ===
|
|
176
|
+
"function";
|
|
177
|
+
const declaresCap = supported.has(capability);
|
|
178
|
+
if (hasMethod && !declaresCap) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Sandbox provider "${this.provider.id}" implements ${method}() but ` +
|
|
181
|
+
`does not list "${capability}" in supportedCapabilities. ` +
|
|
182
|
+
`Add the capability to the provider's runtime set so activities ` +
|
|
183
|
+
`for it can be registered.`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
if (declaresCap && !hasMethod) {
|
|
187
|
+
throw new Error(
|
|
188
|
+
`Sandbox provider "${this.provider.id}" lists "${capability}" in ` +
|
|
189
|
+
`supportedCapabilities but does not implement ${method}(). ` +
|
|
190
|
+
`Either add the method to the provider or remove the capability ` +
|
|
191
|
+
`from supportedCapabilities.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
118
195
|
}
|
|
119
196
|
|
|
120
197
|
async create(
|
|
@@ -165,35 +242,84 @@ export class SandboxManager<
|
|
|
165
242
|
await this.provider.destroy(id);
|
|
166
243
|
}
|
|
167
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Capability-gated lifecycle methods on the underlying provider.
|
|
247
|
+
*
|
|
248
|
+
* These manager methods always exist at runtime; calling one whose
|
|
249
|
+
* capability is absent from the provider's `supportedCapabilities`
|
|
250
|
+
* throws an error. The activities returned from
|
|
251
|
+
* {@link SandboxManager.createActivities} are gated at the type level
|
|
252
|
+
* via `TCaps`, which is where compile-time safety is enforced.
|
|
253
|
+
*/
|
|
168
254
|
async pause(id: string, ttlSeconds?: number): Promise<void> {
|
|
169
|
-
|
|
255
|
+
const fn = this.providerMethod("pause") as
|
|
256
|
+
| ((id: string, ttlSeconds?: number) => Promise<void>)
|
|
257
|
+
| undefined;
|
|
258
|
+
if (!fn) throw this.unsupported("pause");
|
|
259
|
+
await fn.call(this.provider, id, ttlSeconds);
|
|
170
260
|
}
|
|
171
261
|
|
|
172
262
|
async resume(id: string): Promise<void> {
|
|
173
|
-
|
|
263
|
+
const fn = this.providerMethod("resume") as
|
|
264
|
+
| ((id: string) => Promise<void>)
|
|
265
|
+
| undefined;
|
|
266
|
+
if (!fn) throw this.unsupported("resume");
|
|
267
|
+
await fn.call(this.provider, id);
|
|
174
268
|
}
|
|
175
269
|
|
|
176
270
|
async snapshot(id: string, options?: TOptions): Promise<SandboxSnapshot> {
|
|
177
|
-
|
|
271
|
+
const fn = this.providerMethod("snapshot") as
|
|
272
|
+
| ((id: string, options?: TOptions) => Promise<SandboxSnapshot>)
|
|
273
|
+
| undefined;
|
|
274
|
+
if (!fn) throw this.unsupported("snapshot");
|
|
275
|
+
return fn.call(this.provider, id, options);
|
|
178
276
|
}
|
|
179
277
|
|
|
180
278
|
async restore(
|
|
181
279
|
snapshot: SandboxSnapshot,
|
|
182
280
|
options?: TOptions
|
|
183
281
|
): Promise<string> {
|
|
184
|
-
const
|
|
282
|
+
const fn = this.providerMethod("restore") as
|
|
283
|
+
| ((snap: SandboxSnapshot, options?: TOptions) => Promise<TSandbox>)
|
|
284
|
+
| undefined;
|
|
285
|
+
if (!fn) throw this.unsupported("restore");
|
|
286
|
+
const sandbox = await fn.call(this.provider, snapshot, options);
|
|
185
287
|
return sandbox.id;
|
|
186
288
|
}
|
|
187
289
|
|
|
188
290
|
async deleteSnapshot(snapshot: SandboxSnapshot): Promise<void> {
|
|
189
|
-
|
|
291
|
+
const fn = this.providerMethod("deleteSnapshot") as
|
|
292
|
+
| ((snap: SandboxSnapshot) => Promise<void>)
|
|
293
|
+
| undefined;
|
|
294
|
+
if (!fn) throw this.unsupported("deleteSnapshot");
|
|
295
|
+
await fn.call(this.provider, snapshot);
|
|
190
296
|
}
|
|
191
297
|
|
|
192
298
|
async fork(sandboxId: string, options?: TOptions): Promise<string> {
|
|
193
|
-
const
|
|
299
|
+
const fn = this.providerMethod("fork") as
|
|
300
|
+
| ((id: string, options?: TOptions) => Promise<TSandbox>)
|
|
301
|
+
| undefined;
|
|
302
|
+
if (!fn) throw this.unsupported("fork");
|
|
303
|
+
const sandbox = await fn.call(this.provider, sandboxId, options);
|
|
194
304
|
return sandbox.id;
|
|
195
305
|
}
|
|
196
306
|
|
|
307
|
+
private providerMethod(name: string): unknown {
|
|
308
|
+
const value = (this.provider as unknown as Record<string, unknown>)[name];
|
|
309
|
+
return typeof value === "function" ? value : undefined;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Constructs the structured error thrown when an unsupported lifecycle
|
|
314
|
+
* method is invoked through the manager. Uses the public
|
|
315
|
+
* {@link SandboxNotSupportedError} symbol so consumers that catch on
|
|
316
|
+
* `instanceof SandboxNotSupportedError` (the documented compatibility
|
|
317
|
+
* path) keep matching after the refactor.
|
|
318
|
+
*/
|
|
319
|
+
private unsupported(name: string): SandboxNotSupportedError {
|
|
320
|
+
return new SandboxNotSupportedError(name);
|
|
321
|
+
}
|
|
322
|
+
|
|
197
323
|
/**
|
|
198
324
|
* Returns Temporal activity functions with prefixed names.
|
|
199
325
|
*
|
|
@@ -201,6 +327,11 @@ export class SandboxManager<
|
|
|
201
327
|
* to pass the workflow/scope name. Use the matching `proxy*SandboxOps()`
|
|
202
328
|
* helper from the adapter's `/workflow` entrypoint on the workflow side.
|
|
203
329
|
*
|
|
330
|
+
* Activities are only registered for capabilities the provider declares
|
|
331
|
+
* via {@link SandboxProvider.supportedCapabilities}: methods omitted
|
|
332
|
+
* from the cap set are not wrapped, and the returned object's type
|
|
333
|
+
* omits the corresponding keys.
|
|
334
|
+
*
|
|
204
335
|
* @param scope - Workflow name (appended to the provider id)
|
|
205
336
|
*
|
|
206
337
|
* @example
|
|
@@ -211,14 +342,25 @@ export class SandboxManager<
|
|
|
211
342
|
*
|
|
212
343
|
* const dmgr = new SandboxManager(new DaytonaSandboxProvider(config));
|
|
213
344
|
* dmgr.createActivities("CodingAgent");
|
|
214
|
-
* // registers: daytonaCodingAgentCreateSandbox,
|
|
345
|
+
* // registers: daytonaCodingAgentCreateSandbox, daytonaCodingAgentDestroySandbox
|
|
346
|
+
* // (snapshot/restore/fork/pause/resume omitted — Daytona doesn't declare them)
|
|
215
347
|
* ```
|
|
216
348
|
*/
|
|
217
349
|
createActivities<S extends string>(
|
|
218
350
|
scope: S
|
|
219
|
-
): PrefixedSandboxOps<`${TId}${Capitalize<S>}`, TOptions, TCtx> {
|
|
351
|
+
): PrefixedSandboxOps<`${TId}${Capitalize<S>}`, TOptions, TCtx, TCaps> {
|
|
220
352
|
const prefix = `${this.provider.id}${scope.charAt(0).toUpperCase()}${scope.slice(1)}`;
|
|
221
|
-
const
|
|
353
|
+
const cap = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);
|
|
354
|
+
// The set is statically typed against the (possibly narrow) `TCaps`,
|
|
355
|
+
// but we need to probe every well-known capability here. Widen for
|
|
356
|
+
// the duration of the lookup; the constructor-time consistency check
|
|
357
|
+
// already ensures these probes can't accidentally observe a method
|
|
358
|
+
// present on the provider that's missing from the declared set.
|
|
359
|
+
const supported = this.provider
|
|
360
|
+
.supportedCapabilities as ReadonlySet<SandboxCapability>;
|
|
361
|
+
|
|
362
|
+
type WideOps = SandboxOps<TOptions, TCtx>;
|
|
363
|
+
const ops: Partial<WideOps> = {
|
|
222
364
|
createSandbox: async (
|
|
223
365
|
options?: TOptions,
|
|
224
366
|
ctx?: TCtx
|
|
@@ -228,42 +370,56 @@ export class SandboxManager<
|
|
|
228
370
|
destroySandbox: async (sandboxId: string): Promise<void> => {
|
|
229
371
|
await this.destroy(sandboxId);
|
|
230
372
|
},
|
|
231
|
-
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
if (supported.has("pause")) {
|
|
376
|
+
ops.pauseSandbox = async (
|
|
232
377
|
sandboxId: string,
|
|
233
378
|
ttlSeconds?: number
|
|
234
379
|
): Promise<void> => {
|
|
235
380
|
await this.pause(sandboxId, ttlSeconds);
|
|
236
|
-
}
|
|
237
|
-
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
if (supported.has("resume")) {
|
|
384
|
+
ops.resumeSandbox = async (sandboxId: string): Promise<void> => {
|
|
238
385
|
await this.resume(sandboxId);
|
|
239
|
-
}
|
|
240
|
-
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
if (supported.has("snapshot")) {
|
|
389
|
+
ops.snapshotSandbox = async (
|
|
241
390
|
sandboxId: string,
|
|
242
391
|
options?: TOptions
|
|
243
392
|
): Promise<SandboxSnapshot> => {
|
|
244
393
|
return this.snapshot(sandboxId, options);
|
|
245
|
-
}
|
|
246
|
-
|
|
394
|
+
};
|
|
395
|
+
ops.deleteSandboxSnapshot = async (
|
|
396
|
+
snapshot: SandboxSnapshot
|
|
397
|
+
): Promise<void> => {
|
|
398
|
+
await this.deleteSnapshot(snapshot);
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
if (supported.has("restore")) {
|
|
402
|
+
ops.restoreSandbox = async (
|
|
247
403
|
snapshot: SandboxSnapshot,
|
|
248
404
|
options?: TOptions
|
|
249
405
|
): Promise<string> => {
|
|
250
406
|
return this.restore(snapshot, options);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
await this.deleteSnapshot(snapshot);
|
|
256
|
-
},
|
|
257
|
-
forkSandbox: async (
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
if (supported.has("fork")) {
|
|
410
|
+
ops.forkSandbox = async (
|
|
258
411
|
sandboxId: string,
|
|
259
412
|
options?: TOptions
|
|
260
413
|
): Promise<string> => {
|
|
261
414
|
return this.fork(sandboxId, options);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const entries = Object.entries(ops).filter(
|
|
419
|
+
([, v]) => typeof v === "function"
|
|
420
|
+
);
|
|
265
421
|
return Object.fromEntries(
|
|
266
|
-
|
|
267
|
-
) as PrefixedSandboxOps<`${TId}${Capitalize<S>}`, TOptions, TCtx>;
|
|
422
|
+
entries.map(([k, v]) => [`${prefix}${cap(k)}`, v])
|
|
423
|
+
) as PrefixedSandboxOps<`${TId}${Capitalize<S>}`, TOptions, TCtx, TCaps>;
|
|
268
424
|
}
|
|
269
425
|
}
|
package/src/lib/sandbox/types.ts
CHANGED
|
@@ -84,6 +84,14 @@ export interface ExecResult {
|
|
|
84
84
|
// Capabilities
|
|
85
85
|
// ============================================================================
|
|
86
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Runtime capability flags carried by a {@link Sandbox} instance.
|
|
89
|
+
*
|
|
90
|
+
* These are an orthogonal mechanism to the type-level
|
|
91
|
+
* {@link SandboxCapability} union: this flag bag is for runtime
|
|
92
|
+
* introspection ("does the sandbox support a filesystem?") whereas
|
|
93
|
+
* {@link SandboxCapability} narrows the type-level provider/ops contract.
|
|
94
|
+
*/
|
|
87
95
|
export interface SandboxCapabilities {
|
|
88
96
|
/** Sandbox supports filesystem operations */
|
|
89
97
|
filesystem: boolean;
|
|
@@ -93,6 +101,24 @@ export interface SandboxCapabilities {
|
|
|
93
101
|
persistence: boolean;
|
|
94
102
|
}
|
|
95
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Type-level capability vocabulary for {@link SandboxProvider} and
|
|
106
|
+
* {@link SandboxOps}. Adapters declare the subset they actually support; the
|
|
107
|
+
* conditional types on each contract gate the corresponding methods so
|
|
108
|
+
* unsupported calls become a compile-time error rather than a runtime
|
|
109
|
+
* {@link SandboxNotSupportedError}.
|
|
110
|
+
*
|
|
111
|
+
* `pause` and `resume` are split because some adapters might support one
|
|
112
|
+
* direction without the other. The `snapshot` cap covers both `snapshot()`
|
|
113
|
+
* and `deleteSnapshot()` since they always travel together in practice.
|
|
114
|
+
*/
|
|
115
|
+
export type SandboxCapability =
|
|
116
|
+
| "pause"
|
|
117
|
+
| "resume"
|
|
118
|
+
| "snapshot"
|
|
119
|
+
| "restore"
|
|
120
|
+
| "fork";
|
|
121
|
+
|
|
96
122
|
// ============================================================================
|
|
97
123
|
// Sandbox
|
|
98
124
|
// ============================================================================
|
|
@@ -145,88 +171,196 @@ export interface SandboxCreateResult {
|
|
|
145
171
|
sandbox: Sandbox;
|
|
146
172
|
}
|
|
147
173
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Internal helper: drop keys whose value is `never` from an object type.
|
|
176
|
+
*
|
|
177
|
+
* Used by the capability-gated contracts below so that an absent capability
|
|
178
|
+
* removes the corresponding key entirely, instead of leaving a required
|
|
179
|
+
* field with type `never` (which would make implementations impossible).
|
|
180
|
+
*/
|
|
181
|
+
type OmitNever<T> = {
|
|
182
|
+
[K in keyof T as [T[K]] extends [never] ? never : K]: T[K];
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Capability-gated provider lifecycle methods.
|
|
187
|
+
*
|
|
188
|
+
* Each field becomes `never` when its capability is absent from `TCaps`;
|
|
189
|
+
* the wrapping `OmitNever` removes those keys entirely, so the method
|
|
190
|
+
* isn't part of the type surface for adapters that don't support it.
|
|
191
|
+
*/
|
|
192
|
+
type SandboxProviderCapMethods<
|
|
193
|
+
TOptions extends SandboxCreateOptions,
|
|
194
|
+
TSandbox extends Sandbox,
|
|
195
|
+
TCaps extends SandboxCapability,
|
|
196
|
+
> = OmitNever<{
|
|
197
|
+
pause: "pause" extends TCaps
|
|
198
|
+
? (sandboxId: string, ttlSeconds?: number) => Promise<void>
|
|
199
|
+
: never;
|
|
200
|
+
resume: "resume" extends TCaps ? (sandboxId: string) => Promise<void> : never;
|
|
201
|
+
snapshot: "snapshot" extends TCaps
|
|
202
|
+
? (sandboxId: string, options?: TOptions) => Promise<SandboxSnapshot>
|
|
203
|
+
: never;
|
|
204
|
+
deleteSnapshot: "snapshot" extends TCaps
|
|
205
|
+
? (snapshot: SandboxSnapshot) => Promise<void>
|
|
206
|
+
: never;
|
|
207
|
+
restore: "restore" extends TCaps
|
|
208
|
+
? (snapshot: SandboxSnapshot, options?: TOptions) => Promise<TSandbox>
|
|
209
|
+
: never;
|
|
210
|
+
fork: "fork" extends TCaps
|
|
211
|
+
? (sandboxId: string, options?: TOptions) => Promise<TSandbox>
|
|
212
|
+
: never;
|
|
213
|
+
}>;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Always-present provider lifecycle methods. These do not depend on the
|
|
217
|
+
* capability set and are required by every adapter.
|
|
218
|
+
*/
|
|
219
|
+
interface SandboxProviderBase<
|
|
220
|
+
TOptions extends SandboxCreateOptions,
|
|
221
|
+
TSandbox extends Sandbox,
|
|
222
|
+
TCaps extends SandboxCapability,
|
|
151
223
|
> {
|
|
152
224
|
readonly id: string;
|
|
153
225
|
readonly capabilities: SandboxCapabilities;
|
|
226
|
+
/**
|
|
227
|
+
* Runtime-introspectable list of supported capabilities.
|
|
228
|
+
*
|
|
229
|
+
* Constrained to `ReadonlySet<TCaps & SandboxCapability>` so the runtime
|
|
230
|
+
* set cannot include capabilities not declared at the type level — a
|
|
231
|
+
* provider typed as `SandboxProvider<…, never>` cannot ship a runtime
|
|
232
|
+
* set that contains `"pause"`, etc.
|
|
233
|
+
*
|
|
234
|
+
* The other direction (type declares a cap, runtime set omits it)
|
|
235
|
+
* cannot be enforced by TypeScript alone; adapters should derive both
|
|
236
|
+
* `TCaps` and the runtime set from the same `as const` array (see
|
|
237
|
+
* `SandboxManager`'s constructor-time consistency check) so the two
|
|
238
|
+
* surfaces cannot drift.
|
|
239
|
+
*/
|
|
240
|
+
readonly supportedCapabilities: ReadonlySet<TCaps & SandboxCapability>;
|
|
154
241
|
|
|
155
242
|
create(options?: TOptions): Promise<SandboxCreateResult>;
|
|
156
243
|
get(sandboxId: string): Promise<TSandbox>;
|
|
157
244
|
destroy(sandboxId: string): Promise<void>;
|
|
158
|
-
pause(sandboxId: string, ttlSeconds?: number): Promise<void>;
|
|
159
|
-
/** Resume a paused sandbox. No-op if already running. */
|
|
160
|
-
resume(sandboxId: string): Promise<void>;
|
|
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>;
|
|
178
245
|
}
|
|
179
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Provider-side sandbox lifecycle contract.
|
|
249
|
+
*
|
|
250
|
+
* Generic over an optional capability set (`TCaps`). Each capability gates
|
|
251
|
+
* a specific method: when the cap is absent the corresponding key is
|
|
252
|
+
* **removed** from the type entirely, so calling it produces a TypeScript
|
|
253
|
+
* error at the call site instead of a runtime
|
|
254
|
+
* {@link SandboxNotSupportedError}.
|
|
255
|
+
*
|
|
256
|
+
* The default `TCaps = SandboxCapability` resolves to the full union, so
|
|
257
|
+
* existing usages that only pass `TOptions` / `TSandbox` continue to see
|
|
258
|
+
* the full method surface (backwards compatible).
|
|
259
|
+
*
|
|
260
|
+
* Adapters that don't support a method should narrow `TCaps` accordingly:
|
|
261
|
+
*
|
|
262
|
+
* - In-memory / E2B: `SandboxCapability` (default — all caps present).
|
|
263
|
+
* - Bedrock Code Interpreter / Daytona: `never` (only base ops).
|
|
264
|
+
* - Bedrock AgentCore Runtime: `"pause" | "resume"`.
|
|
265
|
+
*/
|
|
266
|
+
export type SandboxProvider<
|
|
267
|
+
TOptions extends SandboxCreateOptions = SandboxCreateOptions,
|
|
268
|
+
TSandbox extends Sandbox = Sandbox,
|
|
269
|
+
TCaps extends SandboxCapability = SandboxCapability,
|
|
270
|
+
> = SandboxProviderBase<TOptions, TSandbox, TCaps> &
|
|
271
|
+
SandboxProviderCapMethods<TOptions, TSandbox, TCaps>;
|
|
272
|
+
|
|
180
273
|
// ============================================================================
|
|
181
274
|
// SandboxOps — workflow-side activity interface (like ThreadOps)
|
|
182
275
|
// ============================================================================
|
|
183
276
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Capability-gated workflow-side methods. Mirrors the provider's gating:
|
|
279
|
+
* keys whose capability is absent from `TCaps` are removed from the type.
|
|
280
|
+
*/
|
|
281
|
+
type SandboxOpsCapMethods<
|
|
282
|
+
TOptions extends SandboxCreateOptions,
|
|
283
|
+
TCaps extends SandboxCapability,
|
|
284
|
+
> = OmitNever<{
|
|
285
|
+
pauseSandbox: "pause" extends TCaps
|
|
286
|
+
? (sandboxId: string) => Promise<void>
|
|
287
|
+
: never;
|
|
288
|
+
resumeSandbox: "resume" extends TCaps
|
|
289
|
+
? (sandboxId: string) => Promise<void>
|
|
290
|
+
: never;
|
|
291
|
+
snapshotSandbox: "snapshot" extends TCaps
|
|
292
|
+
? (sandboxId: string, options?: TOptions) => Promise<SandboxSnapshot>
|
|
293
|
+
: never;
|
|
294
|
+
deleteSandboxSnapshot: "snapshot" extends TCaps
|
|
295
|
+
? (snapshot: SandboxSnapshot) => Promise<void>
|
|
296
|
+
: never;
|
|
297
|
+
restoreSandbox: "restore" extends TCaps
|
|
298
|
+
? (snapshot: SandboxSnapshot, options?: TOptions) => Promise<string>
|
|
299
|
+
: never;
|
|
300
|
+
forkSandbox: "fork" extends TCaps
|
|
301
|
+
? (sandboxId: string, options?: TOptions) => Promise<string>
|
|
302
|
+
: never;
|
|
303
|
+
}>;
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Always-present workflow-side lifecycle methods.
|
|
307
|
+
*/
|
|
308
|
+
interface SandboxOpsBase<
|
|
309
|
+
TOptions extends SandboxCreateOptions,
|
|
310
|
+
TCtx,
|
|
187
311
|
> {
|
|
188
312
|
createSandbox(
|
|
189
313
|
options?: TOptions,
|
|
190
314
|
ctx?: TCtx
|
|
191
315
|
): Promise<{ sandboxId: string } | null>;
|
|
192
316
|
destroySandbox(sandboxId: string): Promise<void>;
|
|
193
|
-
pauseSandbox(sandboxId: string): Promise<void>;
|
|
194
|
-
/** Resume a paused sandbox. No-op if already running. */
|
|
195
|
-
resumeSandbox(sandboxId: string): Promise<void>;
|
|
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>;
|
|
210
317
|
}
|
|
211
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Workflow-side counterpart to {@link SandboxProvider}. Exposed as a set of
|
|
321
|
+
* Temporal activities and consumed by `createSession`'s `sandboxOps` field
|
|
322
|
+
* and by `defineSubagent`'s `sandbox.proxy`.
|
|
323
|
+
*
|
|
324
|
+
* Generic over a capability set (`TCaps`) — same semantics as the provider:
|
|
325
|
+
* keys whose capability is absent are removed from the type, so calling
|
|
326
|
+
* them is a TypeScript error rather than a runtime throw. The default
|
|
327
|
+
* `TCaps = SandboxCapability` keeps the full method surface for existing
|
|
328
|
+
* consumers.
|
|
329
|
+
*/
|
|
330
|
+
export type SandboxOps<
|
|
331
|
+
TOptions extends SandboxCreateOptions = SandboxCreateOptions,
|
|
332
|
+
TCtx = unknown,
|
|
333
|
+
TCaps extends SandboxCapability = SandboxCapability,
|
|
334
|
+
> = SandboxOpsBase<TOptions, TCtx> & SandboxOpsCapMethods<TOptions, TCaps>;
|
|
335
|
+
|
|
212
336
|
/**
|
|
213
337
|
* Maps generic {@link SandboxOps} method names to adapter-prefixed names.
|
|
214
338
|
*
|
|
339
|
+
* Inherits the capability gating from {@link SandboxOps}: when `TCaps` omits
|
|
340
|
+
* a capability the prefixed key carries the `never` type so call sites are
|
|
341
|
+
* type-protected.
|
|
342
|
+
*
|
|
215
343
|
* @example
|
|
216
344
|
* ```typescript
|
|
217
345
|
* type InMemOps = PrefixedSandboxOps<"inMemory">;
|
|
218
|
-
* // → { inMemoryCreateSandbox, inMemoryDestroySandbox, inMemorySnapshotSandbox }
|
|
346
|
+
* // → { inMemoryCreateSandbox, inMemoryDestroySandbox, inMemorySnapshotSandbox, … }
|
|
219
347
|
* ```
|
|
220
348
|
*/
|
|
221
349
|
export type PrefixedSandboxOps<
|
|
222
350
|
TPrefix extends string,
|
|
223
351
|
TOptions extends SandboxCreateOptions = SandboxCreateOptions,
|
|
224
352
|
TCtx = unknown,
|
|
353
|
+
TCaps extends SandboxCapability = SandboxCapability,
|
|
225
354
|
> = {
|
|
226
355
|
[K in keyof SandboxOps<
|
|
227
356
|
TOptions,
|
|
228
|
-
TCtx
|
|
229
|
-
|
|
357
|
+
TCtx,
|
|
358
|
+
TCaps
|
|
359
|
+
> as `${TPrefix}${Capitalize<K & string>}`]: SandboxOps<
|
|
360
|
+
TOptions,
|
|
361
|
+
TCtx,
|
|
362
|
+
TCaps
|
|
363
|
+
>[K];
|
|
230
364
|
};
|
|
231
365
|
|
|
232
366
|
// ============================================================================
|
|
@@ -235,6 +369,15 @@ export type PrefixedSandboxOps<
|
|
|
235
369
|
|
|
236
370
|
import { ApplicationFailure } from "@temporalio/common";
|
|
237
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Thrown by adapters that still surface an unsupported method at runtime.
|
|
374
|
+
*
|
|
375
|
+
* After the capability-generic refactor most adapters drop their
|
|
376
|
+
* unsupported methods entirely so the type system rejects them at call
|
|
377
|
+
* sites. This symbol is still exported so consumers running against older
|
|
378
|
+
* adapter versions can keep their backwards-compatible error-handling
|
|
379
|
+
* paths until they finish migrating.
|
|
380
|
+
*/
|
|
238
381
|
export class SandboxNotSupportedError extends ApplicationFailure {
|
|
239
382
|
constructor(operation: string) {
|
|
240
383
|
super(
|