@tangle-network/sandbox 0.0.0-develop.20260514223840.b2abd84
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/LICENSE +11 -0
- package/README.md +736 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +1 -0
- package/dist/client-CO5cnRwn.js +1 -0
- package/dist/collaboration/index.d.ts +2 -0
- package/dist/collaboration/index.js +1 -0
- package/dist/collaboration-CRyb5e8F.js +1 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +1 -0
- package/dist/errors-CljiGR__.js +1 -0
- package/dist/errors-Cy5W2uYq.d.ts +1116 -0
- package/dist/index-CCsA3S0D.d.ts +136 -0
- package/dist/index-Cka6RuZB.d.ts +371 -0
- package/dist/index-Dpj1oB5i.d.ts +220 -0
- package/dist/index.d.ts +555 -0
- package/dist/index.js +1 -0
- package/dist/openai/index.d.ts +642 -0
- package/dist/openai/index.js +1 -0
- package/dist/platform-integrations.d.ts +2 -0
- package/dist/platform-integrations.js +1 -0
- package/dist/sandbox-193cSjQB.js +1 -0
- package/dist/sandbox-CTe9fN5m.d.ts +4857 -0
- package/dist/session-gateway/index.d.ts +448 -0
- package/dist/session-gateway/index.js +1 -0
- package/dist/tangle/index.d.ts +2 -0
- package/dist/tangle/index.js +1 -0
- package/dist/tangle-B4_UoyBS.js +1 -0
- package/package.json +105 -0
|
@@ -0,0 +1,4857 @@
|
|
|
1
|
+
import { IntegrationActor, IntegrationManifest } from "@tangle-network/agent-integrations";
|
|
2
|
+
|
|
3
|
+
//#region src/mcp.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* MCP (Model Context Protocol) helpers for sandbox capabilities.
|
|
6
|
+
*
|
|
7
|
+
* The sandbox exposes capabilities (currently `computer_use`, more
|
|
8
|
+
* later) as MCP tools over Streamable HTTP. Any MCP-capable client —
|
|
9
|
+
* Claude Desktop, Cursor, claude-code, codex, opencode, raw
|
|
10
|
+
* `@modelcontextprotocol/sdk` apps — can consume this surface by
|
|
11
|
+
* pasting the JSON returned from `Sandbox#getMcpEndpoint()` (or
|
|
12
|
+
* `buildSandboxMcpConfig` if you already have the URL + token) into
|
|
13
|
+
* the client's MCP config.
|
|
14
|
+
*
|
|
15
|
+
* Security model:
|
|
16
|
+
* - Tokens are capability-scoped JWTs (claim `cap: ["computer_use"]`).
|
|
17
|
+
* - Full sandbox runtime tokens are rejected on `/mcp`; only
|
|
18
|
+
* capability-scoped tokens work there.
|
|
19
|
+
* - A scoped token cannot pivot to admin endpoints (`/exec`, `/files`,
|
|
20
|
+
* etc.) — those routes reject scoped tokens.
|
|
21
|
+
* - Tokens are short-lived. Rotate via `Sandbox#getMcpEndpoint()`,
|
|
22
|
+
* which mints a fresh token each call.
|
|
23
|
+
*/
|
|
24
|
+
/** Default name of the MCP server entry — surfaces in the host UI. */
|
|
25
|
+
declare const SANDBOX_MCP_SERVER_NAME = "tangle-sandbox";
|
|
26
|
+
/**
|
|
27
|
+
* MCP HTTP server entry — matches the Anthropic MCP HTTP transport
|
|
28
|
+
* schema (`type: "http"`, `url`, optional `headers`). Compatible with
|
|
29
|
+
* every MCP host that implements the spec.
|
|
30
|
+
*/
|
|
31
|
+
interface SandboxMcpServerEntry {
|
|
32
|
+
type: "http";
|
|
33
|
+
url: string;
|
|
34
|
+
headers: Record<string, string>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* `.mcp.json`-shaped config any MCP host accepts. Drop the contents of
|
|
38
|
+
* `mcpServers` into your host's `mcpServers` block (Claude Desktop,
|
|
39
|
+
* Cursor, claude-code's `--mcp-config`, etc.) — no host-specific
|
|
40
|
+
* fields, no provider lock-in.
|
|
41
|
+
*/
|
|
42
|
+
interface SandboxMcpConfig {
|
|
43
|
+
mcpServers: Record<string, SandboxMcpServerEntry>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Endpoint payload returned by `GET /v1/sandboxes/:id/mcp`. Includes
|
|
47
|
+
* the canonical config plus token expiry so callers can plan
|
|
48
|
+
* refreshes.
|
|
49
|
+
*/
|
|
50
|
+
interface SandboxMcpEndpoint {
|
|
51
|
+
/** MCP host config — paste this into Cursor/Claude Desktop/etc. */
|
|
52
|
+
config: SandboxMcpConfig;
|
|
53
|
+
/** Server entry name used inside `config.mcpServers`. */
|
|
54
|
+
serverName: string;
|
|
55
|
+
/** Reachable URL for the MCP HTTP transport. */
|
|
56
|
+
url: string;
|
|
57
|
+
/** Bearer token sent by the MCP host on every request. */
|
|
58
|
+
authToken: string;
|
|
59
|
+
/** ISO-8601 expiry — the host should refresh before this. */
|
|
60
|
+
expiresAt: string;
|
|
61
|
+
/** Capabilities the token is scoped to. */
|
|
62
|
+
capabilities: ReadonlyArray<"computer_use">;
|
|
63
|
+
}
|
|
64
|
+
interface BuildSandboxMcpConfigOptions {
|
|
65
|
+
/** Public sandbox URL where `/mcp` is reachable. No trailing slash. */
|
|
66
|
+
sandboxUrl: string;
|
|
67
|
+
/** Capability-scoped JWT minted by the Sandbox API. */
|
|
68
|
+
authToken: string;
|
|
69
|
+
/** Override the entry name. Defaults to SANDBOX_MCP_SERVER_NAME. */
|
|
70
|
+
serverName?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build the canonical `mcpServers` config for a sandbox MCP endpoint.
|
|
74
|
+
* Pure function — no I/O, no crypto. Use this when you already have a
|
|
75
|
+
* `{ url, authToken }` pair from the API and just want the JSON shape
|
|
76
|
+
* to paste into a host. Most callers should use
|
|
77
|
+
* `Sandbox#getMcpEndpoint()` instead, which fetches a freshly-minted
|
|
78
|
+
* token from the API.
|
|
79
|
+
*/
|
|
80
|
+
declare function buildSandboxMcpConfig(options: BuildSandboxMcpConfigOptions): {
|
|
81
|
+
serverName: string;
|
|
82
|
+
config: SandboxMcpConfig;
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/agent-profile.d.ts
|
|
86
|
+
/**
|
|
87
|
+
* Provider-neutral agent profile types for public SDK consumers.
|
|
88
|
+
*
|
|
89
|
+
* These model portable agent intent at the application boundary.
|
|
90
|
+
* Individual backends can translate this shape into their own native
|
|
91
|
+
* profile/configuration formats internally.
|
|
92
|
+
*/
|
|
93
|
+
/**
|
|
94
|
+
* Permission policy value for a capability.
|
|
95
|
+
*/
|
|
96
|
+
type AgentProfilePermissionValue = "allow" | "ask" | "deny";
|
|
97
|
+
type AgentProfilePermission = AgentProfilePermissionValue | Record<string, AgentProfilePermissionValue>;
|
|
98
|
+
/**
|
|
99
|
+
* Generic resource reference that can be resolved into a file or instruction.
|
|
100
|
+
*/
|
|
101
|
+
type AgentProfileResourceRef = {
|
|
102
|
+
kind: "inline";
|
|
103
|
+
name: string;
|
|
104
|
+
content: string;
|
|
105
|
+
} | {
|
|
106
|
+
kind: "github";
|
|
107
|
+
/**
|
|
108
|
+
* Optional repository in "owner/repo" form. When omitted, providers may
|
|
109
|
+
* only resolve the path if they have an ambient repository context.
|
|
110
|
+
*/
|
|
111
|
+
repository?: string;
|
|
112
|
+
path: string;
|
|
113
|
+
ref?: string;
|
|
114
|
+
name?: string;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Helper for creating typed inline resource refs.
|
|
118
|
+
*/
|
|
119
|
+
declare function defineInlineResource(name: string, content: string): AgentProfileResourceRef;
|
|
120
|
+
/**
|
|
121
|
+
* Helper for creating typed GitHub-backed resource refs.
|
|
122
|
+
*/
|
|
123
|
+
declare function defineGitHubResource(path: string, options?: {
|
|
124
|
+
repository?: string;
|
|
125
|
+
ref?: string;
|
|
126
|
+
name?: string;
|
|
127
|
+
}): AgentProfileResourceRef;
|
|
128
|
+
/**
|
|
129
|
+
* Resource mounted into a backend workspace.
|
|
130
|
+
*/
|
|
131
|
+
interface AgentProfileFileMount {
|
|
132
|
+
path: string;
|
|
133
|
+
resource: AgentProfileResourceRef;
|
|
134
|
+
executable?: boolean;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Provider-neutral resource bundle.
|
|
138
|
+
*/
|
|
139
|
+
interface AgentProfileResources {
|
|
140
|
+
/**
|
|
141
|
+
* Generic files to materialize into the agent workspace before execution.
|
|
142
|
+
*/
|
|
143
|
+
files?: AgentProfileFileMount[];
|
|
144
|
+
/**
|
|
145
|
+
* Provider-native tool files. Backends materialize these into their standard
|
|
146
|
+
* discovery location when they support file-based tools.
|
|
147
|
+
*/
|
|
148
|
+
tools?: AgentProfileResourceRef[];
|
|
149
|
+
/**
|
|
150
|
+
* Agent Skills (`SKILL.md`) packages. Supported by Cursor, Claude Code,
|
|
151
|
+
* Codex-compatible layouts, OpenCode, and Hermes-style skill harnesses.
|
|
152
|
+
*/
|
|
153
|
+
skills?: AgentProfileResourceRef[];
|
|
154
|
+
/**
|
|
155
|
+
* Provider-native subagent definition files.
|
|
156
|
+
*/
|
|
157
|
+
agents?: AgentProfileResourceRef[];
|
|
158
|
+
/**
|
|
159
|
+
* Provider-native slash command files.
|
|
160
|
+
*/
|
|
161
|
+
commands?: AgentProfileResourceRef[];
|
|
162
|
+
/**
|
|
163
|
+
* Additional instructions injected into the agent context.
|
|
164
|
+
*/
|
|
165
|
+
instructions?: string | AgentProfileResourceRef;
|
|
166
|
+
/**
|
|
167
|
+
* Fail initialization when a provider cannot materialize a resource.
|
|
168
|
+
*/
|
|
169
|
+
failOnError?: boolean;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Model selection hints for backends.
|
|
173
|
+
*/
|
|
174
|
+
interface AgentProfileModelHints {
|
|
175
|
+
/**
|
|
176
|
+
* Preferred default model (format depends on backend, commonly "provider/model").
|
|
177
|
+
*/
|
|
178
|
+
default?: string;
|
|
179
|
+
/**
|
|
180
|
+
* Preferred small/cheap model for lightweight work.
|
|
181
|
+
*/
|
|
182
|
+
small?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Optional provider preference hint.
|
|
185
|
+
*/
|
|
186
|
+
provider?: string;
|
|
187
|
+
/**
|
|
188
|
+
* Backend-agnostic model metadata/hints.
|
|
189
|
+
*/
|
|
190
|
+
metadata?: Record<string, unknown>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Prompt shaping for an agent.
|
|
194
|
+
*/
|
|
195
|
+
interface AgentProfilePrompt {
|
|
196
|
+
/**
|
|
197
|
+
* Full system prompt replacement, when supported.
|
|
198
|
+
*/
|
|
199
|
+
systemPrompt?: string;
|
|
200
|
+
/**
|
|
201
|
+
* Additional instruction lines appended to the active prompt.
|
|
202
|
+
*/
|
|
203
|
+
instructions?: string[];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Generic subagent definition.
|
|
207
|
+
*/
|
|
208
|
+
interface AgentSubagentProfile {
|
|
209
|
+
description?: string;
|
|
210
|
+
prompt?: string;
|
|
211
|
+
model?: string;
|
|
212
|
+
tools?: Record<string, boolean>;
|
|
213
|
+
permissions?: Record<string, AgentProfilePermission>;
|
|
214
|
+
maxSteps?: number;
|
|
215
|
+
metadata?: Record<string, unknown>;
|
|
216
|
+
}
|
|
217
|
+
interface AgentProfileHookCommand {
|
|
218
|
+
command: string;
|
|
219
|
+
timeoutMs?: number;
|
|
220
|
+
blocking?: boolean;
|
|
221
|
+
matcher?: string;
|
|
222
|
+
env?: Record<string, string>;
|
|
223
|
+
}
|
|
224
|
+
interface AgentProfileMode {
|
|
225
|
+
description?: string;
|
|
226
|
+
model?: string;
|
|
227
|
+
prompt?: string;
|
|
228
|
+
tools?: Record<string, boolean>;
|
|
229
|
+
permissions?: Record<string, AgentProfilePermission>;
|
|
230
|
+
metadata?: Record<string, unknown>;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Confidential-execution options for sandbox backends.
|
|
234
|
+
*
|
|
235
|
+
* The Tangle blueprint path translates this into TEE job parameters and fails
|
|
236
|
+
* closed when the requested TEE is unavailable. Callers should verify returned
|
|
237
|
+
* attestation evidence before treating a session as confidential.
|
|
238
|
+
*/
|
|
239
|
+
interface AgentProfileConfidential {
|
|
240
|
+
/**
|
|
241
|
+
* TEE variant requested from the operator.
|
|
242
|
+
*/
|
|
243
|
+
tee?: "tdx" | "nitro" | "phala-dstack" | "sev-snp" | "any" | (string & {});
|
|
244
|
+
/**
|
|
245
|
+
* Optional hex-encoded 32-64 byte challenge for deploy-time report data.
|
|
246
|
+
*/
|
|
247
|
+
attestationNonce?: string;
|
|
248
|
+
/**
|
|
249
|
+
* Require no persistence across session end when supported by the backend.
|
|
250
|
+
*/
|
|
251
|
+
sealed?: boolean;
|
|
252
|
+
/**
|
|
253
|
+
* Ask the SDK/backend to create or require a fresh attestation challenge.
|
|
254
|
+
*/
|
|
255
|
+
attestationRefresh?: boolean;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Generic MCP server configuration.
|
|
259
|
+
*/
|
|
260
|
+
interface AgentProfileMcpServer {
|
|
261
|
+
transport?: "stdio" | "sse" | "http";
|
|
262
|
+
command?: string;
|
|
263
|
+
args?: string[];
|
|
264
|
+
env?: Record<string, string>;
|
|
265
|
+
cwd?: string;
|
|
266
|
+
url?: string;
|
|
267
|
+
headers?: Record<string, string>;
|
|
268
|
+
enabled?: boolean;
|
|
269
|
+
metadata?: Record<string, unknown>;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Public provider-neutral agent profile contract.
|
|
273
|
+
*/
|
|
274
|
+
interface AgentProfile {
|
|
275
|
+
name?: string;
|
|
276
|
+
description?: string;
|
|
277
|
+
version?: string;
|
|
278
|
+
tags?: string[];
|
|
279
|
+
prompt?: AgentProfilePrompt;
|
|
280
|
+
model?: AgentProfileModelHints;
|
|
281
|
+
permissions?: Record<string, AgentProfilePermission>;
|
|
282
|
+
tools?: Record<string, boolean>;
|
|
283
|
+
mcp?: Record<string, AgentProfileMcpServer>;
|
|
284
|
+
subagents?: Record<string, AgentSubagentProfile>;
|
|
285
|
+
resources?: AgentProfileResources;
|
|
286
|
+
hooks?: Record<string, AgentProfileHookCommand[]>;
|
|
287
|
+
modes?: Record<string, AgentProfileMode>;
|
|
288
|
+
confidential?: AgentProfileConfidential;
|
|
289
|
+
metadata?: Record<string, unknown>;
|
|
290
|
+
/**
|
|
291
|
+
* Non-portable backend-specific extensions.
|
|
292
|
+
*
|
|
293
|
+
* Use this only for features that cannot be expressed generically.
|
|
294
|
+
* SDK consumers should treat extension keys as backend namespaces.
|
|
295
|
+
*/
|
|
296
|
+
extensions?: Record<string, Record<string, unknown> | undefined>;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Helper for declaring typed profiles in application code.
|
|
300
|
+
*/
|
|
301
|
+
declare function defineAgentProfile<T extends AgentProfile>(profile: T): T;
|
|
302
|
+
/**
|
|
303
|
+
* Capabilities describing how a backend interprets AgentProfile.
|
|
304
|
+
*/
|
|
305
|
+
interface AgentProfileCapabilities {
|
|
306
|
+
namedProfiles: boolean;
|
|
307
|
+
systemPrompt: boolean;
|
|
308
|
+
instructions: boolean;
|
|
309
|
+
tools: boolean;
|
|
310
|
+
permissions: boolean;
|
|
311
|
+
mcp: boolean;
|
|
312
|
+
subagents: boolean;
|
|
313
|
+
resources: {
|
|
314
|
+
files: boolean;
|
|
315
|
+
instructions: boolean;
|
|
316
|
+
tools?: boolean;
|
|
317
|
+
skills?: boolean;
|
|
318
|
+
agents?: boolean;
|
|
319
|
+
commands?: boolean;
|
|
320
|
+
};
|
|
321
|
+
hooks?: boolean;
|
|
322
|
+
modes?: boolean;
|
|
323
|
+
runtimeUpdate: boolean;
|
|
324
|
+
validation: boolean;
|
|
325
|
+
/**
|
|
326
|
+
* Backend extension namespaces understood by this backend.
|
|
327
|
+
*/
|
|
328
|
+
extensions?: string[];
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Validation issue for a profile/backend pairing.
|
|
332
|
+
*/
|
|
333
|
+
interface AgentProfileValidationIssue {
|
|
334
|
+
level: "error" | "warning" | "info";
|
|
335
|
+
code: string;
|
|
336
|
+
message: string;
|
|
337
|
+
path?: string;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Validation output for a provider adapter.
|
|
341
|
+
*/
|
|
342
|
+
interface AgentProfileValidationResult {
|
|
343
|
+
ok: boolean;
|
|
344
|
+
issues: AgentProfileValidationIssue[];
|
|
345
|
+
normalizedProfile?: AgentProfile;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Merge two public AgentProfile values.
|
|
349
|
+
*
|
|
350
|
+
* Overlay fields win on conflicts. Array-like instruction sets are appended.
|
|
351
|
+
*/
|
|
352
|
+
declare function mergeAgentProfiles(base: AgentProfile | undefined, overlay: AgentProfile | undefined): AgentProfile | undefined;
|
|
353
|
+
//#endregion
|
|
354
|
+
//#region src/types.d.ts
|
|
355
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
356
|
+
[key: string]: JsonValue;
|
|
357
|
+
};
|
|
358
|
+
/**
|
|
359
|
+
* A development environment.
|
|
360
|
+
*
|
|
361
|
+
* Environments provide toolchains provisioned via Nix profiles mounted into
|
|
362
|
+
* a shared base container. The default "universal" environment includes all
|
|
363
|
+
* common toolchains (Node.js, Python, Rust, Go, etc.).
|
|
364
|
+
*/
|
|
365
|
+
interface SandboxEnvironment {
|
|
366
|
+
/** Environment identifier (e.g., "universal") */
|
|
367
|
+
id: string;
|
|
368
|
+
/** Human-readable description */
|
|
369
|
+
description?: string;
|
|
370
|
+
/** Base template this environment extends */
|
|
371
|
+
base?: string;
|
|
372
|
+
/** Environment version tag */
|
|
373
|
+
version: string;
|
|
374
|
+
/** Public template identifier when this environment comes from a published template */
|
|
375
|
+
publicTemplateId?: string;
|
|
376
|
+
/** Snapshot identifier backing the environment when applicable */
|
|
377
|
+
snapshotId?: string;
|
|
378
|
+
}
|
|
379
|
+
interface PublicTemplateVersionInfo {
|
|
380
|
+
id: string;
|
|
381
|
+
templateId: string;
|
|
382
|
+
versionNumber: number;
|
|
383
|
+
snapshotId: string;
|
|
384
|
+
sourceSandboxId: string;
|
|
385
|
+
readmeMarkdown: string;
|
|
386
|
+
tags: string[];
|
|
387
|
+
releaseNotes: string;
|
|
388
|
+
createdByCustomerId: string;
|
|
389
|
+
createdAt: string;
|
|
390
|
+
}
|
|
391
|
+
interface PublicTemplateInfo {
|
|
392
|
+
id: string;
|
|
393
|
+
slug: string;
|
|
394
|
+
name: string;
|
|
395
|
+
description: string;
|
|
396
|
+
websiteUrl: string | null;
|
|
397
|
+
ownerCustomerId: string;
|
|
398
|
+
ownerTeamId: string | null;
|
|
399
|
+
forkedFromTemplateId: string | null;
|
|
400
|
+
latestVersionId: string | null;
|
|
401
|
+
isFeatured: boolean;
|
|
402
|
+
featuredRank: number | null;
|
|
403
|
+
forkCount: number;
|
|
404
|
+
sandboxCount: number;
|
|
405
|
+
createdAt: string;
|
|
406
|
+
updatedAt: string;
|
|
407
|
+
publishedAt: string;
|
|
408
|
+
latestVersion: PublicTemplateVersionInfo | null;
|
|
409
|
+
}
|
|
410
|
+
interface PublishPublicTemplateOptions {
|
|
411
|
+
name: string;
|
|
412
|
+
slug?: string;
|
|
413
|
+
description?: string;
|
|
414
|
+
websiteUrl?: string;
|
|
415
|
+
snapshotId: string;
|
|
416
|
+
sourceSandboxId: string;
|
|
417
|
+
teamId?: string;
|
|
418
|
+
readmeMarkdown?: string;
|
|
419
|
+
tags?: string[];
|
|
420
|
+
releaseNotes?: string;
|
|
421
|
+
forkedFromTemplateId?: string;
|
|
422
|
+
}
|
|
423
|
+
interface PublishPublicTemplateVersionOptions {
|
|
424
|
+
snapshotId: string;
|
|
425
|
+
sourceSandboxId: string;
|
|
426
|
+
readmeMarkdown?: string;
|
|
427
|
+
tags?: string[];
|
|
428
|
+
releaseNotes?: string;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Git authentication configuration.
|
|
432
|
+
*
|
|
433
|
+
* @example HTTPS token
|
|
434
|
+
* ```typescript
|
|
435
|
+
* const auth: GitAuth = {
|
|
436
|
+
* token: process.env.GITHUB_TOKEN,
|
|
437
|
+
* };
|
|
438
|
+
* ```
|
|
439
|
+
*/
|
|
440
|
+
interface GitAuth {
|
|
441
|
+
/** HTTPS auth token (e.g., GitHub PAT) */
|
|
442
|
+
token?: string;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Git repository configuration for cloning at sandbox creation.
|
|
446
|
+
*
|
|
447
|
+
* When provided, the repository is cloned during sandbox provisioning,
|
|
448
|
+
* before the sandbox becomes ready. This is more efficient than cloning
|
|
449
|
+
* after the sandbox starts.
|
|
450
|
+
*
|
|
451
|
+
* @example Basic clone
|
|
452
|
+
* ```typescript
|
|
453
|
+
* const git: GitConfig = {
|
|
454
|
+
* url: "https://github.com/user/repo.git",
|
|
455
|
+
* };
|
|
456
|
+
* ```
|
|
457
|
+
*
|
|
458
|
+
* @example Clone specific branch with auth
|
|
459
|
+
* ```typescript
|
|
460
|
+
* const git: GitConfig = {
|
|
461
|
+
* url: "https://github.com/user/private-repo.git",
|
|
462
|
+
* ref: "develop",
|
|
463
|
+
* auth: { token: process.env.GITHUB_TOKEN },
|
|
464
|
+
* };
|
|
465
|
+
* ```
|
|
466
|
+
*
|
|
467
|
+
* @example Sparse checkout for monorepo
|
|
468
|
+
* ```typescript
|
|
469
|
+
* const git: GitConfig = {
|
|
470
|
+
* url: "https://github.com/org/monorepo.git",
|
|
471
|
+
* sparse: ["packages/my-package", "shared"],
|
|
472
|
+
* depth: 1,
|
|
473
|
+
* };
|
|
474
|
+
* ```
|
|
475
|
+
*/
|
|
476
|
+
interface GitConfig {
|
|
477
|
+
/** Repository URL (HTTPS or SSH) */
|
|
478
|
+
url: string;
|
|
479
|
+
/** Branch, tag, or commit SHA to checkout (default: default branch) */
|
|
480
|
+
ref?: string;
|
|
481
|
+
/** Shallow clone depth (default: 1 for faster clones) */
|
|
482
|
+
depth?: number;
|
|
483
|
+
/** Sparse checkout paths - only clone these directories */
|
|
484
|
+
sparse?: string[];
|
|
485
|
+
/** Authentication for private repositories */
|
|
486
|
+
auth?: GitAuth;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Tool version specifications for mise (polyglot version manager).
|
|
490
|
+
*
|
|
491
|
+
* Mise is pre-installed in all managed sandboxes and can install any
|
|
492
|
+
* language runtime or tool on demand. Specify versions here to have
|
|
493
|
+
* them pre-installed when the sandbox starts.
|
|
494
|
+
*
|
|
495
|
+
* @see https://mise.jdx.dev for supported tools
|
|
496
|
+
*
|
|
497
|
+
* @example Common tools
|
|
498
|
+
* ```typescript
|
|
499
|
+
* const tools: ToolsConfig = {
|
|
500
|
+
* node: "22", // Node.js 22.x (latest minor/patch)
|
|
501
|
+
* python: "3.12", // Python 3.12.x
|
|
502
|
+
* rust: "1.75", // Rust 1.75.x
|
|
503
|
+
* go: "1.22", // Go 1.22.x
|
|
504
|
+
* };
|
|
505
|
+
* ```
|
|
506
|
+
*
|
|
507
|
+
* @example Exact versions
|
|
508
|
+
* ```typescript
|
|
509
|
+
* const tools: ToolsConfig = {
|
|
510
|
+
* node: "20.11.0", // Exact version
|
|
511
|
+
* pnpm: "8.15.1",
|
|
512
|
+
* deno: "1.40",
|
|
513
|
+
* };
|
|
514
|
+
* ```
|
|
515
|
+
*/
|
|
516
|
+
interface ToolsConfig {
|
|
517
|
+
/** Node.js version (e.g., "22", "20.11.0", "lts") */
|
|
518
|
+
node?: string;
|
|
519
|
+
/** Python version (e.g., "3.12", "3.11.7") */
|
|
520
|
+
python?: string;
|
|
521
|
+
/** Rust version (e.g., "1.75", "stable", "nightly") */
|
|
522
|
+
rust?: string;
|
|
523
|
+
/** Go version (e.g., "1.22", "1.21.6") */
|
|
524
|
+
go?: string;
|
|
525
|
+
/** Java version (e.g., "21", "17") */
|
|
526
|
+
java?: string;
|
|
527
|
+
/** Ruby version (e.g., "3.3", "3.2.2") */
|
|
528
|
+
ruby?: string;
|
|
529
|
+
/** Any other mise-supported tool and version */
|
|
530
|
+
[tool: string]: string | undefined;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Configuration for initializing the Sandbox client.
|
|
534
|
+
*
|
|
535
|
+
* @example
|
|
536
|
+
* ```typescript
|
|
537
|
+
* const client = new Sandbox({
|
|
538
|
+
* apiKey: "sk_sandbox_abc123",
|
|
539
|
+
* baseUrl: "https://your-sandbox-api.example.com",
|
|
540
|
+
* timeoutMs: 60000,
|
|
541
|
+
* });
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
544
|
+
interface SandboxClientConfig {
|
|
545
|
+
/** API key for authentication. Must start with `sk_sandbox_` */
|
|
546
|
+
apiKey: string;
|
|
547
|
+
/** Base URL for the Sandbox API */
|
|
548
|
+
baseUrl: string;
|
|
549
|
+
/** Request timeout in milliseconds. Defaults to 30000 (30 seconds) */
|
|
550
|
+
timeoutMs?: number;
|
|
551
|
+
/**
|
|
552
|
+
* Permit the SDK to read CLI auth files from the host home directory
|
|
553
|
+
* (`~/.codex/auth.json`, `~/.claude/.credentials.json`,
|
|
554
|
+
* `~/.claude/settings.json`) and ship them to a `localhost` /
|
|
555
|
+
* `127.0.0.1` / `::1` `baseUrl` when creating a `codex` or
|
|
556
|
+
* `claude-code` backend without explicit credentials.
|
|
557
|
+
*
|
|
558
|
+
* Default `false`. Without this flag, any process bound to a
|
|
559
|
+
* localhost port (your sandbox-api or anything else) can impersonate
|
|
560
|
+
* the API and silently harvest those credentials. Set this to `true`
|
|
561
|
+
* only when the localhost endpoint is one you control. For non-local
|
|
562
|
+
* `baseUrl`s the flag is ignored — the SDK never reads home-dir auth
|
|
563
|
+
* files for remote endpoints.
|
|
564
|
+
*/
|
|
565
|
+
trustLocalCliAuth?: boolean;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Status of a sandbox instance.
|
|
569
|
+
*
|
|
570
|
+
* Lifecycle: `pending` -> `provisioning` -> `running` -> `stopped` -> (deleted)
|
|
571
|
+
*
|
|
572
|
+
* - `pending` - Sandbox created but not yet provisioning
|
|
573
|
+
* - `provisioning` - Container and resources being allocated
|
|
574
|
+
* - `running` - Sandbox is active and accepting commands
|
|
575
|
+
* - `stopped` - Sandbox is paused (can be resumed)
|
|
576
|
+
* - `failed` - Sandbox encountered an error
|
|
577
|
+
* - `expired` - Sandbox exceeded its lifetime limit
|
|
578
|
+
*/
|
|
579
|
+
type SandboxStatus = "pending" | "provisioning" | "running" | "stopped" | "failed" | "expired";
|
|
580
|
+
/**
|
|
581
|
+
* Resource limits for a sandbox.
|
|
582
|
+
*/
|
|
583
|
+
interface SandboxResources {
|
|
584
|
+
/** Number of CPU cores */
|
|
585
|
+
cpuCores?: number;
|
|
586
|
+
/** Memory in megabytes */
|
|
587
|
+
memoryMB?: number;
|
|
588
|
+
/** Disk space in gigabytes */
|
|
589
|
+
diskGB?: number;
|
|
590
|
+
/** Accelerator request for GPU-class workloads. */
|
|
591
|
+
accelerator?: SandboxAccelerator;
|
|
592
|
+
}
|
|
593
|
+
/** @deprecated Use SandboxAccelerator.kind via SandboxResources.accelerator. */
|
|
594
|
+
type GpuType = string;
|
|
595
|
+
/**
|
|
596
|
+
* Configuration for creating a new sandbox.
|
|
597
|
+
*
|
|
598
|
+
* Sandboxes can run in two modes:
|
|
599
|
+
* - **Managed** (default): Full-featured with agent, files, terminal, git, tools
|
|
600
|
+
* - **Bare**: Minimal container with only exec() and lifecycle methods
|
|
601
|
+
*
|
|
602
|
+
* @example Minimal sandbox (managed mode with defaults)
|
|
603
|
+
* ```typescript
|
|
604
|
+
* const box = await client.create();
|
|
605
|
+
* // Uses 'universal' image, managed mode, sane defaults
|
|
606
|
+
* ```
|
|
607
|
+
*
|
|
608
|
+
* @example Sandbox with pre-built image and git
|
|
609
|
+
* ```typescript
|
|
610
|
+
* const box = await client.create({
|
|
611
|
+
* image: "ethereum", // Stack name — tools provisioned via Nix profile
|
|
612
|
+
* git: {
|
|
613
|
+
* url: "https://github.com/user/dapp.git",
|
|
614
|
+
* ref: "main",
|
|
615
|
+
* },
|
|
616
|
+
* tools: { node: "22", python: "3.12" },
|
|
617
|
+
* });
|
|
618
|
+
* ```
|
|
619
|
+
*
|
|
620
|
+
* @example Sandbox with custom Docker image
|
|
621
|
+
* ```typescript
|
|
622
|
+
* const box = await client.create({
|
|
623
|
+
* image: "python:3.12-slim",
|
|
624
|
+
* git: { url: "https://github.com/user/ml-project.git" },
|
|
625
|
+
* tools: { python: "3.12" },
|
|
626
|
+
* });
|
|
627
|
+
* ```
|
|
628
|
+
*
|
|
629
|
+
* @example Bare sandbox (no managed runtime, just exec)
|
|
630
|
+
* ```typescript
|
|
631
|
+
* const box = await client.create({
|
|
632
|
+
* image: "ubuntu:24.04",
|
|
633
|
+
* bare: true,
|
|
634
|
+
* });
|
|
635
|
+
* // Only box.exec(), box.stop(), box.resume(), box.delete() available
|
|
636
|
+
* ```
|
|
637
|
+
*
|
|
638
|
+
* @example With BYOS3 storage for snapshots
|
|
639
|
+
* ```typescript
|
|
640
|
+
* const box = await client.create({
|
|
641
|
+
* image: "universal",
|
|
642
|
+
* storage: {
|
|
643
|
+
* type: "s3",
|
|
644
|
+
* bucket: "my-snapshots",
|
|
645
|
+
* credentials: { accessKeyId: "...", secretAccessKey: "..." },
|
|
646
|
+
* },
|
|
647
|
+
* fromSnapshot: "snap_abc123",
|
|
648
|
+
* });
|
|
649
|
+
* ```
|
|
650
|
+
*/
|
|
651
|
+
interface CreateSandboxOptions {
|
|
652
|
+
/**
|
|
653
|
+
* Development environment name.
|
|
654
|
+
*
|
|
655
|
+
* Environments provision toolchains via Nix profiles mounted into a
|
|
656
|
+
* shared base container. Use `client.environments.list()` to discover
|
|
657
|
+
* available environments.
|
|
658
|
+
*
|
|
659
|
+
* Takes precedence over `image` if both are specified.
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```typescript
|
|
663
|
+
* environment: "universal" // Multi-language (default)
|
|
664
|
+
* ```
|
|
665
|
+
*/
|
|
666
|
+
environment?: string;
|
|
667
|
+
/**
|
|
668
|
+
* Container image to use for the sandbox.
|
|
669
|
+
*
|
|
670
|
+
* For most use cases the default "universal" environment is sufficient.
|
|
671
|
+
* Use this field for custom images; the SDK runtime integration is applied
|
|
672
|
+
* automatically.
|
|
673
|
+
*
|
|
674
|
+
* **Resolution rules:**
|
|
675
|
+
* - Full image paths → Used as-is
|
|
676
|
+
* - Simple names without `/` or `:` → Treated as environment name
|
|
677
|
+
* (equivalent to setting `environment`)
|
|
678
|
+
*
|
|
679
|
+
* When neither `environment` nor `image` is set the SDK omits the
|
|
680
|
+
* field entirely and the server applies its own default.
|
|
681
|
+
*/
|
|
682
|
+
image?: string;
|
|
683
|
+
/**
|
|
684
|
+
* Create a bare sandbox without the managed runtime.
|
|
685
|
+
*
|
|
686
|
+
* Bare sandboxes only have:
|
|
687
|
+
* - `exec()` - Execute commands
|
|
688
|
+
* - `stop()` / `resume()` - Lifecycle control
|
|
689
|
+
* - `delete()` - Cleanup
|
|
690
|
+
*
|
|
691
|
+
* Use bare mode when you need a clean container without the managed
|
|
692
|
+
* runtime integration.
|
|
693
|
+
*
|
|
694
|
+
* @default false
|
|
695
|
+
*/
|
|
696
|
+
bare?: boolean;
|
|
697
|
+
/**
|
|
698
|
+
* Infrastructure driver selection.
|
|
699
|
+
* Controls how the sandbox is provisioned and isolated.
|
|
700
|
+
*
|
|
701
|
+
* @example Firecracker with CRIU
|
|
702
|
+
* ```typescript
|
|
703
|
+
* driver: { type: "firecracker", enableCriu: true }
|
|
704
|
+
* ```
|
|
705
|
+
*/
|
|
706
|
+
driver?: DriverConfig;
|
|
707
|
+
/**
|
|
708
|
+
* AI coding agent backend configuration.
|
|
709
|
+
* Determines which agent runs inside the sandbox.
|
|
710
|
+
*
|
|
711
|
+
* @example OpenCode with profile
|
|
712
|
+
* ```typescript
|
|
713
|
+
* backend: { type: "opencode", profile: "with-web-search" }
|
|
714
|
+
* ```
|
|
715
|
+
*/
|
|
716
|
+
backend?: BackendConfig;
|
|
717
|
+
/**
|
|
718
|
+
* Confidential execution requirements for this sandbox.
|
|
719
|
+
*
|
|
720
|
+
* This is equivalent to setting `backend.profile.confidential` on an inline
|
|
721
|
+
* AgentProfile. Tangle-backed creation translates it into blueprint TEE
|
|
722
|
+
* fields; operators that cannot satisfy the requested TEE fail closed.
|
|
723
|
+
*/
|
|
724
|
+
confidential?: AgentProfileConfidential;
|
|
725
|
+
/**
|
|
726
|
+
* Initial permissions and access control settings.
|
|
727
|
+
*
|
|
728
|
+
* @example Multi-user sandbox
|
|
729
|
+
* ```typescript
|
|
730
|
+
* permissions: {
|
|
731
|
+
* defaultRole: "developer",
|
|
732
|
+
* initialUsers: [{ userId: "user_xyz", role: "developer" }],
|
|
733
|
+
* }
|
|
734
|
+
* ```
|
|
735
|
+
*/
|
|
736
|
+
permissions?: SandboxPermissionsConfig;
|
|
737
|
+
/**
|
|
738
|
+
* Network security configuration.
|
|
739
|
+
* Controls outbound network access from the sandbox.
|
|
740
|
+
*
|
|
741
|
+
* @example Block all outbound traffic
|
|
742
|
+
* ```typescript
|
|
743
|
+
* network: { blockOutbound: true }
|
|
744
|
+
* ```
|
|
745
|
+
*
|
|
746
|
+
* @example Allow only specific destinations
|
|
747
|
+
* ```typescript
|
|
748
|
+
* network: {
|
|
749
|
+
* allowList: ["8.8.8.8/32", "10.0.0.0/8"],
|
|
750
|
+
* ports: [8000, 8080], // Pre-expose ports
|
|
751
|
+
* }
|
|
752
|
+
* ```
|
|
753
|
+
*/
|
|
754
|
+
network?: NetworkConfig;
|
|
755
|
+
/**
|
|
756
|
+
* Git repository to clone at sandbox creation.
|
|
757
|
+
*
|
|
758
|
+
* The repository is cloned during provisioning, before the sandbox
|
|
759
|
+
* becomes ready. This is more efficient than cloning after start.
|
|
760
|
+
*
|
|
761
|
+
* @example { url: "https://github.com/user/repo.git", ref: "main" }
|
|
762
|
+
*/
|
|
763
|
+
git?: GitConfig;
|
|
764
|
+
/**
|
|
765
|
+
* Tool versions to pre-install via mise.
|
|
766
|
+
*
|
|
767
|
+
* Mise (polyglot version manager) is pre-installed in managed sandboxes.
|
|
768
|
+
* Specify versions here to have them ready when the sandbox starts.
|
|
769
|
+
*
|
|
770
|
+
* @example { node: "22", python: "3.12", rust: "1.75" }
|
|
771
|
+
*/
|
|
772
|
+
tools?: ToolsConfig;
|
|
773
|
+
/** Human-readable name for the sandbox */
|
|
774
|
+
name?: string;
|
|
775
|
+
/** Resource limits (CPU cores, memory, disk) */
|
|
776
|
+
resources?: SandboxResources;
|
|
777
|
+
/** Environment variables injected into the sandbox */
|
|
778
|
+
env?: Record<string, string>;
|
|
779
|
+
/**
|
|
780
|
+
* Integration requirements the sandbox app needs at launch.
|
|
781
|
+
*
|
|
782
|
+
* The sandbox API resolves this manifest through id.tangle.tools,
|
|
783
|
+
* creates owner-scoped grants, and injects only a short-lived
|
|
784
|
+
* `TANGLE_INTEGRATION_BUNDLE` capability payload. Raw provider OAuth
|
|
785
|
+
* tokens and API keys never enter the sandbox environment.
|
|
786
|
+
*/
|
|
787
|
+
integrationManifest?: IntegrationManifest;
|
|
788
|
+
/**
|
|
789
|
+
* Existing platform grant ids to bind to this launch.
|
|
790
|
+
*
|
|
791
|
+
* Use this for installed templates or pre-consented apps where the
|
|
792
|
+
* installer owns the connection. The sandbox API still requires
|
|
793
|
+
* `integrationManifest` so platform can fail closed if a grant does not
|
|
794
|
+
* match the declared requirements.
|
|
795
|
+
*/
|
|
796
|
+
integrationGrantIds?: string[];
|
|
797
|
+
/**
|
|
798
|
+
* Grant durability for `integrationManifest`.
|
|
799
|
+
*
|
|
800
|
+
* `preview` scopes consent to this sandbox preview/session,
|
|
801
|
+
* `durable-app` is for installed/generated app instances, and
|
|
802
|
+
* `one-shot` is for a single workflow run.
|
|
803
|
+
*/
|
|
804
|
+
integrationGrantMode?: "preview" | "durable-app" | "one-shot";
|
|
805
|
+
/**
|
|
806
|
+
* Logical app/agent subject receiving the grant. When omitted, the
|
|
807
|
+
* sandbox itself is the grantee and runtime subject.
|
|
808
|
+
*/
|
|
809
|
+
integrationSubject?: IntegrationActor;
|
|
810
|
+
/**
|
|
811
|
+
* Maximum lifetime in seconds.
|
|
812
|
+
* Sandbox is automatically deleted after this time.
|
|
813
|
+
* @default 3600 (1 hour)
|
|
814
|
+
*/
|
|
815
|
+
maxLifetimeSeconds?: number;
|
|
816
|
+
/**
|
|
817
|
+
* Idle timeout in seconds.
|
|
818
|
+
* Sandbox is suspended after this period of inactivity.
|
|
819
|
+
* @default 900 (15 minutes)
|
|
820
|
+
*/
|
|
821
|
+
idleTimeoutSeconds?: number;
|
|
822
|
+
/**
|
|
823
|
+
* Enable SSH access to the sandbox.
|
|
824
|
+
* Use `sandbox.ssh()` to get connection credentials.
|
|
825
|
+
* @default false
|
|
826
|
+
*/
|
|
827
|
+
sshEnabled?: boolean;
|
|
828
|
+
/** Custom SSH public key for access (optional) */
|
|
829
|
+
sshPublicKey?: string;
|
|
830
|
+
/**
|
|
831
|
+
* Enable web terminal access.
|
|
832
|
+
* Provides a browser-based terminal via websocket.
|
|
833
|
+
* @default false
|
|
834
|
+
*/
|
|
835
|
+
webTerminalEnabled?: boolean;
|
|
836
|
+
/**
|
|
837
|
+
* Customer-provided S3-compatible storage for snapshots (BYOS3).
|
|
838
|
+
*
|
|
839
|
+
* When configured, snapshots are stored in your own bucket
|
|
840
|
+
* instead of Tangle's managed storage.
|
|
841
|
+
*/
|
|
842
|
+
storage?: StorageConfig;
|
|
843
|
+
/** Snapshot ID to restore from when creating the sandbox */
|
|
844
|
+
fromSnapshot?: string;
|
|
845
|
+
/** Source sandbox ID that owns the snapshot (required when fromSnapshot is set) */
|
|
846
|
+
fromSandboxId?: string;
|
|
847
|
+
/**
|
|
848
|
+
* Apply a saved template at create time. Templates seed the
|
|
849
|
+
* sandbox with a snapshot, default environment, and config defaults
|
|
850
|
+
* so a team can publish a golden-path starting point once and have
|
|
851
|
+
* every member spin up the same baseline.
|
|
852
|
+
*
|
|
853
|
+
* The template must either be personal (owned by the caller) or
|
|
854
|
+
* belong to a team the caller is an active member of. Explicit
|
|
855
|
+
* fields on this call win over template defaults — so you can layer
|
|
856
|
+
* a one-off override on top of the golden path without forking the
|
|
857
|
+
* template itself.
|
|
858
|
+
*
|
|
859
|
+
* @example
|
|
860
|
+
* ```typescript
|
|
861
|
+
* const box = await client.create({
|
|
862
|
+
* templateId: "tpl_abc123",
|
|
863
|
+
* teamId: "team_...", // optional; sandbox is shared with the team
|
|
864
|
+
* });
|
|
865
|
+
* ```
|
|
866
|
+
*/
|
|
867
|
+
templateId?: string;
|
|
868
|
+
/**
|
|
869
|
+
* Create from a published public template by id or slug.
|
|
870
|
+
* The API resolves the latest published version unless
|
|
871
|
+
* `publicTemplateVersionId` is also provided.
|
|
872
|
+
*/
|
|
873
|
+
publicTemplateId?: string;
|
|
874
|
+
/** Pin sandbox creation to a specific published public-template version. */
|
|
875
|
+
publicTemplateVersionId?: string;
|
|
876
|
+
/**
|
|
877
|
+
* Names of secrets to inject as environment variables.
|
|
878
|
+
*
|
|
879
|
+
* Secrets must be created via `client.secrets.create()` before use.
|
|
880
|
+
* They are injected as environment variables with the same name.
|
|
881
|
+
*
|
|
882
|
+
* @example
|
|
883
|
+
* ```typescript
|
|
884
|
+
* // First, create the secrets
|
|
885
|
+
* await client.secrets.create("HF_TOKEN", "hf_xxx");
|
|
886
|
+
* await client.secrets.create("AWS_ACCESS_KEY", "AKIA...");
|
|
887
|
+
*
|
|
888
|
+
* // Then use them in a sandbox
|
|
889
|
+
* const box = await client.create({
|
|
890
|
+
* secrets: ["HF_TOKEN", "AWS_ACCESS_KEY"],
|
|
891
|
+
* });
|
|
892
|
+
*
|
|
893
|
+
* // Secrets are available as env vars
|
|
894
|
+
* const result = await box.exec("echo $HF_TOKEN");
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
secrets?: string[];
|
|
898
|
+
/** Custom metadata to store with the sandbox */
|
|
899
|
+
metadata?: Record<string, unknown>;
|
|
900
|
+
/**
|
|
901
|
+
* Share this sandbox with a team. The caller must be an active
|
|
902
|
+
* member of the team — the API rejects requests from non-members
|
|
903
|
+
* before provisioning. When omitted the sandbox is personal
|
|
904
|
+
* (accessible only to the creator).
|
|
905
|
+
*/
|
|
906
|
+
teamId?: string;
|
|
907
|
+
/**
|
|
908
|
+
* Sidecar capabilities to enable at boot. Each capability boots an
|
|
909
|
+
* additional subsystem inside the sandbox; absent capabilities incur
|
|
910
|
+
* zero startup cost.
|
|
911
|
+
*
|
|
912
|
+
* Currently supported:
|
|
913
|
+
* - `"computer_use"` — boots Xvfb, dbus, AT-SPI, and an MCP server
|
|
914
|
+
* exposing mouse/keyboard/screenshot via the Anthropic + OpenAI
|
|
915
|
+
* Responses computer-use surface. Required if you plan to call
|
|
916
|
+
* {@link SandboxInstance.getMcpAccessToken | `getMcpAccessToken`}
|
|
917
|
+
* with `capabilities: ["computer_use"]`.
|
|
918
|
+
*
|
|
919
|
+
* The capability is enforced at two layers:
|
|
920
|
+
* 1. The sidecar refuses to start if a capability's binaries are
|
|
921
|
+
* missing (computer_use needs the universal Nix profile, which
|
|
922
|
+
* Docker / host-agent / Firecracker drivers ship via the host
|
|
923
|
+
* bind-mount or the universal sidecar image variant; Firecracker
|
|
924
|
+
* host profiles built without the universal flake do not).
|
|
925
|
+
* 2. The MCP token endpoint refuses to mint a `cap: ["computer_use"]`
|
|
926
|
+
* JWT for a sandbox that wasn't created with that capability.
|
|
927
|
+
*
|
|
928
|
+
* **Sizing note:** `computer_use` boots an always-on Xvfb + dbus
|
|
929
|
+
* stack costing roughly **~100 MB resident memory** inside the
|
|
930
|
+
* container. Billing is by reserved capacity (not measured RSS), so
|
|
931
|
+
* this comes out of your sandbox's RAM envelope rather than adding
|
|
932
|
+
* a separate line item. On a 1 GB sandbox that is ~10% of your
|
|
933
|
+
* workload's headroom; bump `resources.memoryMb` to 1.5–2 GB if
|
|
934
|
+
* the agent will run anything memory-hungry alongside it.
|
|
935
|
+
*
|
|
936
|
+
* @example
|
|
937
|
+
* ```typescript
|
|
938
|
+
* const box = await client.create({
|
|
939
|
+
* environment: "universal",
|
|
940
|
+
* capabilities: ["computer_use"],
|
|
941
|
+
* });
|
|
942
|
+
* const { token } = await box.getMcpAccessToken({
|
|
943
|
+
* capabilities: ["computer_use"],
|
|
944
|
+
* });
|
|
945
|
+
* ```
|
|
946
|
+
*/
|
|
947
|
+
capabilities?: ReadonlyArray<"computer_use">;
|
|
948
|
+
/**
|
|
949
|
+
* Privacy controls for the sandbox. Two independent layers:
|
|
950
|
+
*
|
|
951
|
+
* - **`egress`** — what happens when the sandbox sends a request to a
|
|
952
|
+
* model vendor (Anthropic, OpenAI, your own router, etc.):
|
|
953
|
+
* - `"redact"` — PII spans are masked before the request leaves
|
|
954
|
+
* the sandbox. Emails, JWTs, API keys, credit cards (Luhn-
|
|
955
|
+
* validated), SSNs, phone numbers, IPv4 addresses are caught
|
|
956
|
+
* today; names / postal addresses / DOBs land when the OPF
|
|
957
|
+
* model service is enabled. The agent receives normal
|
|
958
|
+
* responses; the vendor sees masked input.
|
|
959
|
+
* - `"block"` — PII presence fails the egress request closed.
|
|
960
|
+
* For high-compliance flows that prefer fail-closed to leak.
|
|
961
|
+
* - `"off"` — no egress filtering. Default for free tier; opt-in
|
|
962
|
+
* for tasks that genuinely need raw PII (form-filling,
|
|
963
|
+
* customer-support agents reading customer details).
|
|
964
|
+
*
|
|
965
|
+
* - **`logs`** — whether infrastructure logs / telemetry / Sentry
|
|
966
|
+
* redact PII before recording. This is OUR side, not the model
|
|
967
|
+
* vendor's, and there's basically never a reason to leak PII into
|
|
968
|
+
* our own logs. Default `"on"`.
|
|
969
|
+
*
|
|
970
|
+
* Note: privacy controls operate at the boundary between the
|
|
971
|
+
* sandbox and external systems. They do NOT redact contents inside
|
|
972
|
+
* the sandbox workspace itself — files / code / database fixtures
|
|
973
|
+
* the customer puts there are the customer's data and stay
|
|
974
|
+
* unmodified. Snapshots preserve those contents verbatim.
|
|
975
|
+
*
|
|
976
|
+
* @example
|
|
977
|
+
* ```typescript
|
|
978
|
+
* const box = await client.create({
|
|
979
|
+
* privacy: { egress: "redact", logs: "on" },
|
|
980
|
+
* });
|
|
981
|
+
* ```
|
|
982
|
+
*/
|
|
983
|
+
privacy?: {
|
|
984
|
+
egress?: "redact" | "block" | "off";
|
|
985
|
+
logs?: "on" | "off";
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* SSH connection credentials.
|
|
990
|
+
*/
|
|
991
|
+
interface SSHCredentials {
|
|
992
|
+
/** Username for SSH authentication */
|
|
993
|
+
username: string;
|
|
994
|
+
/** SSH server port */
|
|
995
|
+
port: number;
|
|
996
|
+
/** ProxyCommand for sandbox API tunnel-based SSH. */
|
|
997
|
+
proxyCommand: string;
|
|
998
|
+
}
|
|
999
|
+
interface SSHCommandDescriptor {
|
|
1000
|
+
command: string;
|
|
1001
|
+
env: Record<string, string>;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Connection information for a sandbox.
|
|
1005
|
+
*
|
|
1006
|
+
* Most code should use `SandboxInstance` methods (`exec`, `prompt`, etc.).
|
|
1007
|
+
* The raw `runtimeUrl` and `authToken` are surfaced only for advanced
|
|
1008
|
+
* lower-level use cases such as custom protocol clients.
|
|
1009
|
+
*/
|
|
1010
|
+
interface SandboxConnection {
|
|
1011
|
+
/** Sandbox runtime API URL for programmatic access */
|
|
1012
|
+
runtimeUrl?: string;
|
|
1013
|
+
/** Access token for authenticating directly with the runtime (Bearer token) */
|
|
1014
|
+
authToken?: string;
|
|
1015
|
+
/** Token expiration timestamp (ISO 8601). Refresh before this time. */
|
|
1016
|
+
authTokenExpiresAt?: string;
|
|
1017
|
+
/** SSH connection info if `sshEnabled` was true during creation */
|
|
1018
|
+
ssh?: SSHCredentials;
|
|
1019
|
+
/** Web terminal URL if `webTerminalEnabled` was true during creation */
|
|
1020
|
+
webTerminalUrl?: string;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Full sandbox information returned from the API.
|
|
1024
|
+
*/
|
|
1025
|
+
interface SandboxInfo {
|
|
1026
|
+
/** Unique sandbox identifier */
|
|
1027
|
+
id: string;
|
|
1028
|
+
/** Human-readable name */
|
|
1029
|
+
name?: string;
|
|
1030
|
+
/** Current status */
|
|
1031
|
+
status: SandboxStatus;
|
|
1032
|
+
/** Connection information */
|
|
1033
|
+
connection?: SandboxConnection;
|
|
1034
|
+
/** Custom metadata */
|
|
1035
|
+
metadata?: Record<string, unknown>;
|
|
1036
|
+
/** When the sandbox was created */
|
|
1037
|
+
createdAt: Date;
|
|
1038
|
+
/** When the sandbox started running */
|
|
1039
|
+
startedAt?: Date;
|
|
1040
|
+
/** Last activity timestamp */
|
|
1041
|
+
lastActivityAt?: Date;
|
|
1042
|
+
/** When the sandbox will expire */
|
|
1043
|
+
expiresAt?: Date;
|
|
1044
|
+
/** Error message if status is 'failed' */
|
|
1045
|
+
error?: string;
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Raw TEE attestation evidence returned by the sandbox runtime.
|
|
1049
|
+
*
|
|
1050
|
+
* Pass this object to `@tangle-network/tcloud-attestation` for caller-side
|
|
1051
|
+
* policy checks and hardware verification.
|
|
1052
|
+
*/
|
|
1053
|
+
interface TeeAttestationReport {
|
|
1054
|
+
/** TEE backend that produced the report, e.g. `Tdx`, `Sev`, or `Nitro`. */
|
|
1055
|
+
tee_type: string;
|
|
1056
|
+
/** Raw vendor evidence bytes. */
|
|
1057
|
+
evidence: number[];
|
|
1058
|
+
/** Runtime measurement bytes. */
|
|
1059
|
+
measurement: number[];
|
|
1060
|
+
/** Unix timestamp when the report was generated. */
|
|
1061
|
+
timestamp: number;
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Response from a sandbox TEE attestation request.
|
|
1065
|
+
*/
|
|
1066
|
+
interface TeeAttestationResponse {
|
|
1067
|
+
/** Sandbox identifier the attestation belongs to. */
|
|
1068
|
+
sandbox_id: string;
|
|
1069
|
+
/** Raw TEE attestation report. */
|
|
1070
|
+
attestation: TeeAttestationReport;
|
|
1071
|
+
/** Caller nonce used for this report, when supplied. */
|
|
1072
|
+
attestationNonce?: string;
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* TEE-bound public key used for sealed-secret encryption.
|
|
1076
|
+
*/
|
|
1077
|
+
interface TeePublicKey {
|
|
1078
|
+
/** Key agreement/encryption algorithm, e.g. `x25519-hkdf-sha256`. */
|
|
1079
|
+
algorithm: string;
|
|
1080
|
+
/** Raw public key bytes. */
|
|
1081
|
+
public_key_bytes: number[];
|
|
1082
|
+
/** Attestation report binding this key to the enclave. */
|
|
1083
|
+
attestation: TeeAttestationReport;
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Response from a sandbox TEE public-key request.
|
|
1087
|
+
*/
|
|
1088
|
+
interface TeePublicKeyResponse {
|
|
1089
|
+
/** Sandbox identifier the public key belongs to. */
|
|
1090
|
+
sandbox_id: string;
|
|
1091
|
+
/** TEE-bound public key and its attestation proof. */
|
|
1092
|
+
public_key: TeePublicKey;
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Options for requesting fresh TEE attestation evidence.
|
|
1096
|
+
*/
|
|
1097
|
+
interface TeeAttestationOptions {
|
|
1098
|
+
/**
|
|
1099
|
+
* Hex-encoded 32-64 byte caller nonce. When supported by the selected TEE
|
|
1100
|
+
* backend, the runtime binds this to report data so the caller can reject
|
|
1101
|
+
* replayed quotes.
|
|
1102
|
+
*/
|
|
1103
|
+
attestationNonce?: string;
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Options for listing sandboxes.
|
|
1107
|
+
*/
|
|
1108
|
+
interface ListSandboxOptions {
|
|
1109
|
+
/** Filter by status */
|
|
1110
|
+
status?: SandboxStatus | SandboxStatus[];
|
|
1111
|
+
/** Filter personal/team visibility scope */
|
|
1112
|
+
scope?: "personal" | "team" | "all" | `team:${string}`;
|
|
1113
|
+
/** Maximum number of results */
|
|
1114
|
+
limit?: number;
|
|
1115
|
+
/** Offset for pagination */
|
|
1116
|
+
offset?: number;
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Result of executing a command.
|
|
1120
|
+
*/
|
|
1121
|
+
interface ExecResult {
|
|
1122
|
+
/** Exit code (0 = success) */
|
|
1123
|
+
exitCode: number;
|
|
1124
|
+
/** Standard output */
|
|
1125
|
+
stdout: string;
|
|
1126
|
+
/** Standard error */
|
|
1127
|
+
stderr: string;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Options for executing a command.
|
|
1131
|
+
*/
|
|
1132
|
+
interface ExecOptions {
|
|
1133
|
+
/** Working directory for the command. When `sessionId` is set the
|
|
1134
|
+
* runtime remaps well-known absolute sandbox paths to the task's
|
|
1135
|
+
* real workspace; without `sessionId`, absolute paths pass through
|
|
1136
|
+
* verbatim and may not resolve to the task's actual filesystem. */
|
|
1137
|
+
cwd?: string;
|
|
1138
|
+
/** Environment variables */
|
|
1139
|
+
env?: Record<string, string>;
|
|
1140
|
+
/** Timeout in milliseconds */
|
|
1141
|
+
timeoutMs?: number;
|
|
1142
|
+
/** Task session id (e.g. `task-abc123`). When set, the runtime
|
|
1143
|
+
* resolves `cwd` against the session's isolated workspace and
|
|
1144
|
+
* applies a virtual-root remap so a well-known absolute sandbox
|
|
1145
|
+
* path lands in the directory the task actually writes to rather
|
|
1146
|
+
* than the host's literal filesystem. Essential for drivers that
|
|
1147
|
+
* give each task its own workspace subdirectory; no-op for drivers
|
|
1148
|
+
* where the workspace is already the container root. */
|
|
1149
|
+
sessionId?: string;
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Options for code search.
|
|
1153
|
+
*
|
|
1154
|
+
* @example Search TypeScript files
|
|
1155
|
+
* ```typescript
|
|
1156
|
+
* const matches = await box.search("TODO", {
|
|
1157
|
+
* glob: "**\/*.ts",
|
|
1158
|
+
* maxResults: 100,
|
|
1159
|
+
* });
|
|
1160
|
+
* ```
|
|
1161
|
+
*/
|
|
1162
|
+
interface SearchOptions {
|
|
1163
|
+
/** Glob pattern to filter files (e.g., "**\/*.ts") */
|
|
1164
|
+
glob?: string;
|
|
1165
|
+
/** Directory to search in (default: workspace root) */
|
|
1166
|
+
cwd?: string;
|
|
1167
|
+
/** Maximum number of results */
|
|
1168
|
+
maxResults?: number;
|
|
1169
|
+
/** Case-insensitive search */
|
|
1170
|
+
ignoreCase?: boolean;
|
|
1171
|
+
/** Include line context (lines before/after match) */
|
|
1172
|
+
context?: number;
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* A single search match from ripgrep.
|
|
1176
|
+
*/
|
|
1177
|
+
interface SearchMatch {
|
|
1178
|
+
/** File path relative to search root */
|
|
1179
|
+
path: string;
|
|
1180
|
+
/** Line number (1-indexed) */
|
|
1181
|
+
line: number;
|
|
1182
|
+
/** Column number (1-indexed) */
|
|
1183
|
+
column: number;
|
|
1184
|
+
/** The matching line text */
|
|
1185
|
+
text: string;
|
|
1186
|
+
/** Context lines before the match */
|
|
1187
|
+
before?: string[];
|
|
1188
|
+
/** Context lines after the match */
|
|
1189
|
+
after?: string[];
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Git repository status.
|
|
1193
|
+
*/
|
|
1194
|
+
interface GitStatus {
|
|
1195
|
+
/** Current branch name */
|
|
1196
|
+
branch: string;
|
|
1197
|
+
/** Commit SHA of HEAD */
|
|
1198
|
+
head: string;
|
|
1199
|
+
/** Whether there are uncommitted changes */
|
|
1200
|
+
isDirty: boolean;
|
|
1201
|
+
/** Number of commits ahead of upstream */
|
|
1202
|
+
ahead: number;
|
|
1203
|
+
/** Number of commits behind upstream */
|
|
1204
|
+
behind: number;
|
|
1205
|
+
/** Staged files */
|
|
1206
|
+
staged: string[];
|
|
1207
|
+
/** Modified but unstaged files */
|
|
1208
|
+
modified: string[];
|
|
1209
|
+
/** Untracked files */
|
|
1210
|
+
untracked: string[];
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Git commit information.
|
|
1214
|
+
*/
|
|
1215
|
+
interface GitCommit {
|
|
1216
|
+
/** Commit SHA */
|
|
1217
|
+
sha: string;
|
|
1218
|
+
/** Short SHA (7 chars) */
|
|
1219
|
+
shortSha: string;
|
|
1220
|
+
/** Commit message */
|
|
1221
|
+
message: string;
|
|
1222
|
+
/** Author name */
|
|
1223
|
+
author: string;
|
|
1224
|
+
/** Author email */
|
|
1225
|
+
email: string;
|
|
1226
|
+
/** Commit date */
|
|
1227
|
+
date: Date;
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Git branch information.
|
|
1231
|
+
*/
|
|
1232
|
+
interface GitBranch {
|
|
1233
|
+
/** Branch name */
|
|
1234
|
+
name: string;
|
|
1235
|
+
/** Whether this is the current branch */
|
|
1236
|
+
current: boolean;
|
|
1237
|
+
/** Upstream branch (if tracking) */
|
|
1238
|
+
upstream?: string;
|
|
1239
|
+
/** Latest commit SHA */
|
|
1240
|
+
commit: string;
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Git diff information.
|
|
1244
|
+
*/
|
|
1245
|
+
interface GitDiff {
|
|
1246
|
+
/** Files changed */
|
|
1247
|
+
files: Array<{
|
|
1248
|
+
path: string;
|
|
1249
|
+
status: "added" | "modified" | "deleted" | "renamed";
|
|
1250
|
+
additions: number;
|
|
1251
|
+
deletions: number;
|
|
1252
|
+
}>;
|
|
1253
|
+
/** Total additions */
|
|
1254
|
+
additions: number;
|
|
1255
|
+
/** Total deletions */
|
|
1256
|
+
deletions: number;
|
|
1257
|
+
/** Raw diff output */
|
|
1258
|
+
raw: string;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Information about an installed tool.
|
|
1262
|
+
*/
|
|
1263
|
+
interface InstalledTool {
|
|
1264
|
+
/** Tool name (e.g., "node", "python") */
|
|
1265
|
+
name: string;
|
|
1266
|
+
/** Installed version */
|
|
1267
|
+
version: string;
|
|
1268
|
+
/** Path to the tool binary */
|
|
1269
|
+
path: string;
|
|
1270
|
+
/** Whether this is the active/default version */
|
|
1271
|
+
active: boolean;
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Result of an agent prompt.
|
|
1275
|
+
*/
|
|
1276
|
+
interface PromptResult {
|
|
1277
|
+
/** Whether the prompt completed successfully */
|
|
1278
|
+
success: boolean;
|
|
1279
|
+
/** Agent's response text */
|
|
1280
|
+
response?: string;
|
|
1281
|
+
/** Error message if failed */
|
|
1282
|
+
error?: string;
|
|
1283
|
+
/** Trace ID for debugging */
|
|
1284
|
+
traceId?: string;
|
|
1285
|
+
/** Duration in milliseconds */
|
|
1286
|
+
durationMs: number;
|
|
1287
|
+
/** Token usage */
|
|
1288
|
+
usage?: {
|
|
1289
|
+
inputTokens: number;
|
|
1290
|
+
outputTokens: number;
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
type PromptInputPart = {
|
|
1294
|
+
type: "text";
|
|
1295
|
+
text: string;
|
|
1296
|
+
} | {
|
|
1297
|
+
type: "image";
|
|
1298
|
+
filename?: string;
|
|
1299
|
+
mediaType?: string;
|
|
1300
|
+
url?: string;
|
|
1301
|
+
path?: string;
|
|
1302
|
+
} | {
|
|
1303
|
+
type: "file";
|
|
1304
|
+
filename?: string;
|
|
1305
|
+
mediaType?: string;
|
|
1306
|
+
url?: string;
|
|
1307
|
+
path?: string;
|
|
1308
|
+
content?: string;
|
|
1309
|
+
};
|
|
1310
|
+
/**
|
|
1311
|
+
* Options for sending a prompt.
|
|
1312
|
+
*/
|
|
1313
|
+
interface PromptOptions {
|
|
1314
|
+
/** Session ID for conversation continuity */
|
|
1315
|
+
sessionId?: string;
|
|
1316
|
+
/** Model to use (format: provider/model, e.g., anthropic/claude-sonnet-4-20250514) */
|
|
1317
|
+
model?: string;
|
|
1318
|
+
/**
|
|
1319
|
+
* Per-run backend override.
|
|
1320
|
+
*
|
|
1321
|
+
* Use `backend.profile` with a string for a named profile or a provider-neutral
|
|
1322
|
+
* `AgentProfile` object for inline profile configuration.
|
|
1323
|
+
*/
|
|
1324
|
+
backend?: Partial<BackendConfig>;
|
|
1325
|
+
/** Timeout in milliseconds */
|
|
1326
|
+
timeoutMs?: number;
|
|
1327
|
+
/** Additional context */
|
|
1328
|
+
context?: Record<string, unknown>;
|
|
1329
|
+
/** AbortSignal for cancellation */
|
|
1330
|
+
signal?: AbortSignal;
|
|
1331
|
+
}
|
|
1332
|
+
/**
|
|
1333
|
+
* SSE event from sandbox streaming.
|
|
1334
|
+
*/
|
|
1335
|
+
interface SandboxEvent {
|
|
1336
|
+
/** Event type */
|
|
1337
|
+
type: string;
|
|
1338
|
+
/** Event data */
|
|
1339
|
+
data: Record<string, unknown>;
|
|
1340
|
+
/** Event ID */
|
|
1341
|
+
id?: string;
|
|
1342
|
+
}
|
|
1343
|
+
interface SandboxTraceEvent {
|
|
1344
|
+
type: "sandbox.lifecycle.snapshot" | "sandbox.runtime.snapshot" | "sandbox.usage.snapshot" | "sandbox.insight.summary";
|
|
1345
|
+
timestamp: string;
|
|
1346
|
+
sandboxId: string;
|
|
1347
|
+
durationMs?: number;
|
|
1348
|
+
attributes: Record<string, unknown>;
|
|
1349
|
+
}
|
|
1350
|
+
interface SandboxTraceExport {
|
|
1351
|
+
schemaVersion: "sandbox.trace.v1";
|
|
1352
|
+
traceId: string;
|
|
1353
|
+
sandboxId: string;
|
|
1354
|
+
exportedAt: string;
|
|
1355
|
+
timings: {
|
|
1356
|
+
observedLifecycleMs: number;
|
|
1357
|
+
observedRuntimeMs: number;
|
|
1358
|
+
idleObservedMs: number;
|
|
1359
|
+
};
|
|
1360
|
+
criticalPath: {
|
|
1361
|
+
durationMs: number;
|
|
1362
|
+
phases: Array<{
|
|
1363
|
+
name: string;
|
|
1364
|
+
durationMs: number;
|
|
1365
|
+
}>;
|
|
1366
|
+
};
|
|
1367
|
+
events: SandboxTraceEvent[];
|
|
1368
|
+
}
|
|
1369
|
+
interface SandboxIntelligenceEnvelope {
|
|
1370
|
+
schemaVersion: "sandbox.intelligence.v1";
|
|
1371
|
+
source: "sandbox-api";
|
|
1372
|
+
subject: {
|
|
1373
|
+
type: "sandbox";
|
|
1374
|
+
sandboxId: string;
|
|
1375
|
+
};
|
|
1376
|
+
billing: {
|
|
1377
|
+
billable: false;
|
|
1378
|
+
billedTo: "platform";
|
|
1379
|
+
costUsd: 0;
|
|
1380
|
+
reason: "deterministic_platform_insight";
|
|
1381
|
+
};
|
|
1382
|
+
metrics: Record<string, number>;
|
|
1383
|
+
signals: Array<{
|
|
1384
|
+
name: string;
|
|
1385
|
+
value: string | number | boolean;
|
|
1386
|
+
severity: "info" | "warn" | "critical";
|
|
1387
|
+
rationale: string;
|
|
1388
|
+
}>;
|
|
1389
|
+
recommendedActions: string[];
|
|
1390
|
+
}
|
|
1391
|
+
interface SandboxTraceBundle {
|
|
1392
|
+
trace: SandboxTraceExport;
|
|
1393
|
+
intelligence?: SandboxIntelligenceEnvelope;
|
|
1394
|
+
}
|
|
1395
|
+
interface SandboxTraceOptions {
|
|
1396
|
+
/**
|
|
1397
|
+
* Include the platform-generated intelligence envelope. Defaults to false.
|
|
1398
|
+
* Set true when a customer wants generated insight with the raw trace export.
|
|
1399
|
+
*/
|
|
1400
|
+
includeIntelligence?: boolean;
|
|
1401
|
+
}
|
|
1402
|
+
type IntelligenceReportSubjectType = "sandbox" | "fleet" | "dispatch" | "trace_set";
|
|
1403
|
+
interface IntelligenceReport {
|
|
1404
|
+
jobId: string;
|
|
1405
|
+
subject: {
|
|
1406
|
+
type: IntelligenceReportSubjectType;
|
|
1407
|
+
id: string;
|
|
1408
|
+
};
|
|
1409
|
+
mode: "deterministic" | "agentic";
|
|
1410
|
+
status: "queued" | "running" | "completed" | "failed";
|
|
1411
|
+
billing: {
|
|
1412
|
+
billable: boolean;
|
|
1413
|
+
billedTo: "platform" | "customer";
|
|
1414
|
+
costUsd: number;
|
|
1415
|
+
reason: string;
|
|
1416
|
+
budgetMaxUsd?: number;
|
|
1417
|
+
};
|
|
1418
|
+
result: Record<string, unknown> | null;
|
|
1419
|
+
error?: string;
|
|
1420
|
+
createdAt: string;
|
|
1421
|
+
updatedAt: string;
|
|
1422
|
+
completedAt?: string;
|
|
1423
|
+
}
|
|
1424
|
+
interface IntelligenceReportBudget {
|
|
1425
|
+
maxUsd?: number;
|
|
1426
|
+
billTo?: "customer" | "platform";
|
|
1427
|
+
}
|
|
1428
|
+
interface CreateIntelligenceReportOptions {
|
|
1429
|
+
subject: {
|
|
1430
|
+
type: IntelligenceReportSubjectType;
|
|
1431
|
+
id: string;
|
|
1432
|
+
};
|
|
1433
|
+
mode?: "deterministic" | "agentic";
|
|
1434
|
+
acknowledgeCost?: boolean;
|
|
1435
|
+
budget?: IntelligenceReportBudget;
|
|
1436
|
+
metadata?: Record<string, unknown>;
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Options for event streaming.
|
|
1440
|
+
*/
|
|
1441
|
+
interface EventStreamOptions {
|
|
1442
|
+
/** AbortSignal for cancellation */
|
|
1443
|
+
signal?: AbortSignal;
|
|
1444
|
+
/** Filter to specific event types */
|
|
1445
|
+
eventTypes?: string[];
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Provisioning step identifier for progress reporting.
|
|
1449
|
+
*/
|
|
1450
|
+
type ProvisionStep = "match" | "networking" | "git" | "host-select" | "storage" | "image-check" | "image-pull" | "image-build" | "container-create" | "container-start" | "health-check" | "runtime-ready" | "workspace";
|
|
1451
|
+
/**
|
|
1452
|
+
* Status of a provisioning step.
|
|
1453
|
+
*/
|
|
1454
|
+
type ProvisionStatus = "started" | "progress" | "completed" | "skipped" | "error";
|
|
1455
|
+
/**
|
|
1456
|
+
* Provisioning progress event emitted during sandbox creation.
|
|
1457
|
+
*
|
|
1458
|
+
* Subscribe via `box.watchProvisioning()` or pass `onProgress` to `box.waitFor()`.
|
|
1459
|
+
*
|
|
1460
|
+
* @example
|
|
1461
|
+
* ```typescript
|
|
1462
|
+
* for await (const event of box.watchProvisioning()) {
|
|
1463
|
+
* console.log(`[${event.step}] ${event.status} — ${event.message}`);
|
|
1464
|
+
* if (event.percent !== undefined) {
|
|
1465
|
+
* updateProgressBar(event.percent);
|
|
1466
|
+
* }
|
|
1467
|
+
* }
|
|
1468
|
+
* ```
|
|
1469
|
+
*/
|
|
1470
|
+
interface ProvisionEvent {
|
|
1471
|
+
/** The provisioning step (e.g., "image-pull", "container-start") */
|
|
1472
|
+
step: ProvisionStep;
|
|
1473
|
+
/** Status of this step */
|
|
1474
|
+
status: ProvisionStatus;
|
|
1475
|
+
/** Human-readable progress message */
|
|
1476
|
+
message?: string;
|
|
1477
|
+
/** Overall progress percentage (0-100) */
|
|
1478
|
+
percent?: number;
|
|
1479
|
+
/** Additional detail for the step */
|
|
1480
|
+
detail?: Record<string, unknown>;
|
|
1481
|
+
/** ISO timestamp */
|
|
1482
|
+
timestamp: string;
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Terminal provisioning event indicating success or failure.
|
|
1486
|
+
*/
|
|
1487
|
+
type ProvisionResult = {
|
|
1488
|
+
type: "complete";
|
|
1489
|
+
containerId: string;
|
|
1490
|
+
timestamp: string;
|
|
1491
|
+
} | {
|
|
1492
|
+
type: "failed";
|
|
1493
|
+
error: string;
|
|
1494
|
+
timestamp: string;
|
|
1495
|
+
};
|
|
1496
|
+
/**
|
|
1497
|
+
* Options for `waitFor()`.
|
|
1498
|
+
*/
|
|
1499
|
+
interface WaitForOptions {
|
|
1500
|
+
/** Timeout in milliseconds (default: 120000) */
|
|
1501
|
+
timeoutMs?: number;
|
|
1502
|
+
/** Poll interval in milliseconds when SSE is unavailable (default: 2000) */
|
|
1503
|
+
pollIntervalMs?: number;
|
|
1504
|
+
/** AbortSignal for cancellation */
|
|
1505
|
+
signal?: AbortSignal;
|
|
1506
|
+
/**
|
|
1507
|
+
* Callback invoked with real-time provisioning progress events.
|
|
1508
|
+
* When provided and the sandbox is provisioning, `waitFor()` uses SSE
|
|
1509
|
+
* instead of polling for faster, more granular updates.
|
|
1510
|
+
*/
|
|
1511
|
+
onProgress?: (event: ProvisionEvent) => void;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Usage information for the account.
|
|
1515
|
+
*/
|
|
1516
|
+
interface UsageInfo {
|
|
1517
|
+
/** Total compute minutes used today */
|
|
1518
|
+
computeMinutes: number;
|
|
1519
|
+
/** Number of currently active sandboxes */
|
|
1520
|
+
activeSandboxes: number;
|
|
1521
|
+
/** Total sandboxes created (lifetime) */
|
|
1522
|
+
totalSandboxes: number;
|
|
1523
|
+
/** Period start date (current day UTC) */
|
|
1524
|
+
periodStart: Date;
|
|
1525
|
+
/** Period end date (next day UTC) */
|
|
1526
|
+
periodEnd: Date;
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Subscription and billing information for the account.
|
|
1530
|
+
*/
|
|
1531
|
+
interface SubscriptionInfo {
|
|
1532
|
+
/** Current plan tier */
|
|
1533
|
+
plan: "free" | "pro" | "enterprise";
|
|
1534
|
+
/** Subscription status */
|
|
1535
|
+
status: "active" | "canceled" | "past_due";
|
|
1536
|
+
/**
|
|
1537
|
+
* Available credit balance in USD.
|
|
1538
|
+
*
|
|
1539
|
+
* **May be negative** for overage-enabled plans (pro/enterprise):
|
|
1540
|
+
* overage charges can push the stored balance below zero. Free-tier
|
|
1541
|
+
* plans floor at 0 at the charge path — free users top up their
|
|
1542
|
+
* prepaid balance via Stripe Checkout (`POST /v1/billing/topup`,
|
|
1543
|
+
* issue #874) when they hit zero rather than going into the red.
|
|
1544
|
+
*
|
|
1545
|
+
* Freshness semantics differ by deployment backend: the
|
|
1546
|
+
* Cloudflare/D1 backend includes real-time projected cost of
|
|
1547
|
+
* currently-running sandboxes; the Node/Redis backend returns the
|
|
1548
|
+
* last-deducted stored balance and reflects running sandboxes only
|
|
1549
|
+
* once their usage is recorded. Consumers should not assume this
|
|
1550
|
+
* value is non-negative — use `>= 0` checks rather than truthiness.
|
|
1551
|
+
*/
|
|
1552
|
+
creditsAvailableUsd: number;
|
|
1553
|
+
/** Credits used in USD */
|
|
1554
|
+
creditsUsedUsd: number;
|
|
1555
|
+
/** Monthly included balance in USD */
|
|
1556
|
+
monthlyBalanceUsd: number;
|
|
1557
|
+
/** Max concurrent sandboxes (0 = unlimited) */
|
|
1558
|
+
maxConcurrentSandboxes: number;
|
|
1559
|
+
/** Whether overage billing is allowed */
|
|
1560
|
+
overageAllowed: boolean;
|
|
1561
|
+
/** Resource limits */
|
|
1562
|
+
limits: {
|
|
1563
|
+
maxCpuCores: number;
|
|
1564
|
+
maxRamGB: number;
|
|
1565
|
+
maxStorageGB: number;
|
|
1566
|
+
};
|
|
1567
|
+
/** Current billing period end (epoch ms) */
|
|
1568
|
+
currentPeriodEnd: number;
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* S3-compatible storage provider configuration (BYOS3 - Bring Your Own S3).
|
|
1572
|
+
*
|
|
1573
|
+
* Allows customers to store snapshots in their own S3-compatible storage.
|
|
1574
|
+
* Supports AWS S3, Google Cloud Storage (GCS), and Cloudflare R2.
|
|
1575
|
+
*
|
|
1576
|
+
* @example AWS S3
|
|
1577
|
+
* ```typescript
|
|
1578
|
+
* const storage: StorageConfig = {
|
|
1579
|
+
* type: "s3",
|
|
1580
|
+
* bucket: "my-snapshots",
|
|
1581
|
+
* region: "us-east-1",
|
|
1582
|
+
* credentials: {
|
|
1583
|
+
* accessKeyId: "AKIA...",
|
|
1584
|
+
* secretAccessKey: "...",
|
|
1585
|
+
* },
|
|
1586
|
+
* };
|
|
1587
|
+
* ```
|
|
1588
|
+
*
|
|
1589
|
+
* @example Cloudflare R2
|
|
1590
|
+
* ```typescript
|
|
1591
|
+
* const storage: StorageConfig = {
|
|
1592
|
+
* type: "r2",
|
|
1593
|
+
* bucket: "my-snapshots",
|
|
1594
|
+
* endpoint: "https://<account>.r2.cloudflarestorage.com",
|
|
1595
|
+
* credentials: {
|
|
1596
|
+
* accessKeyId: "...",
|
|
1597
|
+
* secretAccessKey: "...",
|
|
1598
|
+
* },
|
|
1599
|
+
* };
|
|
1600
|
+
* ```
|
|
1601
|
+
*
|
|
1602
|
+
* @example Google Cloud Storage
|
|
1603
|
+
* ```typescript
|
|
1604
|
+
* const storage: StorageConfig = {
|
|
1605
|
+
* type: "gcs",
|
|
1606
|
+
* bucket: "my-snapshots",
|
|
1607
|
+
* credentials: {
|
|
1608
|
+
* accessKeyId: "...", // HMAC key
|
|
1609
|
+
* secretAccessKey: "...",
|
|
1610
|
+
* },
|
|
1611
|
+
* };
|
|
1612
|
+
* ```
|
|
1613
|
+
*/
|
|
1614
|
+
interface StorageConfig {
|
|
1615
|
+
/** Storage provider type */
|
|
1616
|
+
type: "s3" | "gcs" | "r2";
|
|
1617
|
+
/** Bucket name */
|
|
1618
|
+
bucket: string;
|
|
1619
|
+
/** Custom endpoint URL (required for R2, optional for S3/GCS) */
|
|
1620
|
+
endpoint?: string;
|
|
1621
|
+
/** Region (e.g., us-east-1) */
|
|
1622
|
+
region?: string;
|
|
1623
|
+
/** Access credentials */
|
|
1624
|
+
credentials: {
|
|
1625
|
+
accessKeyId: string;
|
|
1626
|
+
secretAccessKey: string;
|
|
1627
|
+
};
|
|
1628
|
+
/** Path prefix within bucket (default: sandbox-snapshots/) */
|
|
1629
|
+
prefix?: string;
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Options for running a multi-turn task.
|
|
1633
|
+
*/
|
|
1634
|
+
interface TaskOptions extends PromptOptions {
|
|
1635
|
+
/** Maximum number of agent turns (default: 10, 0 = unlimited) */
|
|
1636
|
+
maxTurns?: number;
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Result of a multi-turn task execution.
|
|
1640
|
+
*/
|
|
1641
|
+
interface TaskResult extends PromptResult {
|
|
1642
|
+
/** Number of agent turns used */
|
|
1643
|
+
turnsUsed: number;
|
|
1644
|
+
/** Session ID for the task (can be used to continue) */
|
|
1645
|
+
sessionId: string;
|
|
1646
|
+
}
|
|
1647
|
+
/**
|
|
1648
|
+
* Lifecycle state of an agent session inside a sandbox.
|
|
1649
|
+
*/
|
|
1650
|
+
type SessionStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
|
|
1651
|
+
/**
|
|
1652
|
+
* Snapshot of a session's state at the moment it was queried. Returned
|
|
1653
|
+
* by `box.session(id).status()` and `box.sessions()`.
|
|
1654
|
+
*/
|
|
1655
|
+
interface SessionInfo {
|
|
1656
|
+
/** Stable session id assigned by the sandbox runtime. */
|
|
1657
|
+
id: string;
|
|
1658
|
+
/** Current lifecycle state. */
|
|
1659
|
+
status: SessionStatus;
|
|
1660
|
+
/** Backend identifier (e.g. provider name). */
|
|
1661
|
+
backend?: string;
|
|
1662
|
+
/** Model id the session was created with. */
|
|
1663
|
+
model?: string;
|
|
1664
|
+
/** Number of prompts the session has processed. */
|
|
1665
|
+
promptCount?: number;
|
|
1666
|
+
/** When the session was created in the sandbox. */
|
|
1667
|
+
createdAt?: Date;
|
|
1668
|
+
/** When the session began executing. */
|
|
1669
|
+
startedAt?: Date;
|
|
1670
|
+
/** When the session reached a terminal state. */
|
|
1671
|
+
endedAt?: Date;
|
|
1672
|
+
/** Raw payload from the sidecar — stable subset above; this carries
|
|
1673
|
+
* everything else for forward-compatibility. */
|
|
1674
|
+
raw?: Record<string, unknown>;
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1677
|
+
* Options for `box.sessions()` listing.
|
|
1678
|
+
*/
|
|
1679
|
+
interface SessionListOptions {
|
|
1680
|
+
/** Filter by status. */
|
|
1681
|
+
status?: SessionStatus;
|
|
1682
|
+
/** Filter by backend identifier. */
|
|
1683
|
+
backend?: string;
|
|
1684
|
+
}
|
|
1685
|
+
/**
|
|
1686
|
+
* Options for `SandboxSession.events()` streaming.
|
|
1687
|
+
*/
|
|
1688
|
+
interface SessionEventStreamOptions {
|
|
1689
|
+
/** Replay starting from this event id (inclusive). Omit to start at
|
|
1690
|
+
* the live tail. Useful for reconnect-after-disconnect flows. */
|
|
1691
|
+
since?: string;
|
|
1692
|
+
/** Cancel the stream by aborting this signal. */
|
|
1693
|
+
signal?: AbortSignal;
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Options for `box.dispatchPrompt()` — fire-and-detach prompt semantics.
|
|
1697
|
+
*/
|
|
1698
|
+
interface DispatchPromptOptions extends PromptOptions {
|
|
1699
|
+
/** Client-supplied session id for idempotency. Re-dispatching with
|
|
1700
|
+
* the same id while the session is running is a lookup, not a
|
|
1701
|
+
* re-create. Lets queue retries and reconnect-after-restart be safe
|
|
1702
|
+
* by construction. */
|
|
1703
|
+
sessionId?: string;
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Returned by `box.dispatchPrompt()` — minimum the caller needs to track
|
|
1707
|
+
* the session afterward. The sandbox keeps running the prompt; use
|
|
1708
|
+
* `box.session(sessionId)` to follow it.
|
|
1709
|
+
*/
|
|
1710
|
+
interface DispatchedSession {
|
|
1711
|
+
/** Session id (either the one the caller supplied or one the sandbox
|
|
1712
|
+
* minted). */
|
|
1713
|
+
sessionId: string;
|
|
1714
|
+
/** Lifecycle state at the moment dispatch returned. */
|
|
1715
|
+
status: SessionStatus;
|
|
1716
|
+
/** True when an existing session with the supplied id was found and
|
|
1717
|
+
* dispatch was a no-op (idempotency). */
|
|
1718
|
+
alreadyExisted: boolean;
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Scope of a `box.mintScopedToken()` request. Each value narrows the
|
|
1722
|
+
* token's authority compared to the full sandbox bearer.
|
|
1723
|
+
*/
|
|
1724
|
+
type ScopedTokenScope = "session" | "project" | "read-only";
|
|
1725
|
+
/**
|
|
1726
|
+
* Options for `box.mintScopedToken()`.
|
|
1727
|
+
*/
|
|
1728
|
+
interface MintScopedTokenOptions {
|
|
1729
|
+
/** Scope to mint. `session` narrows to a single session id; `project`
|
|
1730
|
+
* grants read access to the whole sandbox; `read-only` is a project
|
|
1731
|
+
* scope without prompt-dispatch capabilities. */
|
|
1732
|
+
scope: ScopedTokenScope;
|
|
1733
|
+
/** Required when `scope === "session"`. */
|
|
1734
|
+
sessionId?: string;
|
|
1735
|
+
/** TTL in minutes. Default 5; clamped to [1, 15]. Browser-side
|
|
1736
|
+
* bearers must be short-lived; pair with `client.onTokenRefresh()`
|
|
1737
|
+
* for long-running consumers. */
|
|
1738
|
+
ttlMinutes?: number;
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Returned by `box.mintScopedToken()`. The token verifies against the
|
|
1742
|
+
* same sidecar middleware that already gates ProductTokenIssuer-issued
|
|
1743
|
+
* JWTs — no new sidecar surface.
|
|
1744
|
+
*/
|
|
1745
|
+
interface ScopedToken {
|
|
1746
|
+
/** Bearer token (JWT). Send as `Authorization: Bearer <token>` or
|
|
1747
|
+
* via the `EventSource` URL with token query param. */
|
|
1748
|
+
token: string;
|
|
1749
|
+
/** When the token expires. */
|
|
1750
|
+
expiresAt: Date;
|
|
1751
|
+
/** Echo of the requested scope. */
|
|
1752
|
+
scope: ScopedTokenScope;
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Callback invoked when the SDK refreshes a sandbox bearer transparently
|
|
1756
|
+
* (e.g. after a 401 retry against the runtime endpoint). Lets long-
|
|
1757
|
+
* running consumers propagate the new token to dependents (live
|
|
1758
|
+
* `EventSource` connections, browser-side caches, etc.).
|
|
1759
|
+
*/
|
|
1760
|
+
type TokenRefreshHandler = (sandboxId: string, newToken: string) => void;
|
|
1761
|
+
/**
|
|
1762
|
+
* Options for creating a snapshot.
|
|
1763
|
+
*/
|
|
1764
|
+
interface SnapshotOptions {
|
|
1765
|
+
/** Tags to apply to the snapshot */
|
|
1766
|
+
tags?: string[];
|
|
1767
|
+
/** Specific paths to include (default: entire workspace) */
|
|
1768
|
+
paths?: string[];
|
|
1769
|
+
/** Customer-provided storage for BYOS3 (calls the runtime directly) */
|
|
1770
|
+
storage?: StorageConfig;
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* Result of a snapshot operation.
|
|
1774
|
+
*/
|
|
1775
|
+
interface SnapshotResult {
|
|
1776
|
+
/** Unique snapshot identifier */
|
|
1777
|
+
snapshotId: string;
|
|
1778
|
+
/** When the snapshot was created */
|
|
1779
|
+
createdAt: Date;
|
|
1780
|
+
/** Size in bytes */
|
|
1781
|
+
sizeBytes?: number;
|
|
1782
|
+
/** Tags applied to the snapshot */
|
|
1783
|
+
tags: string[];
|
|
1784
|
+
}
|
|
1785
|
+
interface RestoreSnapshotOptions {
|
|
1786
|
+
destinationPath?: string;
|
|
1787
|
+
snapshotId?: string;
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* Metadata about an existing snapshot.
|
|
1791
|
+
*/
|
|
1792
|
+
interface SnapshotInfo {
|
|
1793
|
+
/** Unique snapshot identifier */
|
|
1794
|
+
snapshotId: string;
|
|
1795
|
+
/** Sandbox this snapshot belongs to */
|
|
1796
|
+
sandboxId: string;
|
|
1797
|
+
/** When the snapshot was created */
|
|
1798
|
+
createdAt: Date;
|
|
1799
|
+
/** Tags applied to the snapshot */
|
|
1800
|
+
tags: string[];
|
|
1801
|
+
/** Paths included in the snapshot */
|
|
1802
|
+
paths: string[];
|
|
1803
|
+
/** Size in bytes */
|
|
1804
|
+
sizeBytes?: number;
|
|
1805
|
+
}
|
|
1806
|
+
/**
|
|
1807
|
+
* A single task in a batch execution.
|
|
1808
|
+
*/
|
|
1809
|
+
interface BatchTask {
|
|
1810
|
+
/** Unique task identifier */
|
|
1811
|
+
id: string;
|
|
1812
|
+
/** Task prompt/message */
|
|
1813
|
+
message: string;
|
|
1814
|
+
/** Additional context for this task */
|
|
1815
|
+
context?: Record<string, unknown>;
|
|
1816
|
+
/** Per-task timeout in milliseconds */
|
|
1817
|
+
timeoutMs?: number;
|
|
1818
|
+
}
|
|
1819
|
+
/**
|
|
1820
|
+
* Options for batch execution.
|
|
1821
|
+
*/
|
|
1822
|
+
interface BatchOptions {
|
|
1823
|
+
/** Timeout for entire batch in milliseconds (default: 300000 = 5 min) */
|
|
1824
|
+
timeoutMs?: number;
|
|
1825
|
+
/** Scaling mode: fastest, balanced, or cheapest (default: balanced) */
|
|
1826
|
+
scalingMode?: "fastest" | "balanced" | "cheapest";
|
|
1827
|
+
/**
|
|
1828
|
+
* Shared backend override for the batch.
|
|
1829
|
+
*
|
|
1830
|
+
* Use `backend.profile` with a string for a named profile or a provider-neutral
|
|
1831
|
+
* `AgentProfile` object for inline profile configuration.
|
|
1832
|
+
*/
|
|
1833
|
+
backend?: Partial<BackendConfig>;
|
|
1834
|
+
/** Keep sandboxes alive after completion (default: false) */
|
|
1835
|
+
persistent?: boolean;
|
|
1836
|
+
/** Milliseconds to keep non-persistent batch sandboxes alive after completion. */
|
|
1837
|
+
graceMs?: number;
|
|
1838
|
+
/**
|
|
1839
|
+
* AbortSignal to cancel the batch mid-stream. When aborted, the HTTP
|
|
1840
|
+
* request to `/batch/run` is torn down; the SSE generator stops
|
|
1841
|
+
* yielding and `runBatch`/`streamBatch` reject with an `AbortError`.
|
|
1842
|
+
*
|
|
1843
|
+
* Note: the server-side batch may continue running to completion —
|
|
1844
|
+
* the signal is strictly for disconnecting the client from the
|
|
1845
|
+
* stream, not for halting server work.
|
|
1846
|
+
*/
|
|
1847
|
+
signal?: AbortSignal;
|
|
1848
|
+
}
|
|
1849
|
+
/**
|
|
1850
|
+
* Result of a single task in a batch.
|
|
1851
|
+
*/
|
|
1852
|
+
interface BatchTaskResult {
|
|
1853
|
+
/** Task identifier */
|
|
1854
|
+
taskId: string;
|
|
1855
|
+
/** Whether the task succeeded */
|
|
1856
|
+
success: boolean;
|
|
1857
|
+
/** Task response if successful */
|
|
1858
|
+
response?: string;
|
|
1859
|
+
/** Error message if failed */
|
|
1860
|
+
error?: string;
|
|
1861
|
+
/** Duration in milliseconds */
|
|
1862
|
+
durationMs: number;
|
|
1863
|
+
/** Number of retries */
|
|
1864
|
+
retries: number;
|
|
1865
|
+
/** Token usage if available */
|
|
1866
|
+
tokensUsed?: number;
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Summary of batch execution.
|
|
1870
|
+
*/
|
|
1871
|
+
interface BatchResult {
|
|
1872
|
+
/** Total tasks executed */
|
|
1873
|
+
totalTasks: number;
|
|
1874
|
+
/** Number of successful tasks */
|
|
1875
|
+
succeeded: number;
|
|
1876
|
+
/** Number of failed tasks */
|
|
1877
|
+
failed: number;
|
|
1878
|
+
/** Total retries across all tasks */
|
|
1879
|
+
totalRetries: number;
|
|
1880
|
+
/** Success rate (0-100) */
|
|
1881
|
+
successRate: number;
|
|
1882
|
+
/** Individual task results */
|
|
1883
|
+
results: BatchTaskResult[];
|
|
1884
|
+
}
|
|
1885
|
+
/**
|
|
1886
|
+
* SSE event from batch streaming.
|
|
1887
|
+
*/
|
|
1888
|
+
interface BatchEvent {
|
|
1889
|
+
/** Event type (batch.started, task.completed, etc.) */
|
|
1890
|
+
type: string;
|
|
1891
|
+
/** Event data */
|
|
1892
|
+
data: Record<string, unknown>;
|
|
1893
|
+
/**
|
|
1894
|
+
* Optional `id:` from the SSE frame. Present at runtime whenever
|
|
1895
|
+
* the server emits an `id:` line (used by EventSource-style
|
|
1896
|
+
* reconnection). Declared optional because the batch protocol
|
|
1897
|
+
* doesn't currently emit it — downstream consumers that want to
|
|
1898
|
+
* implement resume should feature-detect.
|
|
1899
|
+
*/
|
|
1900
|
+
id?: string;
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Stable worker identifier inside a sandbox fleet.
|
|
1904
|
+
*
|
|
1905
|
+
* Machine IDs are intentionally narrower than sandbox names so agents
|
|
1906
|
+
* can route work without smuggling shell metacharacters or path-like
|
|
1907
|
+
* values through tool calls.
|
|
1908
|
+
*/
|
|
1909
|
+
type FleetMachineId = string;
|
|
1910
|
+
type SandboxFleetMachineRole = "coordinator" | "worker";
|
|
1911
|
+
/**
|
|
1912
|
+
* Resource policy for a single fleet create call.
|
|
1913
|
+
*
|
|
1914
|
+
* These caps are enforced client-side before any sandbox is created.
|
|
1915
|
+
* Server-side plan quotas still apply and remain the source of truth.
|
|
1916
|
+
*/
|
|
1917
|
+
interface SandboxFleetPolicy {
|
|
1918
|
+
/** Maximum number of machines in this create call. Defaults to machines.length. */
|
|
1919
|
+
maxMachines?: number;
|
|
1920
|
+
/** Maximum sandbox create fanout allowed for this fleet request. */
|
|
1921
|
+
maxConcurrentCreates?: number;
|
|
1922
|
+
/** Maximum total requested CPU cores across machines with explicit resources. */
|
|
1923
|
+
maxTotalCpu?: number;
|
|
1924
|
+
/** Maximum total requested memory across machines with explicit resources. */
|
|
1925
|
+
maxTotalMemoryMb?: number;
|
|
1926
|
+
/** Maximum total requested storage across machines with explicit resources. */
|
|
1927
|
+
maxTotalStorageMb?: number;
|
|
1928
|
+
/** Maximum total requested accelerator devices across machines. */
|
|
1929
|
+
maxTotalAccelerators?: number;
|
|
1930
|
+
/** Maximum lifetime in seconds for any machine in this fleet. */
|
|
1931
|
+
maxLifetimeSeconds?: number;
|
|
1932
|
+
/** Maximum estimated USD spend for the fleet's configured lifetime. */
|
|
1933
|
+
maxSpendUsd?: number;
|
|
1934
|
+
/** Allowed infrastructure drivers for fleet machines. */
|
|
1935
|
+
allowedDrivers?: DriverType[];
|
|
1936
|
+
/** Allowed images/environments for fleet machines. */
|
|
1937
|
+
allowedImages?: string[];
|
|
1938
|
+
/** Allowed personal or public template identifiers for fleet machines. */
|
|
1939
|
+
allowedTemplateIds?: string[];
|
|
1940
|
+
/** Whether machines may request accelerator devices. Defaults to allowed. */
|
|
1941
|
+
allowAccelerators?: boolean;
|
|
1942
|
+
}
|
|
1943
|
+
interface SandboxFleetWorkspace {
|
|
1944
|
+
mode: "isolated" | "shared";
|
|
1945
|
+
id?: string;
|
|
1946
|
+
quotaMb?: number;
|
|
1947
|
+
mountPath?: string;
|
|
1948
|
+
snapshotId?: string;
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Per-machine create spec for a sandbox fleet.
|
|
1952
|
+
*/
|
|
1953
|
+
interface SandboxFleetMachineSpec extends Omit<CreateSandboxOptions, "metadata" | "name"> {
|
|
1954
|
+
/** Stable agent-facing machine id, e.g. "coordinator" or "worker-1". */
|
|
1955
|
+
machineId: FleetMachineId;
|
|
1956
|
+
/** Optional display name. Defaults to `${fleetId}-${machineId}`. */
|
|
1957
|
+
name?: string;
|
|
1958
|
+
/** Machine-specific metadata. Fleet tags are added automatically. */
|
|
1959
|
+
metadata?: Record<string, unknown>;
|
|
1960
|
+
/** Optional orchestration role. Defaults to worker. */
|
|
1961
|
+
role?: SandboxFleetMachineRole;
|
|
1962
|
+
}
|
|
1963
|
+
/**
|
|
1964
|
+
* Create a named set of sandboxes for one workload.
|
|
1965
|
+
*/
|
|
1966
|
+
interface CreateSandboxFleetOptions {
|
|
1967
|
+
/** Stable fleet id. Generated when omitted. */
|
|
1968
|
+
fleetId?: string;
|
|
1969
|
+
/** Shared defaults applied to every machine before per-machine overrides. */
|
|
1970
|
+
defaults?: Omit<CreateSandboxOptions, "metadata" | "name">;
|
|
1971
|
+
/** Machines to create. */
|
|
1972
|
+
machines: SandboxFleetMachineSpec[];
|
|
1973
|
+
/** Fleet-level metadata copied to each sandbox under stable tags. */
|
|
1974
|
+
metadata?: Record<string, unknown>;
|
|
1975
|
+
/** Workspace policy for isolated or driver-supported shared mounts. */
|
|
1976
|
+
workspace?: SandboxFleetWorkspace;
|
|
1977
|
+
/**
|
|
1978
|
+
* Client-side safety caps for this create call. These do not replace
|
|
1979
|
+
* server-side quota enforcement.
|
|
1980
|
+
*/
|
|
1981
|
+
policy?: SandboxFleetPolicy;
|
|
1982
|
+
/**
|
|
1983
|
+
* Delete already-created machines if a later machine fails to create.
|
|
1984
|
+
* Defaults to true so partial fleets do not silently burn quota.
|
|
1985
|
+
*/
|
|
1986
|
+
cleanupOnFailure?: boolean;
|
|
1987
|
+
/**
|
|
1988
|
+
* Maximum concurrent sandbox creates for this fleet request.
|
|
1989
|
+
* Defaults to 4 to avoid accidental control-plane stampedes while still
|
|
1990
|
+
* provisioning worker fleets faster than serial creation.
|
|
1991
|
+
*/
|
|
1992
|
+
maxConcurrentCreates?: number;
|
|
1993
|
+
/**
|
|
1994
|
+
* Idempotency key for the server-backed fleet record. Defaults to fleetId.
|
|
1995
|
+
*/
|
|
1996
|
+
idempotencyKey?: string;
|
|
1997
|
+
}
|
|
1998
|
+
interface CreateSandboxFleetWithCoordinatorOptions extends Omit<CreateSandboxFleetOptions, "machines"> {
|
|
1999
|
+
/** Coordinator machine. Defaults to machineId "coordinator". */
|
|
2000
|
+
coordinator?: Omit<SandboxFleetMachineSpec, "machineId" | "role"> & {
|
|
2001
|
+
machineId?: FleetMachineId;
|
|
2002
|
+
};
|
|
2003
|
+
/** Worker machines attached to the same fleet. */
|
|
2004
|
+
workers: SandboxFleetMachineSpec[];
|
|
2005
|
+
}
|
|
2006
|
+
/**
|
|
2007
|
+
* A sandbox with its fleet-local machine id.
|
|
2008
|
+
*/
|
|
2009
|
+
interface SandboxFleetMachine {
|
|
2010
|
+
machineId: FleetMachineId;
|
|
2011
|
+
sandbox: SandboxInfo;
|
|
2012
|
+
role?: SandboxFleetMachineRole;
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* Fleet create/list result.
|
|
2016
|
+
*/
|
|
2017
|
+
interface SandboxFleetInfo {
|
|
2018
|
+
fleetId: string;
|
|
2019
|
+
machines: SandboxFleetMachine[];
|
|
2020
|
+
}
|
|
2021
|
+
interface FleetExecDispatchOptions extends Pick<ExecOptions, "cwd" | "env" | "timeoutMs"> {
|
|
2022
|
+
machines?: FleetMachineId[];
|
|
2023
|
+
maxConcurrent?: number;
|
|
2024
|
+
retry?: {
|
|
2025
|
+
attempts?: number;
|
|
2026
|
+
};
|
|
2027
|
+
/** Caller-supplied dispatch id for idempotency/result lookup when supported by the API. */
|
|
2028
|
+
dispatchId?: string;
|
|
2029
|
+
/** Ask the API to retain branch results for later `dispatchResults` calls. */
|
|
2030
|
+
bufferResults?: boolean;
|
|
2031
|
+
}
|
|
2032
|
+
interface FleetExecDispatchResult {
|
|
2033
|
+
machineId: FleetMachineId;
|
|
2034
|
+
sandboxId: string;
|
|
2035
|
+
ok: boolean;
|
|
2036
|
+
durationMs: number;
|
|
2037
|
+
attempts?: number;
|
|
2038
|
+
result?: ExecResult;
|
|
2039
|
+
error?: {
|
|
2040
|
+
message: string;
|
|
2041
|
+
status?: number;
|
|
2042
|
+
failureClass?: SandboxFleetDispatchFailureClass;
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
2045
|
+
interface FleetPromptDispatchOptions extends Pick<PromptOptions, "sessionId" | "model" | "backend" | "timeoutMs" | "context"> {
|
|
2046
|
+
machines?: FleetMachineId[];
|
|
2047
|
+
maxConcurrent?: number;
|
|
2048
|
+
retry?: {
|
|
2049
|
+
attempts?: number;
|
|
2050
|
+
};
|
|
2051
|
+
/** Caller-supplied dispatch id for idempotency/result lookup when supported by the API. */
|
|
2052
|
+
dispatchId?: string;
|
|
2053
|
+
/** Ask the API to retain branch results for later `dispatchResults` calls. */
|
|
2054
|
+
bufferResults?: boolean;
|
|
2055
|
+
}
|
|
2056
|
+
interface FleetPromptDispatchResult {
|
|
2057
|
+
machineId: FleetMachineId;
|
|
2058
|
+
sandboxId: string;
|
|
2059
|
+
ok: boolean;
|
|
2060
|
+
durationMs: number;
|
|
2061
|
+
attempts?: number;
|
|
2062
|
+
prompt?: PromptResult & {
|
|
2063
|
+
metadata?: Record<string, unknown>;
|
|
2064
|
+
};
|
|
2065
|
+
error?: {
|
|
2066
|
+
message: string;
|
|
2067
|
+
status?: number;
|
|
2068
|
+
failureClass?: SandboxFleetDispatchFailureClass;
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
type SandboxFleetDispatchFailureClass = "oom" | "timeout" | "dependency" | "infra" | "model" | "user_code";
|
|
2072
|
+
interface FleetDispatchStreamOptions {
|
|
2073
|
+
signal?: AbortSignal;
|
|
2074
|
+
}
|
|
2075
|
+
interface FleetDispatchResultBufferOptions {
|
|
2076
|
+
cursor?: string;
|
|
2077
|
+
limit?: number;
|
|
2078
|
+
machines?: FleetMachineId[];
|
|
2079
|
+
}
|
|
2080
|
+
interface FleetDispatchResultBuffer<T = FleetExecDispatchResult | FleetPromptDispatchResult> {
|
|
2081
|
+
fleetId: string;
|
|
2082
|
+
dispatchId: string;
|
|
2083
|
+
results: T[];
|
|
2084
|
+
cursor?: string;
|
|
2085
|
+
nextCursor?: string;
|
|
2086
|
+
done?: boolean;
|
|
2087
|
+
truncated?: boolean;
|
|
2088
|
+
trace?: SandboxFleetTraceExport;
|
|
2089
|
+
intelligence?: SandboxFleetIntelligenceEnvelope;
|
|
2090
|
+
}
|
|
2091
|
+
interface FleetDispatchCancelResult {
|
|
2092
|
+
fleetId: string;
|
|
2093
|
+
dispatchId: string;
|
|
2094
|
+
cancelled: boolean;
|
|
2095
|
+
status?: string;
|
|
2096
|
+
}
|
|
2097
|
+
interface SandboxFleetArtifactSpec {
|
|
2098
|
+
machineId: FleetMachineId;
|
|
2099
|
+
/**
|
|
2100
|
+
* Absolute path under /workspace. Fleet artifact collection intentionally
|
|
2101
|
+
* rejects host/system paths so caller-provided manifests cannot turn artifact
|
|
2102
|
+
* collection into arbitrary sandbox file reads.
|
|
2103
|
+
*/
|
|
2104
|
+
path: string;
|
|
2105
|
+
label?: string;
|
|
2106
|
+
/** Maximum allowed artifact content size in bytes. Defaults to 5 MiB. */
|
|
2107
|
+
maxBytes?: number;
|
|
2108
|
+
}
|
|
2109
|
+
interface SandboxFleetArtifact extends SandboxFleetArtifactSpec {
|
|
2110
|
+
sandboxId: string;
|
|
2111
|
+
content: string;
|
|
2112
|
+
}
|
|
2113
|
+
interface SandboxFleetDriverTimings {
|
|
2114
|
+
queueMs?: number;
|
|
2115
|
+
placementMs?: number;
|
|
2116
|
+
provisionMs?: number;
|
|
2117
|
+
startupMs?: number;
|
|
2118
|
+
cleanupMs?: number;
|
|
2119
|
+
}
|
|
2120
|
+
interface SandboxFleetMachineMeteredUsage {
|
|
2121
|
+
runtimeMs: number;
|
|
2122
|
+
updatedAt: string;
|
|
2123
|
+
}
|
|
2124
|
+
interface AttachSandboxFleetMachineOptions {
|
|
2125
|
+
machineId: FleetMachineId;
|
|
2126
|
+
sandboxId: string;
|
|
2127
|
+
status?: string;
|
|
2128
|
+
role?: SandboxFleetMachineRole;
|
|
2129
|
+
driverType?: DriverType;
|
|
2130
|
+
image?: string;
|
|
2131
|
+
environment?: string;
|
|
2132
|
+
templateId?: string;
|
|
2133
|
+
publicTemplateId?: string;
|
|
2134
|
+
acceleratorCount?: number;
|
|
2135
|
+
driverTimings?: SandboxFleetDriverTimings;
|
|
2136
|
+
}
|
|
2137
|
+
interface SandboxFleetMachineRecord extends AttachSandboxFleetMachineOptions {
|
|
2138
|
+
workspaceMountPath?: string;
|
|
2139
|
+
meteredUsage?: SandboxFleetMachineMeteredUsage;
|
|
2140
|
+
createdAt?: string;
|
|
2141
|
+
updatedAt?: string;
|
|
2142
|
+
}
|
|
2143
|
+
interface SandboxFleetManifestMachine {
|
|
2144
|
+
machineId: FleetMachineId;
|
|
2145
|
+
sandboxId: string;
|
|
2146
|
+
role?: SandboxFleetMachineRole;
|
|
2147
|
+
status?: string;
|
|
2148
|
+
driverType?: DriverType;
|
|
2149
|
+
image?: string;
|
|
2150
|
+
environment?: string;
|
|
2151
|
+
templateId?: string;
|
|
2152
|
+
publicTemplateId?: string;
|
|
2153
|
+
acceleratorCount?: number;
|
|
2154
|
+
workspaceMountPath?: string;
|
|
2155
|
+
driverTimings?: SandboxFleetDriverTimings;
|
|
2156
|
+
meteredUsage?: SandboxFleetMachineMeteredUsage;
|
|
2157
|
+
createdAt?: string;
|
|
2158
|
+
updatedAt?: string;
|
|
2159
|
+
}
|
|
2160
|
+
interface SandboxFleetManifest {
|
|
2161
|
+
fleetId?: string;
|
|
2162
|
+
id?: string;
|
|
2163
|
+
metadata?: Record<string, unknown>;
|
|
2164
|
+
policy?: SandboxFleetPolicy;
|
|
2165
|
+
resources?: Record<string, unknown>;
|
|
2166
|
+
workspace?: SandboxFleetWorkspace & {
|
|
2167
|
+
status?: string;
|
|
2168
|
+
createdAt?: string;
|
|
2169
|
+
updatedAt?: string;
|
|
2170
|
+
deletedAt?: string;
|
|
2171
|
+
};
|
|
2172
|
+
machines: SandboxFleetManifestMachine[];
|
|
2173
|
+
createdAt?: string;
|
|
2174
|
+
updatedAt?: string;
|
|
2175
|
+
}
|
|
2176
|
+
interface SandboxFleetDispatchResponse<T = FleetExecDispatchResult | FleetPromptDispatchResult> {
|
|
2177
|
+
fleetId: string;
|
|
2178
|
+
dispatchId: string;
|
|
2179
|
+
type: "exec" | "prompt";
|
|
2180
|
+
results: T[];
|
|
2181
|
+
durationMs: number;
|
|
2182
|
+
trace?: SandboxFleetTraceExport;
|
|
2183
|
+
intelligence?: SandboxFleetIntelligenceEnvelope;
|
|
2184
|
+
}
|
|
2185
|
+
interface SandboxFleetWorkspaceSnapshotResult {
|
|
2186
|
+
snapshotId?: string;
|
|
2187
|
+
id?: string;
|
|
2188
|
+
status?: string;
|
|
2189
|
+
createdAt?: string;
|
|
2190
|
+
[key: string]: JsonValue | undefined;
|
|
2191
|
+
}
|
|
2192
|
+
interface SandboxFleetWorkspaceRestoreResult {
|
|
2193
|
+
restored?: boolean;
|
|
2194
|
+
snapshotId?: string;
|
|
2195
|
+
status?: string;
|
|
2196
|
+
[key: string]: JsonValue | undefined;
|
|
2197
|
+
}
|
|
2198
|
+
interface SandboxFleetWorkspaceReconcileResult {
|
|
2199
|
+
fleetId: string;
|
|
2200
|
+
workspaceId?: string;
|
|
2201
|
+
checked: number;
|
|
2202
|
+
orphanedMounts: number;
|
|
2203
|
+
machines: Array<{
|
|
2204
|
+
machineId: string;
|
|
2205
|
+
sandboxId: string;
|
|
2206
|
+
mounted: boolean;
|
|
2207
|
+
}>;
|
|
2208
|
+
}
|
|
2209
|
+
interface SandboxFleetDriverCapability {
|
|
2210
|
+
driverType: DriverType;
|
|
2211
|
+
sharedWorkspace: boolean;
|
|
2212
|
+
accelerators: boolean;
|
|
2213
|
+
queueTimings: boolean;
|
|
2214
|
+
}
|
|
2215
|
+
interface SandboxFleetOperationsSummary {
|
|
2216
|
+
capacity: {
|
|
2217
|
+
fleets: number;
|
|
2218
|
+
machines: number;
|
|
2219
|
+
runningMachines: number;
|
|
2220
|
+
failedMachines: number;
|
|
2221
|
+
requestedCpu: number;
|
|
2222
|
+
requestedMemoryMb: number;
|
|
2223
|
+
requestedStorageMb: number;
|
|
2224
|
+
requestedAccelerators: number;
|
|
2225
|
+
};
|
|
2226
|
+
alerts: Array<{
|
|
2227
|
+
name: string;
|
|
2228
|
+
severity: "info" | "warn" | "critical";
|
|
2229
|
+
fleetId?: string;
|
|
2230
|
+
machineId?: string;
|
|
2231
|
+
message: string;
|
|
2232
|
+
runbook: string[];
|
|
2233
|
+
}>;
|
|
2234
|
+
}
|
|
2235
|
+
interface ReconcileSandboxFleetsOptions {
|
|
2236
|
+
dryRun?: boolean;
|
|
2237
|
+
}
|
|
2238
|
+
interface ReconcileSandboxFleetsResult {
|
|
2239
|
+
dryRun: boolean;
|
|
2240
|
+
checked: number;
|
|
2241
|
+
orphaned: number;
|
|
2242
|
+
removed: number;
|
|
2243
|
+
machines: Array<{
|
|
2244
|
+
fleetId: string;
|
|
2245
|
+
machineId: string;
|
|
2246
|
+
sandboxId: string;
|
|
2247
|
+
removed: boolean;
|
|
2248
|
+
status?: number;
|
|
2249
|
+
error?: string;
|
|
2250
|
+
}>;
|
|
2251
|
+
}
|
|
2252
|
+
interface SandboxFleetUsage {
|
|
2253
|
+
usage: {
|
|
2254
|
+
fleetId: string;
|
|
2255
|
+
status: string;
|
|
2256
|
+
machineCount: number;
|
|
2257
|
+
coordinatorCount: number;
|
|
2258
|
+
workerCount: number;
|
|
2259
|
+
runningMachines: number;
|
|
2260
|
+
failedMachines: number;
|
|
2261
|
+
resources?: {
|
|
2262
|
+
machines: number;
|
|
2263
|
+
totalCpu: number;
|
|
2264
|
+
totalMemoryMb: number;
|
|
2265
|
+
totalStorageMb: number;
|
|
2266
|
+
totalAccelerators: number;
|
|
2267
|
+
maxLifetimeSeconds?: number;
|
|
2268
|
+
};
|
|
2269
|
+
meteredUsage?: {
|
|
2270
|
+
runtimeMs: number;
|
|
2271
|
+
machineRuntimeMs: Record<string, number>;
|
|
2272
|
+
updatedAt: string;
|
|
2273
|
+
};
|
|
2274
|
+
createdAt: string;
|
|
2275
|
+
updatedAt: string;
|
|
2276
|
+
};
|
|
2277
|
+
insights: {
|
|
2278
|
+
reliabilityScore: number;
|
|
2279
|
+
parallelismEfficiencyScore: number;
|
|
2280
|
+
failureRate: number;
|
|
2281
|
+
recommendedActions: string[];
|
|
2282
|
+
};
|
|
2283
|
+
trace: SandboxFleetTraceExport;
|
|
2284
|
+
intelligence: SandboxFleetIntelligenceEnvelope;
|
|
2285
|
+
}
|
|
2286
|
+
interface SandboxFleetTraceEvent {
|
|
2287
|
+
type: "fleet.lifecycle.snapshot" | "fleet.machine.lifecycle.snapshot" | "fleet.workspace.lifecycle.snapshot" | "fleet.usage.snapshot" | "fleet.dispatch.result" | "fleet.insight.summary";
|
|
2288
|
+
timestamp: string;
|
|
2289
|
+
fleetId: string;
|
|
2290
|
+
machineId?: string;
|
|
2291
|
+
durationMs?: number;
|
|
2292
|
+
attributes: Record<string, unknown>;
|
|
2293
|
+
}
|
|
2294
|
+
interface SandboxFleetTraceExport {
|
|
2295
|
+
schemaVersion: "fleet.trace.v1";
|
|
2296
|
+
traceId: string;
|
|
2297
|
+
fleetId: string;
|
|
2298
|
+
exportedAt: string;
|
|
2299
|
+
timings: {
|
|
2300
|
+
observedLifecycleMs: number;
|
|
2301
|
+
machineObservedLifecycleMs: number;
|
|
2302
|
+
dispatchFanoutMs: number;
|
|
2303
|
+
dispatchRuntimeMs: number;
|
|
2304
|
+
cleanupObservedMs: number;
|
|
2305
|
+
driverQueueMs: number;
|
|
2306
|
+
driverPlacementMs: number;
|
|
2307
|
+
driverProvisionMs: number;
|
|
2308
|
+
driverStartupMs: number;
|
|
2309
|
+
driverCleanupMs: number;
|
|
2310
|
+
};
|
|
2311
|
+
criticalPath: {
|
|
2312
|
+
durationMs: number;
|
|
2313
|
+
phases: Array<{
|
|
2314
|
+
name: string;
|
|
2315
|
+
durationMs: number;
|
|
2316
|
+
machineId?: string;
|
|
2317
|
+
}>;
|
|
2318
|
+
};
|
|
2319
|
+
events: SandboxFleetTraceEvent[];
|
|
2320
|
+
}
|
|
2321
|
+
interface SandboxFleetIntelligenceEnvelope {
|
|
2322
|
+
schemaVersion: "fleet.intelligence.v1";
|
|
2323
|
+
source: "sandbox-api";
|
|
2324
|
+
subject: {
|
|
2325
|
+
type: "sandbox_fleet";
|
|
2326
|
+
fleetId: string;
|
|
2327
|
+
};
|
|
2328
|
+
billing: {
|
|
2329
|
+
billable: false;
|
|
2330
|
+
billedTo: "platform";
|
|
2331
|
+
costUsd: 0;
|
|
2332
|
+
reason: "deterministic_platform_insight";
|
|
2333
|
+
};
|
|
2334
|
+
metrics: Record<string, number>;
|
|
2335
|
+
signals: Array<{
|
|
2336
|
+
name: string;
|
|
2337
|
+
value: string | number | boolean;
|
|
2338
|
+
severity: "info" | "warn" | "critical";
|
|
2339
|
+
rationale: string;
|
|
2340
|
+
}>;
|
|
2341
|
+
recommendedActions: string[];
|
|
2342
|
+
}
|
|
2343
|
+
interface SandboxFleetTraceBundle {
|
|
2344
|
+
trace: SandboxFleetTraceExport;
|
|
2345
|
+
intelligence?: SandboxFleetIntelligenceEnvelope;
|
|
2346
|
+
}
|
|
2347
|
+
interface SandboxFleetTraceOptions {
|
|
2348
|
+
/**
|
|
2349
|
+
* Include the platform-generated intelligence envelope. Defaults to false.
|
|
2350
|
+
* Set true when a customer wants generated insight with the raw trace export.
|
|
2351
|
+
*/
|
|
2352
|
+
includeIntelligence?: boolean;
|
|
2353
|
+
}
|
|
2354
|
+
interface SandboxFleetCostEstimate {
|
|
2355
|
+
plan: "free" | "pro" | "enterprise";
|
|
2356
|
+
currency: "USD";
|
|
2357
|
+
hourlyUsd: number;
|
|
2358
|
+
maxLifetimeSeconds: number;
|
|
2359
|
+
estimatedMaxLifetimeUsd: number;
|
|
2360
|
+
requestedResources: {
|
|
2361
|
+
machines: number;
|
|
2362
|
+
totalCpu: number;
|
|
2363
|
+
totalMemoryMb: number;
|
|
2364
|
+
totalStorageMb: number;
|
|
2365
|
+
totalAccelerators: number;
|
|
2366
|
+
maxLifetimeSeconds?: number;
|
|
2367
|
+
};
|
|
2368
|
+
rates: {
|
|
2369
|
+
cpuPerHr: number;
|
|
2370
|
+
ramPerGbHr: number;
|
|
2371
|
+
diskPerGbHr: number;
|
|
2372
|
+
acceleratorPerDeviceHr: number;
|
|
2373
|
+
minChargePerHr: number;
|
|
2374
|
+
entDiscount: number;
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
type SandboxFleetTokenAction = "list" | "create" | "delete" | "exec" | "prompt" | "read" | "write";
|
|
2378
|
+
interface CreateSandboxFleetTokenOptions {
|
|
2379
|
+
/** Allowed fleet actions. Defaults to read/list/exec. */
|
|
2380
|
+
actions?: SandboxFleetTokenAction[];
|
|
2381
|
+
/** Optional token-side policy caps enforced by the Sandbox API. */
|
|
2382
|
+
policy?: SandboxFleetPolicy;
|
|
2383
|
+
/** Token lifetime in minutes. API clamps to its server-side maximum. */
|
|
2384
|
+
ttlMinutes?: number;
|
|
2385
|
+
}
|
|
2386
|
+
interface SandboxFleetToken {
|
|
2387
|
+
token: string;
|
|
2388
|
+
expiresAt: number;
|
|
2389
|
+
fleetId: string;
|
|
2390
|
+
actions: SandboxFleetTokenAction[];
|
|
2391
|
+
policy?: SandboxFleetPolicy;
|
|
2392
|
+
}
|
|
2393
|
+
interface ReapExpiredSandboxFleetsOptions {
|
|
2394
|
+
dryRun?: boolean;
|
|
2395
|
+
}
|
|
2396
|
+
interface ReapExpiredSandboxFleetsResult {
|
|
2397
|
+
dryRun: boolean;
|
|
2398
|
+
expired: number;
|
|
2399
|
+
deleted: number;
|
|
2400
|
+
fleets: Array<{
|
|
2401
|
+
fleetId: string;
|
|
2402
|
+
expiredAt: string;
|
|
2403
|
+
deleted: boolean;
|
|
2404
|
+
machines: Array<{
|
|
2405
|
+
machineId: string;
|
|
2406
|
+
sandboxId: string;
|
|
2407
|
+
ok: boolean;
|
|
2408
|
+
status?: number;
|
|
2409
|
+
error?: string;
|
|
2410
|
+
}>;
|
|
2411
|
+
}>;
|
|
2412
|
+
}
|
|
2413
|
+
/**
|
|
2414
|
+
* Options for listing fleet machines.
|
|
2415
|
+
*/
|
|
2416
|
+
interface ListSandboxFleetOptions extends ListSandboxOptions {
|
|
2417
|
+
/** Fleet id to filter by. */
|
|
2418
|
+
fleetId: string;
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Options for creating a checkpoint.
|
|
2422
|
+
*/
|
|
2423
|
+
interface CheckpointOptions {
|
|
2424
|
+
/** Tags to apply to the checkpoint */
|
|
2425
|
+
tags?: string[];
|
|
2426
|
+
/** Keep sandbox running after checkpoint (default: false - sandbox stops) */
|
|
2427
|
+
leaveRunning?: boolean;
|
|
2428
|
+
/** Also create a filesystem snapshot for data consistency */
|
|
2429
|
+
includeSnapshot?: boolean;
|
|
2430
|
+
}
|
|
2431
|
+
/**
|
|
2432
|
+
* Result of a checkpoint operation.
|
|
2433
|
+
*/
|
|
2434
|
+
interface CheckpointResult {
|
|
2435
|
+
/** Unique checkpoint identifier */
|
|
2436
|
+
checkpointId: string;
|
|
2437
|
+
/** When the checkpoint was created */
|
|
2438
|
+
createdAt: Date;
|
|
2439
|
+
/** Size of checkpoint in bytes (memory state) */
|
|
2440
|
+
sizeBytes?: number;
|
|
2441
|
+
/** Tags applied to the checkpoint */
|
|
2442
|
+
tags: string[];
|
|
2443
|
+
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Information about an existing checkpoint.
|
|
2446
|
+
*/
|
|
2447
|
+
interface CheckpointInfo {
|
|
2448
|
+
/** Unique checkpoint identifier */
|
|
2449
|
+
checkpointId: string;
|
|
2450
|
+
/** Sandbox this checkpoint belongs to */
|
|
2451
|
+
sandboxId: string;
|
|
2452
|
+
/** When the checkpoint was created */
|
|
2453
|
+
createdAt: Date;
|
|
2454
|
+
/** Tags applied to the checkpoint */
|
|
2455
|
+
tags: string[];
|
|
2456
|
+
/** Size of checkpoint in bytes */
|
|
2457
|
+
sizeBytes?: number;
|
|
2458
|
+
/** Whether checkpoint includes memory state */
|
|
2459
|
+
hasMemoryState: boolean;
|
|
2460
|
+
/** Whether checkpoint includes filesystem snapshot */
|
|
2461
|
+
hasFilesystemSnapshot: boolean;
|
|
2462
|
+
}
|
|
2463
|
+
/**
|
|
2464
|
+
* Options for forking a sandbox from a checkpoint.
|
|
2465
|
+
*/
|
|
2466
|
+
interface ForkOptions {
|
|
2467
|
+
/** Name for the forked sandbox */
|
|
2468
|
+
name?: string;
|
|
2469
|
+
/** Override environment variables in the fork */
|
|
2470
|
+
env?: Record<string, string>;
|
|
2471
|
+
/** Override resource limits in the fork */
|
|
2472
|
+
resources?: SandboxResources;
|
|
2473
|
+
/** Custom metadata for the fork */
|
|
2474
|
+
metadata?: Record<string, unknown>;
|
|
2475
|
+
}
|
|
2476
|
+
/**
|
|
2477
|
+
* Result of a fork operation.
|
|
2478
|
+
*/
|
|
2479
|
+
interface ForkResult {
|
|
2480
|
+
/** The newly created sandbox instance */
|
|
2481
|
+
sandbox: SandboxInfo;
|
|
2482
|
+
/** The checkpoint that was forked from */
|
|
2483
|
+
sourceCheckpoint: CheckpointInfo;
|
|
2484
|
+
/** ID of the source sandbox */
|
|
2485
|
+
sourceId: string;
|
|
2486
|
+
/** Time taken to fork in milliseconds */
|
|
2487
|
+
forkTimeMs: number;
|
|
2488
|
+
}
|
|
2489
|
+
/**
|
|
2490
|
+
* Infrastructure driver identifier.
|
|
2491
|
+
*
|
|
2492
|
+
* Most callers should omit `driver` and let the platform select automatically.
|
|
2493
|
+
*/
|
|
2494
|
+
type DriverType = "docker" | "firecracker" | "host-agent" | "tangle";
|
|
2495
|
+
/**
|
|
2496
|
+
* Accelerator class for GPU-class workloads.
|
|
2497
|
+
*
|
|
2498
|
+
* Examples: `nvidia-h100`, `nvidia-l4`, `nvidia-rtx-4090`, `amd-mi300x`.
|
|
2499
|
+
* Providers can introduce new SKU labels without requiring an SDK release.
|
|
2500
|
+
*/
|
|
2501
|
+
type AcceleratorKind = string;
|
|
2502
|
+
/**
|
|
2503
|
+
* Compute accelerator request.
|
|
2504
|
+
*
|
|
2505
|
+
* Accelerators are requested as resources because they are part of workload
|
|
2506
|
+
* shape and billing, not a driver option.
|
|
2507
|
+
*/
|
|
2508
|
+
interface SandboxAccelerator {
|
|
2509
|
+
/** Accelerator class required by the workload. */
|
|
2510
|
+
kind: AcceleratorKind;
|
|
2511
|
+
/**
|
|
2512
|
+
* Number of accelerator devices required.
|
|
2513
|
+
* @default 1
|
|
2514
|
+
*/
|
|
2515
|
+
count?: number;
|
|
2516
|
+
/** Minimum device memory in megabytes when the exact GPU class is flexible. */
|
|
2517
|
+
memoryMB?: number;
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Infrastructure driver configuration.
|
|
2521
|
+
*
|
|
2522
|
+
* @example Default
|
|
2523
|
+
* ```typescript
|
|
2524
|
+
* driver: { type: "docker" }
|
|
2525
|
+
* ```
|
|
2526
|
+
*
|
|
2527
|
+
* @example With pause/resume support
|
|
2528
|
+
* ```typescript
|
|
2529
|
+
* driver: { type: "firecracker", enableCriu: true }
|
|
2530
|
+
* ```
|
|
2531
|
+
*
|
|
2532
|
+
* @example Accelerator-backed sandbox
|
|
2533
|
+
* ```typescript
|
|
2534
|
+
* resources: {
|
|
2535
|
+
* accelerator: { kind: "nvidia-a100", count: 1 },
|
|
2536
|
+
* }
|
|
2537
|
+
* ```
|
|
2538
|
+
*/
|
|
2539
|
+
interface DriverConfig {
|
|
2540
|
+
/**
|
|
2541
|
+
* Driver type identifier.
|
|
2542
|
+
* @default "docker"
|
|
2543
|
+
*/
|
|
2544
|
+
type: DriverType;
|
|
2545
|
+
/**
|
|
2546
|
+
* Enable checkpointing for pause/resume and fork operations.
|
|
2547
|
+
* Support depends on the selected driver.
|
|
2548
|
+
*/
|
|
2549
|
+
enableCriu?: boolean;
|
|
2550
|
+
/**
|
|
2551
|
+
* Preferred placement region.
|
|
2552
|
+
* e.g., "us-east-1", "eu-west-1".
|
|
2553
|
+
*/
|
|
2554
|
+
preferredRegion?: string;
|
|
2555
|
+
/**
|
|
2556
|
+
* @deprecated Use `resources.accelerator` on sandbox or fleet machine specs.
|
|
2557
|
+
*/
|
|
2558
|
+
gpuRequired?: boolean;
|
|
2559
|
+
/**
|
|
2560
|
+
* @deprecated Use `resources.accelerator.kind`.
|
|
2561
|
+
*/
|
|
2562
|
+
gpuType?: GpuType;
|
|
2563
|
+
/**
|
|
2564
|
+
* @deprecated Use `resources.accelerator.count`.
|
|
2565
|
+
*/
|
|
2566
|
+
gpuCount?: number;
|
|
2567
|
+
}
|
|
2568
|
+
/**
|
|
2569
|
+
* Driver capabilities and status.
|
|
2570
|
+
*/
|
|
2571
|
+
interface DriverInfo {
|
|
2572
|
+
/** Driver type */
|
|
2573
|
+
type: DriverType;
|
|
2574
|
+
/** Whether driver is available */
|
|
2575
|
+
available: boolean;
|
|
2576
|
+
/** Driver version string */
|
|
2577
|
+
version: string;
|
|
2578
|
+
/** Driver capabilities */
|
|
2579
|
+
capabilities: {
|
|
2580
|
+
/** Checkpoint/restore support */criu: boolean; /** GPU support */
|
|
2581
|
+
gpu: boolean; /** Filesystem snapshots */
|
|
2582
|
+
snapshots: boolean; /** Multi-user management */
|
|
2583
|
+
userManagement: boolean; /** Network isolation */
|
|
2584
|
+
networkIsolation: boolean;
|
|
2585
|
+
};
|
|
2586
|
+
/** Current capacity */
|
|
2587
|
+
capacity?: {
|
|
2588
|
+
available: number;
|
|
2589
|
+
total: number;
|
|
2590
|
+
};
|
|
2591
|
+
acceleratorCapacity?: {
|
|
2592
|
+
available: number;
|
|
2593
|
+
total: number;
|
|
2594
|
+
kinds: AcceleratorKind[];
|
|
2595
|
+
};
|
|
2596
|
+
}
|
|
2597
|
+
/**
|
|
2598
|
+
* Backend type identifier. Controls which AI agent runtime runs inside the sandbox.
|
|
2599
|
+
*
|
|
2600
|
+
* The public-SDK source of truth. Kept in lock-step with the private
|
|
2601
|
+
* `@tangle-network/cli-agent-registry` spec list via the parity check in
|
|
2602
|
+
* `packages/cli-agent-registry/tests/specs.test.ts` (adding a new CLI spec
|
|
2603
|
+
* without updating this union surfaces as a test failure at PR review
|
|
2604
|
+
* time). Inlined here so the published SDK doesn't carry an unpublished
|
|
2605
|
+
* internal package as a runtime dep.
|
|
2606
|
+
*
|
|
2607
|
+
* - `"opencode"` — Default. Multi-provider, profile system, MCP support.
|
|
2608
|
+
* - `"claude-code"` — Anthropic Claude Code CLI. Requires an Anthropic API key.
|
|
2609
|
+
* - `"kimi-code"` — Moonshot Kimi Code CLI. Uses the operator's Kimi Code
|
|
2610
|
+
* subscription OAuth (shipped via authFiles) by default; falls back to
|
|
2611
|
+
* `MOONSHOT_API_KEY` when an apiKey is supplied.
|
|
2612
|
+
* - `"codex"` — OpenAI Codex CLI. Requires an OpenAI API key.
|
|
2613
|
+
* - `"amp"` — Sourcegraph AMP agent.
|
|
2614
|
+
* - `"factory-droids"` — Factory Droid agent.
|
|
2615
|
+
* - `"pi"` — Pi coding-agent CLI.
|
|
2616
|
+
* - `"hermes"` — Hermes inference-router agent.
|
|
2617
|
+
* - `"forge"` — Forge (forgecode.dev, tailcallhq) multi-provider coding agent.
|
|
2618
|
+
* - `"openclaw"` — OpenClaw dispatcher that routes to claude-cli/codex-cli/gemini-cli.
|
|
2619
|
+
* - `"acp"` — Agent Client Protocol bridge — fronts any ACP-compliant
|
|
2620
|
+
* agent binary (claude-agent-acp, codex-acp, gemini, openclaw acp).
|
|
2621
|
+
* Pick the backing agent via config.subAgent.
|
|
2622
|
+
* - `"cursor"` — Cursor Agent SDK local/cloud backend.
|
|
2623
|
+
* - `"cli-base"` — Minimal CLI-only (no AI agent).
|
|
2624
|
+
*/
|
|
2625
|
+
type BackendType = "opencode" | "claude-code" | "kimi-code" | "codex" | "amp" | "factory-droids" | "pi" | "hermes" | "forge" | "openclaw" | "acp" | "cursor" | "cli-base";
|
|
2626
|
+
/**
|
|
2627
|
+
* MCP (Model Context Protocol) server configuration.
|
|
2628
|
+
*/
|
|
2629
|
+
interface McpServerConfig {
|
|
2630
|
+
/** Command to run (e.g., "npx", "node") */
|
|
2631
|
+
command: string;
|
|
2632
|
+
/** Command arguments */
|
|
2633
|
+
args?: string[];
|
|
2634
|
+
/** Environment variables */
|
|
2635
|
+
env?: Record<string, string>;
|
|
2636
|
+
/** Working directory */
|
|
2637
|
+
cwd?: string;
|
|
2638
|
+
/** Remote URL (for remote MCP servers via SSE) */
|
|
2639
|
+
url?: string;
|
|
2640
|
+
/** Headers for remote connections */
|
|
2641
|
+
headers?: Record<string, string>;
|
|
2642
|
+
}
|
|
2643
|
+
/**
|
|
2644
|
+
* AI coding agent backend configuration.
|
|
2645
|
+
*
|
|
2646
|
+
* @example OpenCode with default settings
|
|
2647
|
+
* ```typescript
|
|
2648
|
+
* backend: { type: "opencode" }
|
|
2649
|
+
* ```
|
|
2650
|
+
*
|
|
2651
|
+
* @example OpenCode with named profile
|
|
2652
|
+
* ```typescript
|
|
2653
|
+
* backend: {
|
|
2654
|
+
* type: "opencode",
|
|
2655
|
+
* profile: "with-web-search",
|
|
2656
|
+
* }
|
|
2657
|
+
* ```
|
|
2658
|
+
*
|
|
2659
|
+
* @example Claude Code with BYOK
|
|
2660
|
+
* ```typescript
|
|
2661
|
+
* backend: {
|
|
2662
|
+
* type: "claude-code",
|
|
2663
|
+
* model: {
|
|
2664
|
+
* provider: "anthropic",
|
|
2665
|
+
* model: "claude-sonnet-4-20250514",
|
|
2666
|
+
* apiKey: process.env.ANTHROPIC_API_KEY,
|
|
2667
|
+
* }
|
|
2668
|
+
* }
|
|
2669
|
+
* ```
|
|
2670
|
+
*/
|
|
2671
|
+
interface BackendConfig {
|
|
2672
|
+
/**
|
|
2673
|
+
* Backend type identifier.
|
|
2674
|
+
* @default "opencode"
|
|
2675
|
+
*/
|
|
2676
|
+
type: BackendType;
|
|
2677
|
+
/**
|
|
2678
|
+
* Backend profile selection.
|
|
2679
|
+
*
|
|
2680
|
+
* Use a string for a named provider/backend profile, or an `AgentProfile`
|
|
2681
|
+
* object for an inline provider-neutral profile definition.
|
|
2682
|
+
*/
|
|
2683
|
+
profile?: string | AgentProfile;
|
|
2684
|
+
/**
|
|
2685
|
+
* Model configuration override.
|
|
2686
|
+
*/
|
|
2687
|
+
model?: {
|
|
2688
|
+
/** Provider name (e.g., "anthropic", "openai", "google") */provider?: string; /** Model identifier (e.g., "claude-sonnet-4-20250514") */
|
|
2689
|
+
model?: string; /** BYOK (Bring Your Own Key) API key */
|
|
2690
|
+
apiKey?: string; /** Custom API base URL (for proxies or on-prem) */
|
|
2691
|
+
baseUrl?: string; /** Maximum thinking tokens for extended reasoning */
|
|
2692
|
+
maxThinkingTokens?: number; /** API mode: "api" for direct calls, "cli" for CLI wrapper */
|
|
2693
|
+
mode?: "api" | "cli"; /** Authentication mode for CLI-native backends */
|
|
2694
|
+
authMode?: "api-key" | "oauth"; /** Auth files to write into the sandbox home directory before CLI startup */
|
|
2695
|
+
authFiles?: Array<{
|
|
2696
|
+
path: string;
|
|
2697
|
+
content: string;
|
|
2698
|
+
mode?: number;
|
|
2699
|
+
}>;
|
|
2700
|
+
};
|
|
2701
|
+
/**
|
|
2702
|
+
* Backend server configuration.
|
|
2703
|
+
*/
|
|
2704
|
+
server?: {
|
|
2705
|
+
/** Server port (auto-assigned if not specified) */port?: number; /** Server hostname */
|
|
2706
|
+
hostname?: string;
|
|
2707
|
+
};
|
|
2708
|
+
}
|
|
2709
|
+
/**
|
|
2710
|
+
* Backend capabilities.
|
|
2711
|
+
*/
|
|
2712
|
+
interface BackendCapabilities {
|
|
2713
|
+
/** Supports streaming responses */
|
|
2714
|
+
streaming: boolean;
|
|
2715
|
+
/** Supports tool/function use */
|
|
2716
|
+
toolUse: boolean;
|
|
2717
|
+
/** Supports extended thinking/reasoning */
|
|
2718
|
+
reasoning: boolean;
|
|
2719
|
+
/** Supports multimodal (images, etc) */
|
|
2720
|
+
multimodal: boolean;
|
|
2721
|
+
/** Context window size in tokens */
|
|
2722
|
+
contextWindow: number;
|
|
2723
|
+
/** Support details for provider-neutral `AgentProfile` values */
|
|
2724
|
+
profile?: AgentProfileCapabilities;
|
|
2725
|
+
}
|
|
2726
|
+
/**
|
|
2727
|
+
* Backend status information.
|
|
2728
|
+
*/
|
|
2729
|
+
interface BackendStatus {
|
|
2730
|
+
/** Backend type */
|
|
2731
|
+
type: BackendType;
|
|
2732
|
+
/** Current status */
|
|
2733
|
+
status: "running" | "stopped" | "starting" | "stopping" | "unknown";
|
|
2734
|
+
/** Backend version */
|
|
2735
|
+
version?: string;
|
|
2736
|
+
/** Error message if failed */
|
|
2737
|
+
error?: string;
|
|
2738
|
+
/** Additional metadata */
|
|
2739
|
+
metadata?: Record<string, unknown>;
|
|
2740
|
+
}
|
|
2741
|
+
/**
|
|
2742
|
+
* Backend information.
|
|
2743
|
+
*/
|
|
2744
|
+
interface BackendInfo {
|
|
2745
|
+
/** Backend type */
|
|
2746
|
+
type: BackendType;
|
|
2747
|
+
/** Whether backend is available */
|
|
2748
|
+
available: boolean;
|
|
2749
|
+
/** Backend capabilities */
|
|
2750
|
+
capabilities: BackendCapabilities;
|
|
2751
|
+
/** Available profiles (for opencode) */
|
|
2752
|
+
profiles?: Array<{
|
|
2753
|
+
name: string;
|
|
2754
|
+
description?: string;
|
|
2755
|
+
tags?: string[];
|
|
2756
|
+
}>;
|
|
2757
|
+
}
|
|
2758
|
+
interface BackendListOptions {
|
|
2759
|
+
limit?: number;
|
|
2760
|
+
cursor?: string;
|
|
2761
|
+
}
|
|
2762
|
+
interface BackendListResult<TItem> {
|
|
2763
|
+
items: TItem[];
|
|
2764
|
+
nextCursor?: string;
|
|
2765
|
+
}
|
|
2766
|
+
interface BackendAccount {
|
|
2767
|
+
apiKeyName?: string;
|
|
2768
|
+
userId?: number;
|
|
2769
|
+
userEmail?: string;
|
|
2770
|
+
userFirstName?: string;
|
|
2771
|
+
userLastName?: string;
|
|
2772
|
+
createdAt?: string;
|
|
2773
|
+
metadata?: Record<string, unknown>;
|
|
2774
|
+
}
|
|
2775
|
+
interface BackendModel {
|
|
2776
|
+
id: string;
|
|
2777
|
+
displayName?: string;
|
|
2778
|
+
description?: string;
|
|
2779
|
+
parameters?: Array<Record<string, unknown>>;
|
|
2780
|
+
variants?: Array<Record<string, unknown>>;
|
|
2781
|
+
}
|
|
2782
|
+
interface BackendRepository {
|
|
2783
|
+
url: string;
|
|
2784
|
+
}
|
|
2785
|
+
interface BackendAgent {
|
|
2786
|
+
agentId: string;
|
|
2787
|
+
name?: string;
|
|
2788
|
+
summary?: string;
|
|
2789
|
+
lastModified?: number;
|
|
2790
|
+
status?: "running" | "finished" | "error";
|
|
2791
|
+
createdAt?: number;
|
|
2792
|
+
archived?: boolean;
|
|
2793
|
+
runtime?: "local" | "cloud";
|
|
2794
|
+
cwd?: string;
|
|
2795
|
+
env?: Record<string, unknown>;
|
|
2796
|
+
repos?: string[];
|
|
2797
|
+
}
|
|
2798
|
+
interface BackendRun {
|
|
2799
|
+
id: string;
|
|
2800
|
+
agentId?: string;
|
|
2801
|
+
status?: "running" | "finished" | "cancelled" | "error";
|
|
2802
|
+
result?: string;
|
|
2803
|
+
durationMs?: number;
|
|
2804
|
+
model?: Record<string, unknown>;
|
|
2805
|
+
git?: Record<string, unknown>;
|
|
2806
|
+
}
|
|
2807
|
+
interface BackendArtifact {
|
|
2808
|
+
path: string;
|
|
2809
|
+
sizeBytes?: number;
|
|
2810
|
+
updatedAt?: string;
|
|
2811
|
+
}
|
|
2812
|
+
/**
|
|
2813
|
+
* Network configuration for sandbox network isolation.
|
|
2814
|
+
*
|
|
2815
|
+
* Supports two modes:
|
|
2816
|
+
* - `blockOutbound: true` - Block all egress traffic (ports still work for inbound)
|
|
2817
|
+
* - `allowList: ["cidr", ...]` - Allow only specific destinations
|
|
2818
|
+
*
|
|
2819
|
+
* These modes are mutually exclusive.
|
|
2820
|
+
*
|
|
2821
|
+
* @example Block all outbound traffic
|
|
2822
|
+
* ```typescript
|
|
2823
|
+
* const box = await client.create({
|
|
2824
|
+
* network: { blockOutbound: true }
|
|
2825
|
+
* });
|
|
2826
|
+
* ```
|
|
2827
|
+
*
|
|
2828
|
+
* @example Allow only specific destinations
|
|
2829
|
+
* ```typescript
|
|
2830
|
+
* const box = await client.create({
|
|
2831
|
+
* network: {
|
|
2832
|
+
* allowList: [
|
|
2833
|
+
* "8.8.8.8/32", // Google DNS
|
|
2834
|
+
* "10.0.0.0/8", // Private network
|
|
2835
|
+
* ]
|
|
2836
|
+
* }
|
|
2837
|
+
* });
|
|
2838
|
+
* ```
|
|
2839
|
+
*
|
|
2840
|
+
* @example Pre-expose ports at creation
|
|
2841
|
+
* ```typescript
|
|
2842
|
+
* const box = await client.create({
|
|
2843
|
+
* network: {
|
|
2844
|
+
* blockOutbound: true,
|
|
2845
|
+
* ports: [8000, 8080], // Pre-expose these ports
|
|
2846
|
+
* }
|
|
2847
|
+
* });
|
|
2848
|
+
* ```
|
|
2849
|
+
*/
|
|
2850
|
+
interface NetworkConfig {
|
|
2851
|
+
/**
|
|
2852
|
+
* Block all outbound network traffic.
|
|
2853
|
+
* Exposed ports still work for inbound connections.
|
|
2854
|
+
* Mutually exclusive with `allowList`.
|
|
2855
|
+
*/
|
|
2856
|
+
blockOutbound?: boolean;
|
|
2857
|
+
/**
|
|
2858
|
+
* CIDR allowlist for outbound traffic.
|
|
2859
|
+
* Only traffic to these destinations is allowed.
|
|
2860
|
+
* Maximum 10 entries. Mutually exclusive with `blockOutbound`.
|
|
2861
|
+
*
|
|
2862
|
+
* Supports both IPv4 and IPv6 CIDR notation:
|
|
2863
|
+
* - "8.8.8.8/32" - Single IPv4 address
|
|
2864
|
+
* - "10.0.0.0/8" - IPv4 subnet
|
|
2865
|
+
* - "2001:db8::/32" - IPv6 subnet
|
|
2866
|
+
*/
|
|
2867
|
+
allowList?: string[];
|
|
2868
|
+
/**
|
|
2869
|
+
* Ports to expose at creation time.
|
|
2870
|
+
* These ports will be accessible regardless of network restrictions.
|
|
2871
|
+
*/
|
|
2872
|
+
ports?: number[];
|
|
2873
|
+
}
|
|
2874
|
+
/**
|
|
2875
|
+
* Network manager for runtime network configuration.
|
|
2876
|
+
* Access via `sandbox.network`.
|
|
2877
|
+
*
|
|
2878
|
+
* @example Update network restrictions
|
|
2879
|
+
* ```typescript
|
|
2880
|
+
* // Block all outbound traffic
|
|
2881
|
+
* await box.network.update({ blockOutbound: true });
|
|
2882
|
+
*
|
|
2883
|
+
* // Or switch to allowlist mode
|
|
2884
|
+
* await box.network.update({
|
|
2885
|
+
* allowList: ["192.168.1.0/24", "8.8.8.8/32"]
|
|
2886
|
+
* });
|
|
2887
|
+
*
|
|
2888
|
+
* // Remove restrictions
|
|
2889
|
+
* await box.network.update({ blockOutbound: false });
|
|
2890
|
+
* ```
|
|
2891
|
+
*
|
|
2892
|
+
* @example Expose ports dynamically
|
|
2893
|
+
* ```typescript
|
|
2894
|
+
* const url = await box.network.exposePort(8000);
|
|
2895
|
+
* console.log(`Service available at: ${url}`);
|
|
2896
|
+
*
|
|
2897
|
+
* const allUrls = await box.network.listUrls();
|
|
2898
|
+
* ```
|
|
2899
|
+
*/
|
|
2900
|
+
interface NetworkManager {
|
|
2901
|
+
/**
|
|
2902
|
+
* Update network permissions at runtime.
|
|
2903
|
+
* Changes apply immediately without container restart.
|
|
2904
|
+
*
|
|
2905
|
+
* @param config - Partial network configuration to apply
|
|
2906
|
+
* @throws Error if blockOutbound and allowList are both specified
|
|
2907
|
+
* @throws Error if allowList exceeds 10 entries
|
|
2908
|
+
* @throws Error if CIDR format is invalid
|
|
2909
|
+
*/
|
|
2910
|
+
update(config: Partial<NetworkConfig>): Promise<void>;
|
|
2911
|
+
/**
|
|
2912
|
+
* Expose a port dynamically.
|
|
2913
|
+
* Returns a publicly accessible URL for the port.
|
|
2914
|
+
* Works regardless of network restrictions.
|
|
2915
|
+
*
|
|
2916
|
+
* @param port - Port number to expose (1-65535)
|
|
2917
|
+
* @returns Public URL for accessing the exposed port
|
|
2918
|
+
*/
|
|
2919
|
+
exposePort(port: number): Promise<string>;
|
|
2920
|
+
/**
|
|
2921
|
+
* List all exposed port URLs.
|
|
2922
|
+
*
|
|
2923
|
+
* @returns Map of port numbers to their public URLs
|
|
2924
|
+
*/
|
|
2925
|
+
listUrls(): Promise<Record<number, string>>;
|
|
2926
|
+
/**
|
|
2927
|
+
* Get current network configuration.
|
|
2928
|
+
*
|
|
2929
|
+
* @returns Current network config including any runtime changes
|
|
2930
|
+
*/
|
|
2931
|
+
getConfig(): Promise<NetworkConfig>;
|
|
2932
|
+
}
|
|
2933
|
+
interface PreviewLinkInfo {
|
|
2934
|
+
previewId: string;
|
|
2935
|
+
sandboxId: string;
|
|
2936
|
+
port: number;
|
|
2937
|
+
protocol: "tcp" | "udp";
|
|
2938
|
+
hostname: string;
|
|
2939
|
+
url: string;
|
|
2940
|
+
status: "provisioning" | "ready" | "error" | "disabled";
|
|
2941
|
+
lastSyncAt: string;
|
|
2942
|
+
createdAt: string;
|
|
2943
|
+
updatedAt: string;
|
|
2944
|
+
metadata?: Record<string, unknown>;
|
|
2945
|
+
}
|
|
2946
|
+
/**
|
|
2947
|
+
* Preview link management.
|
|
2948
|
+
*
|
|
2949
|
+
* Create publicly accessible HTTPS URLs for TCP ports inside the sandbox.
|
|
2950
|
+
*
|
|
2951
|
+
* @example
|
|
2952
|
+
* ```typescript
|
|
2953
|
+
* // Expose a dev server
|
|
2954
|
+
* const link = await box.previewLinks.create(3000);
|
|
2955
|
+
* console.log(link.url);
|
|
2956
|
+
*
|
|
2957
|
+
* // List all preview links
|
|
2958
|
+
* const links = await box.previewLinks.list();
|
|
2959
|
+
*
|
|
2960
|
+
* // Remove a preview link
|
|
2961
|
+
* await box.previewLinks.remove(link.previewId);
|
|
2962
|
+
* ```
|
|
2963
|
+
*/
|
|
2964
|
+
interface PreviewLinkManager {
|
|
2965
|
+
/**
|
|
2966
|
+
* Create a preview link for a port.
|
|
2967
|
+
* Returns the preview link with its public URL.
|
|
2968
|
+
* If a link already exists for this port, returns the existing one.
|
|
2969
|
+
*
|
|
2970
|
+
* @param port - Port number to expose (1-65535)
|
|
2971
|
+
* @param options - Optional protocol and metadata
|
|
2972
|
+
*/
|
|
2973
|
+
create(port: number, options?: {
|
|
2974
|
+
protocol?: "tcp" | "udp";
|
|
2975
|
+
metadata?: Record<string, unknown>;
|
|
2976
|
+
}): Promise<PreviewLinkInfo>;
|
|
2977
|
+
/**
|
|
2978
|
+
* List all preview links for this sandbox.
|
|
2979
|
+
*/
|
|
2980
|
+
list(): Promise<PreviewLinkInfo[]>;
|
|
2981
|
+
/**
|
|
2982
|
+
* Remove a preview link by ID.
|
|
2983
|
+
*
|
|
2984
|
+
* @param previewId - The preview link ID to remove
|
|
2985
|
+
*/
|
|
2986
|
+
remove(previewId: string): Promise<void>;
|
|
2987
|
+
}
|
|
2988
|
+
/**
|
|
2989
|
+
* Permission level for sandbox users.
|
|
2990
|
+
*
|
|
2991
|
+
* - `owner` — Full access, can manage users.
|
|
2992
|
+
* - `admin` — Read/write workspace, can manage users.
|
|
2993
|
+
* - `developer` — Read/write workspace.
|
|
2994
|
+
* - `viewer` — Read-only workspace.
|
|
2995
|
+
*/
|
|
2996
|
+
type PermissionLevel = "owner" | "admin" | "developer" | "viewer";
|
|
2997
|
+
/**
|
|
2998
|
+
* Directory-level permission override.
|
|
2999
|
+
*/
|
|
3000
|
+
interface DirectoryPermission {
|
|
3001
|
+
/** Directory path (absolute, e.g. "/workspace/shared") */
|
|
3002
|
+
path: string;
|
|
3003
|
+
/** Read access */
|
|
3004
|
+
read: boolean;
|
|
3005
|
+
/** Write access */
|
|
3006
|
+
write: boolean;
|
|
3007
|
+
/** Execute/traverse access */
|
|
3008
|
+
execute: boolean;
|
|
3009
|
+
}
|
|
3010
|
+
/**
|
|
3011
|
+
* Glob-based access policy rule.
|
|
3012
|
+
*
|
|
3013
|
+
* @example Block all .env files
|
|
3014
|
+
* ```typescript
|
|
3015
|
+
* { pattern: "*.env", permission: "none" }
|
|
3016
|
+
* ```
|
|
3017
|
+
*
|
|
3018
|
+
* @example Read-only secrets directory
|
|
3019
|
+
* ```typescript
|
|
3020
|
+
* { pattern: "/secrets/**", permission: "read" }
|
|
3021
|
+
* ```
|
|
3022
|
+
*/
|
|
3023
|
+
interface AccessPolicyRule {
|
|
3024
|
+
/** Glob pattern for matching (e.g., "*.env", "/secrets/**") */
|
|
3025
|
+
pattern: string;
|
|
3026
|
+
/** Access level for matching paths */
|
|
3027
|
+
permission: "read" | "write" | "none";
|
|
3028
|
+
/** Priority when patterns overlap (higher wins) */
|
|
3029
|
+
priority?: number;
|
|
3030
|
+
}
|
|
3031
|
+
/**
|
|
3032
|
+
* User in a sandbox.
|
|
3033
|
+
*/
|
|
3034
|
+
interface SandboxUser {
|
|
3035
|
+
/** Unique user ID (from auth system) */
|
|
3036
|
+
userId: string;
|
|
3037
|
+
/** Username inside sandbox (Unix username) */
|
|
3038
|
+
username: string;
|
|
3039
|
+
/** Home directory path */
|
|
3040
|
+
homeDir: string;
|
|
3041
|
+
/** Permission level */
|
|
3042
|
+
role: PermissionLevel;
|
|
3043
|
+
/** SSH public keys */
|
|
3044
|
+
sshKeys: string[];
|
|
3045
|
+
/** Directory permission overrides */
|
|
3046
|
+
directoryPermissions?: DirectoryPermission[];
|
|
3047
|
+
/** Access policy rules */
|
|
3048
|
+
accessPolicies?: AccessPolicyRule[];
|
|
3049
|
+
/** When user was added */
|
|
3050
|
+
createdAt: Date;
|
|
3051
|
+
}
|
|
3052
|
+
/**
|
|
3053
|
+
* Options for adding a user to a sandbox.
|
|
3054
|
+
*/
|
|
3055
|
+
interface AddUserOptions {
|
|
3056
|
+
/** Unique user ID (from your auth system) */
|
|
3057
|
+
userId: string;
|
|
3058
|
+
/** Preferred username (will be sanitized for Unix) */
|
|
3059
|
+
username?: string;
|
|
3060
|
+
/** Permission level (default: developer) */
|
|
3061
|
+
role?: PermissionLevel;
|
|
3062
|
+
/** SSH public keys for remote access */
|
|
3063
|
+
sshKeys?: string[];
|
|
3064
|
+
/** Custom directory permissions */
|
|
3065
|
+
directoryPermissions?: DirectoryPermission[];
|
|
3066
|
+
}
|
|
3067
|
+
/**
|
|
3068
|
+
* Options for updating a user.
|
|
3069
|
+
*/
|
|
3070
|
+
interface UpdateUserOptions {
|
|
3071
|
+
/** New permission level */
|
|
3072
|
+
role?: PermissionLevel;
|
|
3073
|
+
/** SSH keys to add */
|
|
3074
|
+
addSshKeys?: string[];
|
|
3075
|
+
/** SSH keys to remove */
|
|
3076
|
+
removeSshKeys?: string[];
|
|
3077
|
+
/** Directory permissions to add/update */
|
|
3078
|
+
directoryPermissions?: DirectoryPermission[];
|
|
3079
|
+
}
|
|
3080
|
+
/**
|
|
3081
|
+
* Initial permissions configuration for sandbox creation.
|
|
3082
|
+
*/
|
|
3083
|
+
interface SandboxPermissionsConfig {
|
|
3084
|
+
/**
|
|
3085
|
+
* Default role for invited users.
|
|
3086
|
+
* @default "developer"
|
|
3087
|
+
*/
|
|
3088
|
+
defaultRole?: PermissionLevel;
|
|
3089
|
+
/**
|
|
3090
|
+
* Users to invite at creation time.
|
|
3091
|
+
* Owner is automatically added from the API key.
|
|
3092
|
+
*/
|
|
3093
|
+
initialUsers?: Array<{
|
|
3094
|
+
userId: string;
|
|
3095
|
+
role?: PermissionLevel;
|
|
3096
|
+
sshKeys?: string[];
|
|
3097
|
+
}>;
|
|
3098
|
+
/**
|
|
3099
|
+
* Default access policies for all users.
|
|
3100
|
+
*/
|
|
3101
|
+
defaultPolicies?: AccessPolicyRule[];
|
|
3102
|
+
/**
|
|
3103
|
+
* Enable multi-user mode.
|
|
3104
|
+
* @default true when initialUsers is provided
|
|
3105
|
+
*/
|
|
3106
|
+
multiUser?: boolean;
|
|
3107
|
+
}
|
|
3108
|
+
/**
|
|
3109
|
+
* Permissions manager interface.
|
|
3110
|
+
* Access via `sandbox.permissions`.
|
|
3111
|
+
*/
|
|
3112
|
+
interface PermissionsManager {
|
|
3113
|
+
/** List all users in the sandbox */
|
|
3114
|
+
list(): Promise<SandboxUser[]>;
|
|
3115
|
+
/** Get a specific user */
|
|
3116
|
+
get(userId: string): Promise<SandboxUser | null>;
|
|
3117
|
+
/** Add a user to the sandbox */
|
|
3118
|
+
add(options: AddUserOptions): Promise<SandboxUser>;
|
|
3119
|
+
/** Update a user's permissions */
|
|
3120
|
+
update(userId: string, options: UpdateUserOptions): Promise<SandboxUser>;
|
|
3121
|
+
/** Remove a user from the sandbox */
|
|
3122
|
+
remove(userId: string, options?: {
|
|
3123
|
+
preserveHomeDir?: boolean;
|
|
3124
|
+
}): Promise<void>;
|
|
3125
|
+
/** Set access policies for a user */
|
|
3126
|
+
setAccessPolicies(userId: string, rules: AccessPolicyRule[]): Promise<void>;
|
|
3127
|
+
/** Get access policies for a user */
|
|
3128
|
+
getAccessPolicies(userId: string): Promise<AccessPolicyRule[]>;
|
|
3129
|
+
/** Check if a user can perform an action on a path */
|
|
3130
|
+
checkAccess(userId: string, path: string, action: "read" | "write" | "execute"): Promise<boolean>;
|
|
3131
|
+
}
|
|
3132
|
+
/**
|
|
3133
|
+
* Backend manager for runtime agent configuration.
|
|
3134
|
+
* Access via `sandbox.backend`.
|
|
3135
|
+
*/
|
|
3136
|
+
interface BackendManager {
|
|
3137
|
+
/** Get current backend status */
|
|
3138
|
+
status(): Promise<BackendStatus>;
|
|
3139
|
+
/** Get backend capabilities */
|
|
3140
|
+
capabilities(): Promise<BackendCapabilities>;
|
|
3141
|
+
/** Add MCP server at runtime (opencode only) */
|
|
3142
|
+
addMcp(name: string, config: McpServerConfig): Promise<void>;
|
|
3143
|
+
/** Get MCP server status */
|
|
3144
|
+
getMcpStatus(): Promise<Record<string, {
|
|
3145
|
+
status: "running" | "stopped" | "error";
|
|
3146
|
+
error?: string;
|
|
3147
|
+
}>>;
|
|
3148
|
+
/** Update backend configuration */
|
|
3149
|
+
updateConfig(config: Partial<BackendConfig>): Promise<void>;
|
|
3150
|
+
/** Provider account metadata, when exposed by the backend SDK */
|
|
3151
|
+
account(): Promise<BackendAccount>;
|
|
3152
|
+
/** Provider model catalog, when exposed by the backend SDK */
|
|
3153
|
+
models(): Promise<BackendModel[]>;
|
|
3154
|
+
/** Provider repository catalog, when exposed by the backend SDK */
|
|
3155
|
+
repositories(): Promise<BackendRepository[]>;
|
|
3156
|
+
/** Provider-native agent list */
|
|
3157
|
+
agents(options?: BackendListOptions): Promise<BackendListResult<BackendAgent>>;
|
|
3158
|
+
/** Provider-native agent lookup */
|
|
3159
|
+
agent(agentId: string): Promise<BackendAgent>;
|
|
3160
|
+
/** Archive provider-native agent */
|
|
3161
|
+
archiveAgent(agentId: string): Promise<void>;
|
|
3162
|
+
/** Unarchive provider-native agent */
|
|
3163
|
+
unarchiveAgent(agentId: string): Promise<void>;
|
|
3164
|
+
/** Delete provider-native agent */
|
|
3165
|
+
deleteAgent(agentId: string): Promise<void>;
|
|
3166
|
+
/** Provider-native runs for an agent */
|
|
3167
|
+
runs(agentId: string, options?: BackendListOptions): Promise<BackendListResult<BackendRun>>;
|
|
3168
|
+
/** Provider-native run lookup */
|
|
3169
|
+
run(runId: string, options?: {
|
|
3170
|
+
agentId?: string;
|
|
3171
|
+
}): Promise<BackendRun>;
|
|
3172
|
+
/** Provider-native agent messages */
|
|
3173
|
+
agentMessages(agentId: string, options?: BackendListOptions): Promise<unknown>;
|
|
3174
|
+
/** Artifacts for an active backend session */
|
|
3175
|
+
artifacts(sessionId: string): Promise<BackendArtifact[]>;
|
|
3176
|
+
/** Download an artifact from an active backend session */
|
|
3177
|
+
downloadArtifact(sessionId: string, path: string): Promise<Uint8Array>;
|
|
3178
|
+
/**
|
|
3179
|
+
* Validate a provider-neutral profile against the active backend.
|
|
3180
|
+
*
|
|
3181
|
+
* Optional while backends adopt the public `AgentProfile` contract.
|
|
3182
|
+
*/
|
|
3183
|
+
validateProfile?(profile: AgentProfile): Promise<AgentProfileValidationResult>;
|
|
3184
|
+
/** Restart the backend agent */
|
|
3185
|
+
restart(): Promise<void>;
|
|
3186
|
+
}
|
|
3187
|
+
/**
|
|
3188
|
+
* Options for spawning a process.
|
|
3189
|
+
*
|
|
3190
|
+
* @example Basic spawn
|
|
3191
|
+
* ```typescript
|
|
3192
|
+
* const proc = await box.process.spawn("python train.py");
|
|
3193
|
+
* ```
|
|
3194
|
+
*
|
|
3195
|
+
* @example With options
|
|
3196
|
+
* ```typescript
|
|
3197
|
+
* const proc = await box.process.spawn("python train.py", {
|
|
3198
|
+
* cwd: "/workspace/ml",
|
|
3199
|
+
* env: { "CUDA_VISIBLE_DEVICES": "0" },
|
|
3200
|
+
* timeoutMs: 3600000, // 1 hour
|
|
3201
|
+
* });
|
|
3202
|
+
* ```
|
|
3203
|
+
*/
|
|
3204
|
+
interface ProcessSpawnOptions {
|
|
3205
|
+
/** Working directory for the process */
|
|
3206
|
+
cwd?: string;
|
|
3207
|
+
/** Environment variables to set */
|
|
3208
|
+
env?: Record<string, string>;
|
|
3209
|
+
/** Timeout in milliseconds (0 = no timeout) */
|
|
3210
|
+
timeoutMs?: number;
|
|
3211
|
+
}
|
|
3212
|
+
/**
|
|
3213
|
+
* Options for running Python code.
|
|
3214
|
+
*
|
|
3215
|
+
* @example Simple code execution
|
|
3216
|
+
* ```typescript
|
|
3217
|
+
* const result = await box.process.runCode(`
|
|
3218
|
+
* import numpy as np
|
|
3219
|
+
* print(np.random.rand(10))
|
|
3220
|
+
* `);
|
|
3221
|
+
* ```
|
|
3222
|
+
*/
|
|
3223
|
+
interface RunCodeOptions {
|
|
3224
|
+
/** Working directory */
|
|
3225
|
+
cwd?: string;
|
|
3226
|
+
/** Environment variables */
|
|
3227
|
+
env?: Record<string, string>;
|
|
3228
|
+
/** Timeout in milliseconds */
|
|
3229
|
+
timeoutMs?: number;
|
|
3230
|
+
}
|
|
3231
|
+
/**
|
|
3232
|
+
* Status of a spawned process.
|
|
3233
|
+
*/
|
|
3234
|
+
interface ProcessStatus {
|
|
3235
|
+
/** Process ID */
|
|
3236
|
+
pid: number;
|
|
3237
|
+
/** Command that was executed */
|
|
3238
|
+
command: string;
|
|
3239
|
+
/** Working directory */
|
|
3240
|
+
cwd?: string;
|
|
3241
|
+
/** Whether the process is still running */
|
|
3242
|
+
running: boolean;
|
|
3243
|
+
/** Exit code (-1 if still running) */
|
|
3244
|
+
exitCode: number;
|
|
3245
|
+
/** Signal that killed the process (if any) */
|
|
3246
|
+
exitSignal?: string;
|
|
3247
|
+
/** When the process started */
|
|
3248
|
+
startedAt: Date;
|
|
3249
|
+
/** When the process exited (if exited) */
|
|
3250
|
+
exitedAt?: Date;
|
|
3251
|
+
}
|
|
3252
|
+
/**
|
|
3253
|
+
* Full process information including environment.
|
|
3254
|
+
*/
|
|
3255
|
+
interface ProcessInfo extends ProcessStatus {
|
|
3256
|
+
/** Environment variables used */
|
|
3257
|
+
env?: Record<string, string>;
|
|
3258
|
+
}
|
|
3259
|
+
/**
|
|
3260
|
+
* A log entry from process stdout/stderr.
|
|
3261
|
+
*/
|
|
3262
|
+
interface ProcessLogEntry {
|
|
3263
|
+
/** Log source: stdout or stderr */
|
|
3264
|
+
type: "stdout" | "stderr";
|
|
3265
|
+
/** Log content */
|
|
3266
|
+
data: string;
|
|
3267
|
+
/** Timestamp in milliseconds */
|
|
3268
|
+
timestamp: number;
|
|
3269
|
+
}
|
|
3270
|
+
/**
|
|
3271
|
+
* Result of running code or a blocking process.
|
|
3272
|
+
*/
|
|
3273
|
+
interface CodeResult {
|
|
3274
|
+
/** Process ID */
|
|
3275
|
+
pid: number;
|
|
3276
|
+
/** Exit code */
|
|
3277
|
+
exitCode: number;
|
|
3278
|
+
/** Standard output */
|
|
3279
|
+
stdout: string;
|
|
3280
|
+
/** Standard error */
|
|
3281
|
+
stderr: string;
|
|
3282
|
+
/** Execution duration in milliseconds */
|
|
3283
|
+
durationMs: number;
|
|
3284
|
+
}
|
|
3285
|
+
/**
|
|
3286
|
+
* Signal types for killing processes.
|
|
3287
|
+
*/
|
|
3288
|
+
type ProcessSignal = "SIGTERM" | "SIGKILL" | "SIGINT" | "SIGHUP" | "SIGQUIT" | "SIGUSR1" | "SIGUSR2";
|
|
3289
|
+
/**
|
|
3290
|
+
* A handle to a spawned process with control methods.
|
|
3291
|
+
*
|
|
3292
|
+
* @example Non-blocking process with log streaming
|
|
3293
|
+
* ```typescript
|
|
3294
|
+
* const proc = await box.process.spawn("python train.py", {
|
|
3295
|
+
* cwd: "/workspace",
|
|
3296
|
+
* env: { "CUDA_VISIBLE_DEVICES": "0" }
|
|
3297
|
+
* });
|
|
3298
|
+
*
|
|
3299
|
+
* console.log(`Started PID: ${proc.pid}`);
|
|
3300
|
+
*
|
|
3301
|
+
* // Stream logs in real-time
|
|
3302
|
+
* for await (const line of proc.logs()) {
|
|
3303
|
+
* console.log(line);
|
|
3304
|
+
* }
|
|
3305
|
+
*
|
|
3306
|
+
* // Or wait for completion
|
|
3307
|
+
* const exitCode = await proc.wait();
|
|
3308
|
+
* ```
|
|
3309
|
+
*
|
|
3310
|
+
* @example Check status and kill
|
|
3311
|
+
* ```typescript
|
|
3312
|
+
* const status = await proc.status();
|
|
3313
|
+
* if (status.running) {
|
|
3314
|
+
* await proc.kill("SIGKILL");
|
|
3315
|
+
* }
|
|
3316
|
+
* ```
|
|
3317
|
+
*/
|
|
3318
|
+
interface Process {
|
|
3319
|
+
/** Process ID */
|
|
3320
|
+
readonly pid: number;
|
|
3321
|
+
/** Command that was executed */
|
|
3322
|
+
readonly command: string;
|
|
3323
|
+
/**
|
|
3324
|
+
* Get current process status.
|
|
3325
|
+
*/
|
|
3326
|
+
status(): Promise<ProcessStatus>;
|
|
3327
|
+
/**
|
|
3328
|
+
* Wait for the process to exit.
|
|
3329
|
+
* @returns Exit code
|
|
3330
|
+
*/
|
|
3331
|
+
wait(): Promise<number>;
|
|
3332
|
+
/**
|
|
3333
|
+
* Kill the process.
|
|
3334
|
+
* @param signal - Signal to send (default: SIGTERM)
|
|
3335
|
+
*/
|
|
3336
|
+
kill(signal?: ProcessSignal): Promise<void>;
|
|
3337
|
+
/**
|
|
3338
|
+
* Stream stdout/stderr logs in real-time.
|
|
3339
|
+
* Includes buffered logs from process start.
|
|
3340
|
+
*/
|
|
3341
|
+
logs(): AsyncIterable<ProcessLogEntry>;
|
|
3342
|
+
/**
|
|
3343
|
+
* Stream only stdout.
|
|
3344
|
+
*/
|
|
3345
|
+
stdout(): AsyncIterable<string>;
|
|
3346
|
+
/**
|
|
3347
|
+
* Stream only stderr.
|
|
3348
|
+
*/
|
|
3349
|
+
stderr(): AsyncIterable<string>;
|
|
3350
|
+
}
|
|
3351
|
+
/**
|
|
3352
|
+
* Process manager for spawning and controlling processes.
|
|
3353
|
+
* Access via `sandbox.process`.
|
|
3354
|
+
*
|
|
3355
|
+
* Provides non-blocking process execution with real-time log streaming,
|
|
3356
|
+
* ideal for long-running tasks like ML training or dev servers.
|
|
3357
|
+
*
|
|
3358
|
+
* @example Non-blocking process
|
|
3359
|
+
* ```typescript
|
|
3360
|
+
* const proc = await box.process.spawn("python train.py", {
|
|
3361
|
+
* cwd: "/workspace",
|
|
3362
|
+
* env: { "CUDA_VISIBLE_DEVICES": "0" }
|
|
3363
|
+
* });
|
|
3364
|
+
*
|
|
3365
|
+
* // Stream logs
|
|
3366
|
+
* for await (const entry of proc.logs()) {
|
|
3367
|
+
* console.log(`[${entry.type}] ${entry.data}`);
|
|
3368
|
+
* }
|
|
3369
|
+
*
|
|
3370
|
+
* // Check status
|
|
3371
|
+
* const status = await proc.status();
|
|
3372
|
+
* console.log(`Running: ${status.running}`);
|
|
3373
|
+
*
|
|
3374
|
+
* // Kill if needed
|
|
3375
|
+
* await proc.kill();
|
|
3376
|
+
* ```
|
|
3377
|
+
*
|
|
3378
|
+
* @example Run Python code directly
|
|
3379
|
+
* ```typescript
|
|
3380
|
+
* const result = await box.process.runCode(`
|
|
3381
|
+
* import numpy as np
|
|
3382
|
+
* print(np.random.rand(10).mean())
|
|
3383
|
+
* `);
|
|
3384
|
+
* console.log(result.stdout); // Prints the mean
|
|
3385
|
+
* ```
|
|
3386
|
+
*
|
|
3387
|
+
* @example List and manage processes
|
|
3388
|
+
* ```typescript
|
|
3389
|
+
* const procs = await box.process.list();
|
|
3390
|
+
* for (const p of procs) {
|
|
3391
|
+
* console.log(`PID ${p.pid}: ${p.command} (${p.running ? 'running' : 'exited'})`);
|
|
3392
|
+
* }
|
|
3393
|
+
*
|
|
3394
|
+
* // Get specific process
|
|
3395
|
+
* const proc = await box.process.get(1234);
|
|
3396
|
+
* if (proc) {
|
|
3397
|
+
* await proc.kill();
|
|
3398
|
+
* }
|
|
3399
|
+
* ```
|
|
3400
|
+
*/
|
|
3401
|
+
interface ProcessManager {
|
|
3402
|
+
/**
|
|
3403
|
+
* Spawn a process without blocking.
|
|
3404
|
+
* Returns immediately with a Process handle.
|
|
3405
|
+
*
|
|
3406
|
+
* @param command - Shell command to execute
|
|
3407
|
+
* @param options - Spawn options (cwd, env, timeout)
|
|
3408
|
+
* @returns Process handle for control and monitoring
|
|
3409
|
+
*/
|
|
3410
|
+
spawn(command: string, options?: ProcessSpawnOptions): Promise<Process>;
|
|
3411
|
+
/**
|
|
3412
|
+
* Run Python code directly.
|
|
3413
|
+
* Blocks until completion and returns result.
|
|
3414
|
+
*
|
|
3415
|
+
* @param code - Python code to execute
|
|
3416
|
+
* @param options - Execution options
|
|
3417
|
+
* @returns Execution result with stdout/stderr
|
|
3418
|
+
*/
|
|
3419
|
+
runCode(code: string, options?: RunCodeOptions): Promise<CodeResult>;
|
|
3420
|
+
/**
|
|
3421
|
+
* List all tracked processes.
|
|
3422
|
+
*
|
|
3423
|
+
* @returns Array of process status objects
|
|
3424
|
+
*/
|
|
3425
|
+
list(): Promise<ProcessStatus[]>;
|
|
3426
|
+
/**
|
|
3427
|
+
* Get a process by PID.
|
|
3428
|
+
*
|
|
3429
|
+
* @param pid - Process ID
|
|
3430
|
+
* @returns Process handle or null if not found
|
|
3431
|
+
*/
|
|
3432
|
+
get(pid: number): Promise<Process | null>;
|
|
3433
|
+
}
|
|
3434
|
+
/**
|
|
3435
|
+
* Information about a stored secret (without the value).
|
|
3436
|
+
*/
|
|
3437
|
+
interface SecretInfo {
|
|
3438
|
+
/** Secret name (e.g., HF_TOKEN, AWS_ACCESS_KEY) */
|
|
3439
|
+
name: string;
|
|
3440
|
+
/** When the secret was created */
|
|
3441
|
+
createdAt: Date;
|
|
3442
|
+
/** When the secret was last updated */
|
|
3443
|
+
updatedAt: Date;
|
|
3444
|
+
}
|
|
3445
|
+
/**
|
|
3446
|
+
* Secrets manager for storing and retrieving encrypted secrets.
|
|
3447
|
+
* Access via `client.secrets`.
|
|
3448
|
+
*
|
|
3449
|
+
* Secrets are encrypted at rest and can be injected into sandboxes
|
|
3450
|
+
* as environment variables.
|
|
3451
|
+
*
|
|
3452
|
+
* @example Create and manage secrets
|
|
3453
|
+
* ```typescript
|
|
3454
|
+
* // Create a secret
|
|
3455
|
+
* await client.secrets.create("HF_TOKEN", "hf_xxx");
|
|
3456
|
+
*
|
|
3457
|
+
* // List all secrets (names only, not values)
|
|
3458
|
+
* const secrets = await client.secrets.list();
|
|
3459
|
+
* console.log(secrets.map(s => s.name)); // ["HF_TOKEN"]
|
|
3460
|
+
*
|
|
3461
|
+
* // Get a secret value (audited operation)
|
|
3462
|
+
* const value = await client.secrets.get("HF_TOKEN");
|
|
3463
|
+
*
|
|
3464
|
+
* // Update a secret
|
|
3465
|
+
* await client.secrets.update("HF_TOKEN", "hf_new_value");
|
|
3466
|
+
*
|
|
3467
|
+
* // Delete a secret
|
|
3468
|
+
* await client.secrets.delete("HF_TOKEN");
|
|
3469
|
+
* ```
|
|
3470
|
+
*
|
|
3471
|
+
* @example Use secrets in a sandbox
|
|
3472
|
+
* ```typescript
|
|
3473
|
+
* // Create sandbox with secrets injected as env vars
|
|
3474
|
+
* const box = await client.create({
|
|
3475
|
+
* secrets: ["HF_TOKEN", "AWS_ACCESS_KEY"],
|
|
3476
|
+
* });
|
|
3477
|
+
*
|
|
3478
|
+
* // Secrets are available as environment variables
|
|
3479
|
+
* const result = await box.exec("echo $HF_TOKEN");
|
|
3480
|
+
* ```
|
|
3481
|
+
*/
|
|
3482
|
+
interface SecretsManager {
|
|
3483
|
+
/**
|
|
3484
|
+
* Create a new secret.
|
|
3485
|
+
*
|
|
3486
|
+
* @param name - Secret name (uppercase, alphanumeric + underscore, max 63 chars)
|
|
3487
|
+
* @param value - Secret value (max 64KB)
|
|
3488
|
+
* @returns Created secret info
|
|
3489
|
+
* @throws If secret already exists or name is invalid
|
|
3490
|
+
*
|
|
3491
|
+
* @example
|
|
3492
|
+
* ```typescript
|
|
3493
|
+
* await client.secrets.create("HF_TOKEN", "hf_xxx");
|
|
3494
|
+
* await client.secrets.create("AWS_ACCESS_KEY", "AKIA...");
|
|
3495
|
+
* ```
|
|
3496
|
+
*/
|
|
3497
|
+
create(name: string, value: string): Promise<SecretInfo>;
|
|
3498
|
+
/**
|
|
3499
|
+
* List all secrets (names and metadata only, not values).
|
|
3500
|
+
*
|
|
3501
|
+
* @returns Array of secret info objects
|
|
3502
|
+
*
|
|
3503
|
+
* @example
|
|
3504
|
+
* ```typescript
|
|
3505
|
+
* const secrets = await client.secrets.list();
|
|
3506
|
+
* for (const s of secrets) {
|
|
3507
|
+
* console.log(`${s.name} - created ${s.createdAt}`);
|
|
3508
|
+
* }
|
|
3509
|
+
* ```
|
|
3510
|
+
*/
|
|
3511
|
+
list(): Promise<SecretInfo[]>;
|
|
3512
|
+
/**
|
|
3513
|
+
* Get a secret's decrypted value.
|
|
3514
|
+
*
|
|
3515
|
+
* This is an audited operation - access is logged.
|
|
3516
|
+
*
|
|
3517
|
+
* @param name - Secret name
|
|
3518
|
+
* @returns Secret value
|
|
3519
|
+
* @throws If secret not found
|
|
3520
|
+
*
|
|
3521
|
+
* @example
|
|
3522
|
+
* ```typescript
|
|
3523
|
+
* const token = await client.secrets.get("HF_TOKEN");
|
|
3524
|
+
* ```
|
|
3525
|
+
*/
|
|
3526
|
+
get(name: string): Promise<string>;
|
|
3527
|
+
/**
|
|
3528
|
+
* Update an existing secret's value.
|
|
3529
|
+
*
|
|
3530
|
+
* @param name - Secret name
|
|
3531
|
+
* @param value - New secret value
|
|
3532
|
+
* @returns Updated secret info
|
|
3533
|
+
* @throws If secret not found
|
|
3534
|
+
*
|
|
3535
|
+
* @example
|
|
3536
|
+
* ```typescript
|
|
3537
|
+
* await client.secrets.update("HF_TOKEN", "hf_new_value");
|
|
3538
|
+
* ```
|
|
3539
|
+
*/
|
|
3540
|
+
update(name: string, value: string): Promise<SecretInfo>;
|
|
3541
|
+
/**
|
|
3542
|
+
* Delete a secret.
|
|
3543
|
+
*
|
|
3544
|
+
* @param name - Secret name
|
|
3545
|
+
* @throws If secret not found
|
|
3546
|
+
*
|
|
3547
|
+
* @example
|
|
3548
|
+
* ```typescript
|
|
3549
|
+
* await client.secrets.delete("HF_TOKEN");
|
|
3550
|
+
* ```
|
|
3551
|
+
*/
|
|
3552
|
+
delete(name: string): Promise<void>;
|
|
3553
|
+
}
|
|
3554
|
+
/**
|
|
3555
|
+
* Detailed file/directory information.
|
|
3556
|
+
*/
|
|
3557
|
+
interface FileInfo {
|
|
3558
|
+
/** File/directory name */
|
|
3559
|
+
name: string;
|
|
3560
|
+
/** Full path relative to workspace */
|
|
3561
|
+
path: string;
|
|
3562
|
+
/** Size in bytes */
|
|
3563
|
+
size: number;
|
|
3564
|
+
/** Whether this is a directory */
|
|
3565
|
+
isDir: boolean;
|
|
3566
|
+
/** Whether this is a regular file */
|
|
3567
|
+
isFile: boolean;
|
|
3568
|
+
/** Whether this is a symbolic link */
|
|
3569
|
+
isSymlink: boolean;
|
|
3570
|
+
/** Unix permissions (e.g., 0o755) */
|
|
3571
|
+
permissions: number;
|
|
3572
|
+
/** Owner user ID/name */
|
|
3573
|
+
owner: string;
|
|
3574
|
+
/** Group ID/name */
|
|
3575
|
+
group: string;
|
|
3576
|
+
/** Last modification time */
|
|
3577
|
+
modTime: Date;
|
|
3578
|
+
/** Last access time */
|
|
3579
|
+
accessTime: Date;
|
|
3580
|
+
}
|
|
3581
|
+
/**
|
|
3582
|
+
* Options for uploading files.
|
|
3583
|
+
*/
|
|
3584
|
+
interface UploadOptions {
|
|
3585
|
+
/** Overwrite if file exists (default: true) */
|
|
3586
|
+
overwrite?: boolean;
|
|
3587
|
+
/** Set file permissions (Unix mode, e.g., 0o644) */
|
|
3588
|
+
permissions?: number;
|
|
3589
|
+
/** Progress callback for large files */
|
|
3590
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
3591
|
+
}
|
|
3592
|
+
/**
|
|
3593
|
+
* Upload progress information.
|
|
3594
|
+
*/
|
|
3595
|
+
interface UploadProgress {
|
|
3596
|
+
/** Bytes uploaded so far */
|
|
3597
|
+
bytesUploaded: number;
|
|
3598
|
+
/** Total bytes to upload */
|
|
3599
|
+
totalBytes: number;
|
|
3600
|
+
/** Percentage complete (0-100) */
|
|
3601
|
+
percentage: number;
|
|
3602
|
+
}
|
|
3603
|
+
/**
|
|
3604
|
+
* Options for downloading files.
|
|
3605
|
+
*/
|
|
3606
|
+
interface DownloadOptions {
|
|
3607
|
+
/** Overwrite local file if exists (default: true) */
|
|
3608
|
+
overwrite?: boolean;
|
|
3609
|
+
/** Progress callback for large files */
|
|
3610
|
+
onProgress?: (progress: DownloadProgress) => void;
|
|
3611
|
+
}
|
|
3612
|
+
/**
|
|
3613
|
+
* Download progress information.
|
|
3614
|
+
*/
|
|
3615
|
+
interface DownloadProgress {
|
|
3616
|
+
/** Bytes downloaded so far */
|
|
3617
|
+
bytesDownloaded: number;
|
|
3618
|
+
/** Total bytes to download */
|
|
3619
|
+
totalBytes: number;
|
|
3620
|
+
/** Percentage complete (0-100) */
|
|
3621
|
+
percentage: number;
|
|
3622
|
+
}
|
|
3623
|
+
/**
|
|
3624
|
+
* Options for listing directories.
|
|
3625
|
+
*/
|
|
3626
|
+
interface ListOptions {
|
|
3627
|
+
/** Include hidden files (starting with .) */
|
|
3628
|
+
all?: boolean;
|
|
3629
|
+
/** Include full metadata (like ls -l) */
|
|
3630
|
+
long?: boolean;
|
|
3631
|
+
}
|
|
3632
|
+
/**
|
|
3633
|
+
* Options for creating directories.
|
|
3634
|
+
*/
|
|
3635
|
+
interface MkdirOptions {
|
|
3636
|
+
/** Create parent directories as needed (like mkdir -p) */
|
|
3637
|
+
recursive?: boolean;
|
|
3638
|
+
/** Set directory permissions (Unix mode, e.g., 0o755) */
|
|
3639
|
+
mode?: number;
|
|
3640
|
+
}
|
|
3641
|
+
/**
|
|
3642
|
+
* Options for deleting files/directories.
|
|
3643
|
+
*/
|
|
3644
|
+
interface DeleteOptions {
|
|
3645
|
+
/** Recursively delete directories (like rm -rf) */
|
|
3646
|
+
recursive?: boolean;
|
|
3647
|
+
}
|
|
3648
|
+
/**
|
|
3649
|
+
* File system operations for sandboxes. Access via `sandbox.fs`.
|
|
3650
|
+
*
|
|
3651
|
+
* Beyond basic read/write: binary upload/download, directory operations,
|
|
3652
|
+
* progress reporting for large files.
|
|
3653
|
+
*
|
|
3654
|
+
* @example Upload and download files
|
|
3655
|
+
* ```typescript
|
|
3656
|
+
* // Upload a local file
|
|
3657
|
+
* await box.fs.upload("./model.bin", "/workspace/models/model.bin");
|
|
3658
|
+
*
|
|
3659
|
+
* // Download a file
|
|
3660
|
+
* await box.fs.download("/workspace/results.zip", "./local/results.zip");
|
|
3661
|
+
*
|
|
3662
|
+
* // With progress reporting
|
|
3663
|
+
* await box.fs.upload("./large-file.bin", "/workspace/data.bin", {
|
|
3664
|
+
* onProgress: (p) => console.log(`${p.percentage}%`),
|
|
3665
|
+
* });
|
|
3666
|
+
* ```
|
|
3667
|
+
*
|
|
3668
|
+
* @example Directory operations
|
|
3669
|
+
* ```typescript
|
|
3670
|
+
* // Upload entire directory
|
|
3671
|
+
* await box.fs.uploadDir("./local/project", "/workspace/project");
|
|
3672
|
+
*
|
|
3673
|
+
* // Download entire directory
|
|
3674
|
+
* await box.fs.downloadDir("/workspace/output", "./local/output");
|
|
3675
|
+
*
|
|
3676
|
+
* // List directory contents
|
|
3677
|
+
* const files = await box.fs.list("/workspace");
|
|
3678
|
+
* for (const f of files) {
|
|
3679
|
+
* console.log(`${f.name} - ${f.size} bytes`);
|
|
3680
|
+
* }
|
|
3681
|
+
* ```
|
|
3682
|
+
*
|
|
3683
|
+
* @example File management
|
|
3684
|
+
* ```typescript
|
|
3685
|
+
* // Check if file exists
|
|
3686
|
+
* if (await box.fs.exists("/workspace/config.json")) {
|
|
3687
|
+
* const info = await box.fs.stat("/workspace/config.json");
|
|
3688
|
+
* console.log(`Size: ${info.size}, Modified: ${info.modTime}`);
|
|
3689
|
+
* }
|
|
3690
|
+
*
|
|
3691
|
+
* // Create directory
|
|
3692
|
+
* await box.fs.mkdir("/workspace/output/images", { recursive: true });
|
|
3693
|
+
*
|
|
3694
|
+
* // Delete file or directory
|
|
3695
|
+
* await box.fs.delete("/workspace/temp", { recursive: true });
|
|
3696
|
+
* ```
|
|
3697
|
+
*/
|
|
3698
|
+
interface FileSystem {
|
|
3699
|
+
/**
|
|
3700
|
+
* Read a file's contents as a string.
|
|
3701
|
+
* For binary files, use download() instead.
|
|
3702
|
+
*
|
|
3703
|
+
* @param path - Path to file (relative to workspace)
|
|
3704
|
+
* @returns File contents as UTF-8 string
|
|
3705
|
+
* @throws NotFoundError if file doesn't exist
|
|
3706
|
+
*/
|
|
3707
|
+
read(path: string): Promise<string>;
|
|
3708
|
+
/**
|
|
3709
|
+
* Write string content to a file.
|
|
3710
|
+
* For binary files, use upload() instead.
|
|
3711
|
+
* Creates parent directories as needed.
|
|
3712
|
+
*
|
|
3713
|
+
* @param path - Path to file (relative to workspace)
|
|
3714
|
+
* @param content - Content to write
|
|
3715
|
+
*/
|
|
3716
|
+
write(path: string, content: string): Promise<void>;
|
|
3717
|
+
/**
|
|
3718
|
+
* Search for text patterns in files using ripgrep.
|
|
3719
|
+
* @see SearchOptions for available options
|
|
3720
|
+
*/
|
|
3721
|
+
search(query: string, options?: SearchOptions): AsyncIterable<SearchMatch>;
|
|
3722
|
+
/**
|
|
3723
|
+
* Upload a local file to the sandbox.
|
|
3724
|
+
* Handles binary files correctly using multipart upload.
|
|
3725
|
+
* Creates parent directories as needed.
|
|
3726
|
+
*
|
|
3727
|
+
* @param localPath - Path to local file
|
|
3728
|
+
* @param remotePath - Destination path in sandbox
|
|
3729
|
+
* @param options - Upload options (overwrite, permissions, progress)
|
|
3730
|
+
* @throws Error if local file doesn't exist
|
|
3731
|
+
*
|
|
3732
|
+
* @example
|
|
3733
|
+
* ```typescript
|
|
3734
|
+
* await box.fs.upload("./model.bin", "/workspace/models/model.bin");
|
|
3735
|
+
*
|
|
3736
|
+
* // With progress
|
|
3737
|
+
* await box.fs.upload("./large-file.bin", "/data/file.bin", {
|
|
3738
|
+
* onProgress: (p) => console.log(`${p.percentage.toFixed(1)}%`),
|
|
3739
|
+
* });
|
|
3740
|
+
* ```
|
|
3741
|
+
*/
|
|
3742
|
+
upload(localPath: string, remotePath: string, options?: UploadOptions): Promise<void>;
|
|
3743
|
+
/**
|
|
3744
|
+
* Download a file from the sandbox.
|
|
3745
|
+
* Handles binary files correctly.
|
|
3746
|
+
* Creates local parent directories as needed.
|
|
3747
|
+
*
|
|
3748
|
+
* @param remotePath - Path to file in sandbox
|
|
3749
|
+
* @param localPath - Local destination path
|
|
3750
|
+
* @param options - Download options (overwrite, progress)
|
|
3751
|
+
* @throws NotFoundError if remote file doesn't exist
|
|
3752
|
+
*
|
|
3753
|
+
* @example
|
|
3754
|
+
* ```typescript
|
|
3755
|
+
* await box.fs.download("/workspace/output.zip", "./results.zip");
|
|
3756
|
+
* ```
|
|
3757
|
+
*/
|
|
3758
|
+
download(remotePath: string, localPath: string, options?: DownloadOptions): Promise<void>;
|
|
3759
|
+
/**
|
|
3760
|
+
* Upload a local directory to the sandbox.
|
|
3761
|
+
* Uses tar for efficient transfer.
|
|
3762
|
+
* Preserves directory structure and file permissions.
|
|
3763
|
+
*
|
|
3764
|
+
* @param localDir - Path to local directory
|
|
3765
|
+
* @param remoteDir - Destination directory in sandbox
|
|
3766
|
+
* @throws Error if local directory doesn't exist
|
|
3767
|
+
*
|
|
3768
|
+
* @example
|
|
3769
|
+
* ```typescript
|
|
3770
|
+
* await box.fs.uploadDir("./project", "/workspace/project");
|
|
3771
|
+
* ```
|
|
3772
|
+
*/
|
|
3773
|
+
uploadDir(localDir: string, remoteDir: string): Promise<void>;
|
|
3774
|
+
/**
|
|
3775
|
+
* Download a directory from the sandbox.
|
|
3776
|
+
* Uses tar for efficient transfer.
|
|
3777
|
+
* Preserves directory structure and file permissions.
|
|
3778
|
+
*
|
|
3779
|
+
* @param remoteDir - Directory path in sandbox
|
|
3780
|
+
* @param localDir - Local destination directory
|
|
3781
|
+
* @throws NotFoundError if remote directory doesn't exist
|
|
3782
|
+
*
|
|
3783
|
+
* @example
|
|
3784
|
+
* ```typescript
|
|
3785
|
+
* await box.fs.downloadDir("/workspace/output", "./local-output");
|
|
3786
|
+
* ```
|
|
3787
|
+
*/
|
|
3788
|
+
downloadDir(remoteDir: string, localDir: string): Promise<void>;
|
|
3789
|
+
/**
|
|
3790
|
+
* List directory contents with metadata.
|
|
3791
|
+
*
|
|
3792
|
+
* @param path - Directory path (relative to workspace)
|
|
3793
|
+
* @param options - List options (all, long)
|
|
3794
|
+
* @returns Array of file/directory info
|
|
3795
|
+
* @throws NotFoundError if directory doesn't exist
|
|
3796
|
+
*
|
|
3797
|
+
* @example
|
|
3798
|
+
* ```typescript
|
|
3799
|
+
* const entries = await box.fs.list("/workspace", { all: true });
|
|
3800
|
+
* for (const e of entries) {
|
|
3801
|
+
* const type = e.isDir ? "DIR" : "FILE";
|
|
3802
|
+
* console.log(`[${type}] ${e.name} (${e.size} bytes)`);
|
|
3803
|
+
* }
|
|
3804
|
+
* ```
|
|
3805
|
+
*/
|
|
3806
|
+
list(path: string, options?: ListOptions): Promise<FileInfo[]>;
|
|
3807
|
+
/**
|
|
3808
|
+
* Get detailed information about a file or directory.
|
|
3809
|
+
*
|
|
3810
|
+
* @param path - Path to file/directory
|
|
3811
|
+
* @returns File/directory metadata
|
|
3812
|
+
* @throws NotFoundError if path doesn't exist
|
|
3813
|
+
*
|
|
3814
|
+
* @example
|
|
3815
|
+
* ```typescript
|
|
3816
|
+
* const info = await box.fs.stat("/workspace/model.bin");
|
|
3817
|
+
* console.log(`Size: ${info.size}, Modified: ${info.modTime}`);
|
|
3818
|
+
* ```
|
|
3819
|
+
*/
|
|
3820
|
+
stat(path: string): Promise<FileInfo>;
|
|
3821
|
+
/**
|
|
3822
|
+
* Delete a file or directory.
|
|
3823
|
+
*
|
|
3824
|
+
* @param path - Path to delete
|
|
3825
|
+
* @param options - Delete options (recursive for directories)
|
|
3826
|
+
* @throws NotFoundError if path doesn't exist
|
|
3827
|
+
* @throws Error if deleting non-empty directory without recursive
|
|
3828
|
+
*
|
|
3829
|
+
* @example
|
|
3830
|
+
* ```typescript
|
|
3831
|
+
* // Delete file
|
|
3832
|
+
* await box.fs.delete("/workspace/temp.txt");
|
|
3833
|
+
*
|
|
3834
|
+
* // Delete directory recursively
|
|
3835
|
+
* await box.fs.delete("/workspace/cache", { recursive: true });
|
|
3836
|
+
* ```
|
|
3837
|
+
*/
|
|
3838
|
+
delete(path: string, options?: DeleteOptions): Promise<void>;
|
|
3839
|
+
/**
|
|
3840
|
+
* Create a directory.
|
|
3841
|
+
*
|
|
3842
|
+
* @param path - Directory path to create
|
|
3843
|
+
* @param options - Options (recursive to create parents)
|
|
3844
|
+
*
|
|
3845
|
+
* @example
|
|
3846
|
+
* ```typescript
|
|
3847
|
+
* // Create with parents
|
|
3848
|
+
* await box.fs.mkdir("/workspace/output/images", { recursive: true });
|
|
3849
|
+
* ```
|
|
3850
|
+
*/
|
|
3851
|
+
mkdir(path: string, options?: MkdirOptions): Promise<void>;
|
|
3852
|
+
/**
|
|
3853
|
+
* Check if a path exists.
|
|
3854
|
+
*
|
|
3855
|
+
* @param path - Path to check
|
|
3856
|
+
* @returns true if path exists, false otherwise
|
|
3857
|
+
*
|
|
3858
|
+
* @example
|
|
3859
|
+
* ```typescript
|
|
3860
|
+
* if (await box.fs.exists("/workspace/config.json")) {
|
|
3861
|
+
* // File exists
|
|
3862
|
+
* }
|
|
3863
|
+
* ```
|
|
3864
|
+
*/
|
|
3865
|
+
exists(path: string): Promise<boolean>;
|
|
3866
|
+
}
|
|
3867
|
+
//#endregion
|
|
3868
|
+
//#region src/session.d.ts
|
|
3869
|
+
/**
|
|
3870
|
+
* A single agent session inside a sandbox. Created via
|
|
3871
|
+
* `box.session(id)` — does not hit the network until a method is called.
|
|
3872
|
+
*/
|
|
3873
|
+
declare class SandboxSession {
|
|
3874
|
+
private readonly box;
|
|
3875
|
+
/** Stable session id assigned by the sandbox runtime. */
|
|
3876
|
+
readonly id: string;
|
|
3877
|
+
/**
|
|
3878
|
+
* @internal SDK-internal constructor — apps should call `box.session(id)`.
|
|
3879
|
+
*/
|
|
3880
|
+
constructor(box: SandboxInstance, /** Stable session id assigned by the sandbox runtime. */
|
|
3881
|
+
|
|
3882
|
+
id: string);
|
|
3883
|
+
/**
|
|
3884
|
+
* Fetch the current session state from the sandbox. Includes status,
|
|
3885
|
+
* model, prompt count, token usage if known, and timing metadata.
|
|
3886
|
+
*
|
|
3887
|
+
* Throws on transport error; returns `null` if the session id is not
|
|
3888
|
+
* known to the sandbox (e.g. it ended and was reaped, or the id is
|
|
3889
|
+
* invalid).
|
|
3890
|
+
*/
|
|
3891
|
+
status(): Promise<SessionInfo | null>;
|
|
3892
|
+
/**
|
|
3893
|
+
* Stream events from this session as they arrive. With no `since`,
|
|
3894
|
+
* starts at the live tail; with `since`, replays from that event id
|
|
3895
|
+
* forward — useful for reconnect-after-disconnect flows.
|
|
3896
|
+
*
|
|
3897
|
+
* The async iterator terminates when the session reaches a terminal
|
|
3898
|
+
* state (`completed`, `failed`, `cancelled`) and the corresponding
|
|
3899
|
+
* terminal event has been yielded, OR when the caller's signal aborts.
|
|
3900
|
+
*/
|
|
3901
|
+
events(opts?: SessionEventStreamOptions): AsyncGenerator<SandboxEvent>;
|
|
3902
|
+
/**
|
|
3903
|
+
* Await the session's terminal result. Polls status + drains events
|
|
3904
|
+
* until the session reaches a terminal state, then returns the
|
|
3905
|
+
* aggregated `PromptResult`.
|
|
3906
|
+
*
|
|
3907
|
+
* Use this to wait for a session that was started by another caller
|
|
3908
|
+
* (e.g. `dispatchPrompt`).
|
|
3909
|
+
*/
|
|
3910
|
+
result(): Promise<PromptResult>;
|
|
3911
|
+
/**
|
|
3912
|
+
* Continue this session with an additional prompt. Equivalent to
|
|
3913
|
+
* `box.prompt(message, { ...opts, sessionId: this.id })` but reads
|
|
3914
|
+
* naturally on a Session reference.
|
|
3915
|
+
*/
|
|
3916
|
+
prompt(message: string | PromptInputPart[], opts?: PromptOptions): Promise<PromptResult>;
|
|
3917
|
+
/**
|
|
3918
|
+
* Cancel the session. Best-effort: an in-flight LLM call may still
|
|
3919
|
+
* complete one more token before the abort takes effect. Idempotent —
|
|
3920
|
+
* cancelling a completed session is a no-op.
|
|
3921
|
+
*/
|
|
3922
|
+
cancel(): Promise<void>;
|
|
3923
|
+
}
|
|
3924
|
+
//#endregion
|
|
3925
|
+
//#region src/trace-exporter.d.ts
|
|
3926
|
+
type JsonObject = {
|
|
3927
|
+
[key: string]: JsonValue;
|
|
3928
|
+
};
|
|
3929
|
+
type TraceExportFormat = "tangle" | "otel-json";
|
|
3930
|
+
type TraceExportBundle = SandboxTraceBundle | SandboxFleetTraceBundle;
|
|
3931
|
+
interface TraceExportSink {
|
|
3932
|
+
url: string;
|
|
3933
|
+
headers?: Record<string, string>;
|
|
3934
|
+
format?: TraceExportFormat;
|
|
3935
|
+
serviceName?: string;
|
|
3936
|
+
timeoutMs?: number;
|
|
3937
|
+
fetch?: typeof fetch;
|
|
3938
|
+
}
|
|
3939
|
+
interface TraceExportResult {
|
|
3940
|
+
status: number;
|
|
3941
|
+
ok: boolean;
|
|
3942
|
+
body: string;
|
|
3943
|
+
}
|
|
3944
|
+
declare function buildTraceExportPayload(bundle: TraceExportBundle, format?: TraceExportFormat, serviceName?: string): TraceExportBundle | JsonObject;
|
|
3945
|
+
declare function exportTraceBundle(bundle: TraceExportBundle, sink: TraceExportSink): Promise<TraceExportResult>;
|
|
3946
|
+
declare function toOtelJson(bundle: TraceExportBundle, serviceName?: string): JsonObject;
|
|
3947
|
+
declare function otelTraceIdForTangleTrace(traceId: string): string;
|
|
3948
|
+
//#endregion
|
|
3949
|
+
//#region src/sandbox.d.ts
|
|
3950
|
+
/**
|
|
3951
|
+
* HTTP client interface for making requests.
|
|
3952
|
+
*/
|
|
3953
|
+
interface HttpClient {
|
|
3954
|
+
fetch(path: string, options?: RequestInit): Promise<Response>;
|
|
3955
|
+
getApiKey?(): string | undefined;
|
|
3956
|
+
}
|
|
3957
|
+
/**
|
|
3958
|
+
* Git capability for repository operations.
|
|
3959
|
+
*/
|
|
3960
|
+
interface GitCapability {
|
|
3961
|
+
/** Get repository status */
|
|
3962
|
+
status(): Promise<GitStatus>;
|
|
3963
|
+
/** Get commit log */
|
|
3964
|
+
log(limit?: number): Promise<GitCommit[]>;
|
|
3965
|
+
/** Get diff (optionally against a ref) */
|
|
3966
|
+
diff(ref?: string): Promise<GitDiff>;
|
|
3967
|
+
/** Stage files */
|
|
3968
|
+
add(paths: string[]): Promise<void>;
|
|
3969
|
+
/** Create a commit */
|
|
3970
|
+
commit(message: string, options?: {
|
|
3971
|
+
amend?: boolean;
|
|
3972
|
+
}): Promise<GitCommit>;
|
|
3973
|
+
/** Push to remote */
|
|
3974
|
+
push(options?: {
|
|
3975
|
+
force?: boolean;
|
|
3976
|
+
}): Promise<void>;
|
|
3977
|
+
/** Pull from remote */
|
|
3978
|
+
pull(options?: {
|
|
3979
|
+
rebase?: boolean;
|
|
3980
|
+
}): Promise<void>;
|
|
3981
|
+
/** List branches */
|
|
3982
|
+
branches(): Promise<GitBranch[]>;
|
|
3983
|
+
/** Checkout a branch or ref */
|
|
3984
|
+
checkout(ref: string, options?: {
|
|
3985
|
+
create?: boolean;
|
|
3986
|
+
}): Promise<void>;
|
|
3987
|
+
}
|
|
3988
|
+
/**
|
|
3989
|
+
* Tools capability for managing language runtimes via mise.
|
|
3990
|
+
*/
|
|
3991
|
+
interface ToolsCapability {
|
|
3992
|
+
/** Install a tool version */
|
|
3993
|
+
install(tool: string, version: string): Promise<void>;
|
|
3994
|
+
/** Activate a tool version for the session */
|
|
3995
|
+
use(tool: string, version: string): Promise<void>;
|
|
3996
|
+
/** List installed tools */
|
|
3997
|
+
list(): Promise<InstalledTool[]>;
|
|
3998
|
+
/** Run a command with a specific tool */
|
|
3999
|
+
run(tool: string, args: string[]): Promise<ExecResult>;
|
|
4000
|
+
}
|
|
4001
|
+
/**
|
|
4002
|
+
* A sandbox instance with methods for interaction.
|
|
4003
|
+
*/
|
|
4004
|
+
declare class SandboxInstance {
|
|
4005
|
+
private readonly client;
|
|
4006
|
+
private info;
|
|
4007
|
+
private readonly defaultRuntimeBackend?;
|
|
4008
|
+
constructor(client: HttpClient, info: SandboxInfo, defaultRuntimeBackend?: BackendConfig);
|
|
4009
|
+
/** Unique sandbox identifier */
|
|
4010
|
+
get id(): string;
|
|
4011
|
+
/** Human-readable name */
|
|
4012
|
+
get name(): string | undefined;
|
|
4013
|
+
/** Current status */
|
|
4014
|
+
get status(): SandboxStatus;
|
|
4015
|
+
/** Connection information */
|
|
4016
|
+
get connection(): SandboxConnection | undefined;
|
|
4017
|
+
/** Custom metadata */
|
|
4018
|
+
get metadata(): Record<string, unknown> | undefined;
|
|
4019
|
+
/** When the sandbox was created */
|
|
4020
|
+
get createdAt(): Date;
|
|
4021
|
+
/** When the sandbox started running */
|
|
4022
|
+
get startedAt(): Date | undefined;
|
|
4023
|
+
/** Last activity timestamp */
|
|
4024
|
+
get lastActivityAt(): Date | undefined;
|
|
4025
|
+
/** When the sandbox will expire */
|
|
4026
|
+
get expiresAt(): Date | undefined;
|
|
4027
|
+
/** Error message if status is 'failed' */
|
|
4028
|
+
get error(): string | undefined;
|
|
4029
|
+
/** Web terminal URL for browser-based access */
|
|
4030
|
+
get url(): string | undefined;
|
|
4031
|
+
/**
|
|
4032
|
+
* Serialize to the public sandbox shape for logs and structured
|
|
4033
|
+
* output. Secrets in `connection` (currently `authToken`) are
|
|
4034
|
+
* redacted so that `JSON.stringify(box)` is safe to ship to log
|
|
4035
|
+
* sinks. Use {@link toDebugJSON} when the bearer is required (e.g.
|
|
4036
|
+
* one-off CLI commands that print credentials to the user).
|
|
4037
|
+
*/
|
|
4038
|
+
toJSON(): SandboxInfo;
|
|
4039
|
+
/**
|
|
4040
|
+
* Serialize the sandbox **including secrets** when `includeSecrets`
|
|
4041
|
+
* is true. The default behavior matches {@link toJSON} and redacts
|
|
4042
|
+
* `connection.authToken`.
|
|
4043
|
+
*
|
|
4044
|
+
* Use only when the caller has an explicit need for the bearer
|
|
4045
|
+
* (e.g. presenting it once to the human operator). Never wire the
|
|
4046
|
+
* result of `toDebugJSON({ includeSecrets: true })` into a structured
|
|
4047
|
+
* logger — the bearer will land in any log sink consuming that output.
|
|
4048
|
+
*/
|
|
4049
|
+
toDebugJSON(options?: {
|
|
4050
|
+
includeSecrets?: boolean;
|
|
4051
|
+
}): SandboxInfo;
|
|
4052
|
+
/**
|
|
4053
|
+
* Create an advanced direct-runtime view of this sandbox.
|
|
4054
|
+
*
|
|
4055
|
+
* Runtime methods on the returned instance talk to the sandbox runtime
|
|
4056
|
+
* directly using `connection.runtimeUrl` and `connection.authToken`.
|
|
4057
|
+
* Lifecycle methods still go through the parent SDK client.
|
|
4058
|
+
*/
|
|
4059
|
+
direct(): SandboxInstance;
|
|
4060
|
+
/**
|
|
4061
|
+
* Get an MCP endpoint for this sandbox. Returns a paste-able config
|
|
4062
|
+
* for any MCP-capable host (Claude Desktop, Cursor, claude-code,
|
|
4063
|
+
* codex, opencode, …) plus a freshly-minted, capability-scoped JWT.
|
|
4064
|
+
*
|
|
4065
|
+
* The token is short-lived and limited to the requested capabilities
|
|
4066
|
+
* — it cannot be used against admin endpoints (`/exec`, `/files`,
|
|
4067
|
+
* etc.) on the sandbox. Call `getMcpEndpoint()` again to rotate.
|
|
4068
|
+
*
|
|
4069
|
+
* Requires the sandbox to have been created with `capabilities`
|
|
4070
|
+
* including the requested capability (default: `computer_use`).
|
|
4071
|
+
*
|
|
4072
|
+
* @example
|
|
4073
|
+
* ```typescript
|
|
4074
|
+
* const ep = await box.getMcpEndpoint();
|
|
4075
|
+
* // Save ep.config to your IDE's mcp.json — that's it.
|
|
4076
|
+
* fs.writeFileSync("mcp.json", JSON.stringify(ep.config, null, 2));
|
|
4077
|
+
* ```
|
|
4078
|
+
*/
|
|
4079
|
+
getMcpEndpoint(options?: {
|
|
4080
|
+
capabilities?: ReadonlyArray<"computer_use">; /** Override server entry name (default: "tangle-sandbox"). */
|
|
4081
|
+
serverName?: string; /** Token TTL in minutes (server clamps to its policy). */
|
|
4082
|
+
ttlMinutes?: number;
|
|
4083
|
+
}): Promise<SandboxMcpEndpoint>;
|
|
4084
|
+
/**
|
|
4085
|
+
* Refresh sandbox information from the server.
|
|
4086
|
+
*/
|
|
4087
|
+
refresh(): Promise<void>;
|
|
4088
|
+
/**
|
|
4089
|
+
* Fetch fresh TEE attestation evidence for this sandbox.
|
|
4090
|
+
*
|
|
4091
|
+
* When `attestationNonce` is supplied, the runtime must return evidence bound
|
|
4092
|
+
* to that challenge or fail closed if the selected TEE backend cannot support
|
|
4093
|
+
* nonce-bound report data.
|
|
4094
|
+
*/
|
|
4095
|
+
getTeeAttestation(options?: TeeAttestationOptions): Promise<TeeAttestationResponse>;
|
|
4096
|
+
/**
|
|
4097
|
+
* Fetch the TEE-bound public key used for sealed-secret encryption.
|
|
4098
|
+
*
|
|
4099
|
+
* The returned key includes an attestation report. Verify that report before
|
|
4100
|
+
* encrypting secrets to the key.
|
|
4101
|
+
*/
|
|
4102
|
+
getTeePublicKey(): Promise<TeePublicKeyResponse>;
|
|
4103
|
+
/**
|
|
4104
|
+
* Bootstrap a real-time collaboration session for a file.
|
|
4105
|
+
* Returns the WebSocket URL and auth token needed to connect a
|
|
4106
|
+
* Hocuspocus/Yjs provider for live multi-user editing.
|
|
4107
|
+
*
|
|
4108
|
+
* @example
|
|
4109
|
+
* ```typescript
|
|
4110
|
+
* const collab = await box.collaborate("src/index.ts")
|
|
4111
|
+
* // Use collab.transport.websocketUrl + collab.transport.token
|
|
4112
|
+
* // with @hocuspocus/provider to connect
|
|
4113
|
+
* ```
|
|
4114
|
+
*/
|
|
4115
|
+
collaborate(path: string, options?: {
|
|
4116
|
+
access?: "read" | "write";
|
|
4117
|
+
}): Promise<{
|
|
4118
|
+
documentId: string;
|
|
4119
|
+
transport: {
|
|
4120
|
+
websocketUrl: string;
|
|
4121
|
+
token: string;
|
|
4122
|
+
expiresAt: number;
|
|
4123
|
+
};
|
|
4124
|
+
permissions: {
|
|
4125
|
+
access: "read" | "write";
|
|
4126
|
+
canSnapshot: boolean;
|
|
4127
|
+
};
|
|
4128
|
+
}>;
|
|
4129
|
+
/**
|
|
4130
|
+
* Refresh a collaboration token for an existing document session.
|
|
4131
|
+
*/
|
|
4132
|
+
/**
|
|
4133
|
+
* Refresh a collaboration token. Access level is preserved from the original
|
|
4134
|
+
* token — cannot be escalated (read stays read, write stays write).
|
|
4135
|
+
*/
|
|
4136
|
+
refreshCollaborationToken(documentId: string, currentToken: string): Promise<{
|
|
4137
|
+
token: string;
|
|
4138
|
+
expiresAt: number;
|
|
4139
|
+
access: "read" | "write";
|
|
4140
|
+
}>;
|
|
4141
|
+
/**
|
|
4142
|
+
* Get SSH credentials for connecting to the sandbox.
|
|
4143
|
+
* Throws if SSH is not enabled or sandbox is not running.
|
|
4144
|
+
*/
|
|
4145
|
+
ssh(): Promise<SSHCredentials>;
|
|
4146
|
+
sshCommand(): Promise<SSHCommandDescriptor>;
|
|
4147
|
+
/**
|
|
4148
|
+
* Execute a command in the sandbox.
|
|
4149
|
+
*/
|
|
4150
|
+
exec(command: string, options?: ExecOptions): Promise<ExecResult>;
|
|
4151
|
+
/**
|
|
4152
|
+
* Read a file from the sandbox.
|
|
4153
|
+
*
|
|
4154
|
+
* @param path - Path to the file. Relative paths resolve from the workspace root.
|
|
4155
|
+
* Absolute paths (e.g., `/tmp/output.json`) access the container filesystem directly.
|
|
4156
|
+
* @returns File content as string
|
|
4157
|
+
*
|
|
4158
|
+
* @example
|
|
4159
|
+
* ```typescript
|
|
4160
|
+
* const content = await box.read("src/index.ts");
|
|
4161
|
+
* const report = await box.read("/output/report.json");
|
|
4162
|
+
* ```
|
|
4163
|
+
*/
|
|
4164
|
+
read(path: string, options?: {
|
|
4165
|
+
sessionId?: string;
|
|
4166
|
+
}): Promise<string>;
|
|
4167
|
+
/**
|
|
4168
|
+
* Write content to a file in the sandbox.
|
|
4169
|
+
*
|
|
4170
|
+
* @param path - Path to the file. Relative paths resolve from the workspace root.
|
|
4171
|
+
* Absolute paths (e.g., `/tmp/cases.json`) write to the container filesystem directly.
|
|
4172
|
+
* @param content - Content to write
|
|
4173
|
+
*
|
|
4174
|
+
* @example
|
|
4175
|
+
* ```typescript
|
|
4176
|
+
* await box.write("src/fix.ts", "export const fix = () => {}");
|
|
4177
|
+
* await box.write("/tmp/config.json", JSON.stringify(config));
|
|
4178
|
+
* ```
|
|
4179
|
+
*/
|
|
4180
|
+
write(path: string, content: string): Promise<void>;
|
|
4181
|
+
/**
|
|
4182
|
+
* Send a prompt to the agent running in the sandbox.
|
|
4183
|
+
* Returns the complete response after the agent finishes.
|
|
4184
|
+
*/
|
|
4185
|
+
prompt(message: string | PromptInputPart[], options?: PromptOptions): Promise<PromptResult>;
|
|
4186
|
+
/**
|
|
4187
|
+
* Stream events from an agent prompt.
|
|
4188
|
+
* Use this for real-time updates during agent execution.
|
|
4189
|
+
*
|
|
4190
|
+
* Automatically reconnects via the runtime event replay endpoint if the
|
|
4191
|
+
* SSE stream drops before a terminal event (`result` or `done`) is received.
|
|
4192
|
+
* Reconnection is transparent — replayed events that were already yielded
|
|
4193
|
+
* (based on event ID tracking) are deduplicated.
|
|
4194
|
+
*/
|
|
4195
|
+
streamPrompt(message: string | PromptInputPart[], options?: PromptOptions): AsyncGenerator<SandboxEvent>;
|
|
4196
|
+
/**
|
|
4197
|
+
* Stream sandbox lifecycle and activity events.
|
|
4198
|
+
*/
|
|
4199
|
+
events(options?: EventStreamOptions): AsyncGenerator<SandboxEvent>;
|
|
4200
|
+
trace(options?: SandboxTraceOptions): Promise<SandboxTraceBundle>;
|
|
4201
|
+
intelligence(): Promise<NonNullable<SandboxTraceBundle["intelligence"]>>;
|
|
4202
|
+
createIntelligenceReport(options?: {
|
|
4203
|
+
mode?: "deterministic" | "agentic";
|
|
4204
|
+
acknowledgeCost?: boolean;
|
|
4205
|
+
budget?: IntelligenceReportBudget;
|
|
4206
|
+
metadata?: Record<string, unknown>;
|
|
4207
|
+
}): Promise<IntelligenceReport>;
|
|
4208
|
+
createAgenticIntelligenceReport(options: {
|
|
4209
|
+
maxUsd: number;
|
|
4210
|
+
metadata?: Record<string, unknown>;
|
|
4211
|
+
}): Promise<IntelligenceReport>;
|
|
4212
|
+
exportTrace(sink: TraceExportSink): Promise<TraceExportResult>;
|
|
4213
|
+
/**
|
|
4214
|
+
* Stream real-time provisioning progress events.
|
|
4215
|
+
*
|
|
4216
|
+
* Connects to the SSE events stream and yields typed `ProvisionEvent` objects
|
|
4217
|
+
* for each provisioning step. The generator completes when provisioning
|
|
4218
|
+
* finishes (success or failure) and returns the terminal result.
|
|
4219
|
+
*
|
|
4220
|
+
* @returns AsyncGenerator of ProvisionEvent, with a ProvisionResult return value
|
|
4221
|
+
*
|
|
4222
|
+
* @example
|
|
4223
|
+
* ```typescript
|
|
4224
|
+
* const box = await client.create({ image: "ethereum" });
|
|
4225
|
+
*
|
|
4226
|
+
* const stream = box.watchProvisioning();
|
|
4227
|
+
* for await (const event of stream) {
|
|
4228
|
+
* console.log(`[${event.step}] ${event.status} — ${event.message}`);
|
|
4229
|
+
* }
|
|
4230
|
+
* // stream.return value contains the terminal result
|
|
4231
|
+
* ```
|
|
4232
|
+
*/
|
|
4233
|
+
watchProvisioning(options?: {
|
|
4234
|
+
signal?: AbortSignal;
|
|
4235
|
+
}): AsyncGenerator<ProvisionEvent, ProvisionResult | undefined>;
|
|
4236
|
+
/**
|
|
4237
|
+
* Run an agentic task until completion.
|
|
4238
|
+
*
|
|
4239
|
+
* Unlike prompt(), task() is designed for autonomous agent work:
|
|
4240
|
+
* - The agent works until it completes the task or hits an error
|
|
4241
|
+
* - Session state is maintained for context continuity
|
|
4242
|
+
* - Token usage is aggregated across the execution
|
|
4243
|
+
*
|
|
4244
|
+
* Note: The agent (OpenCode/Claude) handles multi-turn execution internally.
|
|
4245
|
+
* Most tasks complete in a single call. The maxTurns option is for edge cases
|
|
4246
|
+
* where the agent explicitly signals it needs additional input.
|
|
4247
|
+
*
|
|
4248
|
+
* @param prompt - Task description for the agent
|
|
4249
|
+
* @param options - Task options
|
|
4250
|
+
* @returns Task result with response and execution metadata
|
|
4251
|
+
*/
|
|
4252
|
+
task(prompt: string, options?: TaskOptions): Promise<TaskResult>;
|
|
4253
|
+
/**
|
|
4254
|
+
* Stream events from a task execution.
|
|
4255
|
+
*
|
|
4256
|
+
* Use this for real-time updates as the agent works:
|
|
4257
|
+
* - Tool calls and results
|
|
4258
|
+
* - Thinking/reasoning steps
|
|
4259
|
+
* - File operations
|
|
4260
|
+
* - Final response
|
|
4261
|
+
*
|
|
4262
|
+
* @param prompt - Task description for the agent
|
|
4263
|
+
* @param options - Task options
|
|
4264
|
+
*/
|
|
4265
|
+
streamTask(prompt: string, options?: TaskOptions): AsyncGenerator<SandboxEvent>;
|
|
4266
|
+
/**
|
|
4267
|
+
* Search for text patterns in files using ripgrep.
|
|
4268
|
+
*
|
|
4269
|
+
* This is a first-class code search capability, not a shell wrapper.
|
|
4270
|
+
* Ripgrep is pre-installed in all managed sandboxes.
|
|
4271
|
+
*
|
|
4272
|
+
* @param pattern - Regular expression pattern to search for
|
|
4273
|
+
* @param options - Search options
|
|
4274
|
+
* @returns Async iterator of search matches
|
|
4275
|
+
*
|
|
4276
|
+
* @example Search for task-marker comments
|
|
4277
|
+
* ```typescript
|
|
4278
|
+
* for await (const match of box.search("TASK:", { glob: "**\/*.ts" })) {
|
|
4279
|
+
* console.log(`${match.path}:${match.line}: ${match.text}`);
|
|
4280
|
+
* }
|
|
4281
|
+
* ```
|
|
4282
|
+
*
|
|
4283
|
+
* @example Collect all matches
|
|
4284
|
+
* ```typescript
|
|
4285
|
+
* const matches = [];
|
|
4286
|
+
* for await (const match of box.search("function.*async")) {
|
|
4287
|
+
* matches.push(match);
|
|
4288
|
+
* }
|
|
4289
|
+
* ```
|
|
4290
|
+
*/
|
|
4291
|
+
search(pattern: string, options?: SearchOptions): AsyncGenerator<SearchMatch>;
|
|
4292
|
+
/**
|
|
4293
|
+
* Git capability object for repository operations.
|
|
4294
|
+
*
|
|
4295
|
+
* All git operations are executed in the sandbox workspace.
|
|
4296
|
+
*
|
|
4297
|
+
* @example Check status and commit
|
|
4298
|
+
* ```typescript
|
|
4299
|
+
* const status = await box.git.status();
|
|
4300
|
+
* if (status.isDirty) {
|
|
4301
|
+
* await box.git.add(["."]);
|
|
4302
|
+
* await box.git.commit("Update files");
|
|
4303
|
+
* await box.git.push();
|
|
4304
|
+
* }
|
|
4305
|
+
* ```
|
|
4306
|
+
*/
|
|
4307
|
+
get git(): GitCapability;
|
|
4308
|
+
private gitStatus;
|
|
4309
|
+
private gitLog;
|
|
4310
|
+
private gitDiff;
|
|
4311
|
+
private gitAdd;
|
|
4312
|
+
private gitCommit;
|
|
4313
|
+
private gitPush;
|
|
4314
|
+
private gitPull;
|
|
4315
|
+
private gitBranches;
|
|
4316
|
+
private gitCheckout;
|
|
4317
|
+
/**
|
|
4318
|
+
* Tools capability object for managing language runtimes.
|
|
4319
|
+
*
|
|
4320
|
+
* Uses mise (polyglot version manager) to install and manage tools.
|
|
4321
|
+
*
|
|
4322
|
+
* @example Install and use Node.js
|
|
4323
|
+
* ```typescript
|
|
4324
|
+
* await box.tools.install("node", "22");
|
|
4325
|
+
* await box.tools.use("node", "22");
|
|
4326
|
+
* const list = await box.tools.list();
|
|
4327
|
+
* ```
|
|
4328
|
+
*/
|
|
4329
|
+
get tools(): ToolsCapability;
|
|
4330
|
+
/**
|
|
4331
|
+
* File system operations beyond basic read/write:
|
|
4332
|
+
* - Binary upload/download
|
|
4333
|
+
* - Directory ops (uploadDir, downloadDir, list, mkdir)
|
|
4334
|
+
* - Metadata (stat, exists)
|
|
4335
|
+
* - Progress reporting for large files
|
|
4336
|
+
*
|
|
4337
|
+
* @example Upload and download
|
|
4338
|
+
* ```typescript
|
|
4339
|
+
* await box.fs.upload("./model.bin", "/workspace/models/model.bin");
|
|
4340
|
+
* await box.fs.download("/workspace/results.zip", "./results.zip");
|
|
4341
|
+
* ```
|
|
4342
|
+
*
|
|
4343
|
+
* @example Directory operations
|
|
4344
|
+
* ```typescript
|
|
4345
|
+
* await box.fs.uploadDir("./project", "/workspace/project");
|
|
4346
|
+
* const files = await box.fs.list("/workspace");
|
|
4347
|
+
* ```
|
|
4348
|
+
*
|
|
4349
|
+
* @example File management
|
|
4350
|
+
* ```typescript
|
|
4351
|
+
* if (await box.fs.exists("/workspace/config.json")) {
|
|
4352
|
+
* const info = await box.fs.stat("/workspace/config.json");
|
|
4353
|
+
* console.log(`Size: ${info.size}`);
|
|
4354
|
+
* }
|
|
4355
|
+
* await box.fs.mkdir("/workspace/output", { recursive: true });
|
|
4356
|
+
* await box.fs.delete("/workspace/temp", { recursive: true });
|
|
4357
|
+
* ```
|
|
4358
|
+
*/
|
|
4359
|
+
get fs(): FileSystem;
|
|
4360
|
+
private fsUpload;
|
|
4361
|
+
private fsDownload;
|
|
4362
|
+
private fsUploadDir;
|
|
4363
|
+
private fsDownloadDir;
|
|
4364
|
+
private fsList;
|
|
4365
|
+
private fsStat;
|
|
4366
|
+
private fsDelete;
|
|
4367
|
+
private fsMkdir;
|
|
4368
|
+
private fsExists;
|
|
4369
|
+
/**
|
|
4370
|
+
* Permissions manager for multi-user access control.
|
|
4371
|
+
*
|
|
4372
|
+
* @example List users
|
|
4373
|
+
* ```typescript
|
|
4374
|
+
* const users = await box.permissions.list();
|
|
4375
|
+
* for (const user of users) {
|
|
4376
|
+
* console.log(`${user.username}: ${user.role}`);
|
|
4377
|
+
* }
|
|
4378
|
+
* ```
|
|
4379
|
+
*
|
|
4380
|
+
* @example Add a developer
|
|
4381
|
+
* ```typescript
|
|
4382
|
+
* await box.permissions.add({
|
|
4383
|
+
* userId: "user_abc",
|
|
4384
|
+
* role: "developer",
|
|
4385
|
+
* sshKeys: ["ssh-ed25519 AAAA..."],
|
|
4386
|
+
* });
|
|
4387
|
+
* ```
|
|
4388
|
+
*/
|
|
4389
|
+
get permissions(): PermissionsManager;
|
|
4390
|
+
private permissionsList;
|
|
4391
|
+
private permissionsGet;
|
|
4392
|
+
private permissionsAdd;
|
|
4393
|
+
private permissionsUpdate;
|
|
4394
|
+
private permissionsRemove;
|
|
4395
|
+
private permissionsSetAccessPolicies;
|
|
4396
|
+
private permissionsGetAccessPolicies;
|
|
4397
|
+
private permissionsCheckAccess;
|
|
4398
|
+
/**
|
|
4399
|
+
* Backend manager for runtime agent configuration.
|
|
4400
|
+
*
|
|
4401
|
+
* @example Check backend status
|
|
4402
|
+
* ```typescript
|
|
4403
|
+
* const status = await box.backend.status();
|
|
4404
|
+
* console.log(`Backend: ${status.type}, Status: ${status.status}`);
|
|
4405
|
+
* ```
|
|
4406
|
+
*
|
|
4407
|
+
* @example Add MCP server at runtime
|
|
4408
|
+
* ```typescript
|
|
4409
|
+
* await box.backend.addMcp("web-search", {
|
|
4410
|
+
* command: "npx",
|
|
4411
|
+
* args: ["-y", "@anthropic/web-search"],
|
|
4412
|
+
* });
|
|
4413
|
+
* ```
|
|
4414
|
+
*
|
|
4415
|
+
* @example Read provider-native Cursor metadata
|
|
4416
|
+
* ```typescript
|
|
4417
|
+
* const models = await box.backend.models();
|
|
4418
|
+
* const agents = await box.backend.agents({ limit: 20 });
|
|
4419
|
+
* const runs = await box.backend.runs(agents.items[0].agentId);
|
|
4420
|
+
* ```
|
|
4421
|
+
*/
|
|
4422
|
+
get backend(): BackendManager;
|
|
4423
|
+
private backendStatus;
|
|
4424
|
+
private backendCapabilities;
|
|
4425
|
+
private backendAddMcp;
|
|
4426
|
+
private backendGetMcpStatus;
|
|
4427
|
+
private backendUpdateConfig;
|
|
4428
|
+
private backendControlData;
|
|
4429
|
+
private backendControlAction;
|
|
4430
|
+
private backendListSearch;
|
|
4431
|
+
private backendAccount;
|
|
4432
|
+
private backendModels;
|
|
4433
|
+
private backendRepositories;
|
|
4434
|
+
private backendAgents;
|
|
4435
|
+
private backendAgent;
|
|
4436
|
+
private backendArchiveAgent;
|
|
4437
|
+
private backendUnarchiveAgent;
|
|
4438
|
+
private backendDeleteAgent;
|
|
4439
|
+
private backendRuns;
|
|
4440
|
+
private backendRun;
|
|
4441
|
+
private backendAgentMessages;
|
|
4442
|
+
private backendArtifacts;
|
|
4443
|
+
private backendDownloadArtifact;
|
|
4444
|
+
private backendRestart;
|
|
4445
|
+
/**
|
|
4446
|
+
* Process manager for spawning and controlling processes.
|
|
4447
|
+
*
|
|
4448
|
+
* Provides non-blocking process execution with real-time log streaming,
|
|
4449
|
+
* ideal for long-running tasks like ML training or dev servers.
|
|
4450
|
+
*
|
|
4451
|
+
* @example Non-blocking process
|
|
4452
|
+
* ```typescript
|
|
4453
|
+
* const proc = await box.process.spawn("python train.py", {
|
|
4454
|
+
* cwd: "/workspace",
|
|
4455
|
+
* env: { "CUDA_VISIBLE_DEVICES": "0" }
|
|
4456
|
+
* });
|
|
4457
|
+
*
|
|
4458
|
+
* // Stream logs
|
|
4459
|
+
* for await (const entry of proc.logs()) {
|
|
4460
|
+
* console.log(`[${entry.type}] ${entry.data}`);
|
|
4461
|
+
* }
|
|
4462
|
+
*
|
|
4463
|
+
* // Check status
|
|
4464
|
+
* const status = await proc.status();
|
|
4465
|
+
* console.log(`Running: ${status.running}`);
|
|
4466
|
+
*
|
|
4467
|
+
* // Kill if needed
|
|
4468
|
+
* await proc.kill();
|
|
4469
|
+
* ```
|
|
4470
|
+
*
|
|
4471
|
+
* @example Run Python code directly
|
|
4472
|
+
* ```typescript
|
|
4473
|
+
* const result = await box.process.runCode(`
|
|
4474
|
+
* import numpy as np
|
|
4475
|
+
* print(np.random.rand(10).mean())
|
|
4476
|
+
* `);
|
|
4477
|
+
* console.log(result.stdout);
|
|
4478
|
+
* ```
|
|
4479
|
+
*/
|
|
4480
|
+
get process(): ProcessManager;
|
|
4481
|
+
private processSpawn;
|
|
4482
|
+
private processRunCode;
|
|
4483
|
+
private processList;
|
|
4484
|
+
private processGet;
|
|
4485
|
+
private createProcessHandle;
|
|
4486
|
+
private parseProcessLogStream;
|
|
4487
|
+
/**
|
|
4488
|
+
* Network manager for runtime network configuration.
|
|
4489
|
+
*
|
|
4490
|
+
* @example Update network restrictions
|
|
4491
|
+
* ```typescript
|
|
4492
|
+
* // Block all outbound traffic
|
|
4493
|
+
* await box.network.update({ blockOutbound: true });
|
|
4494
|
+
*
|
|
4495
|
+
* // Or switch to allowlist mode
|
|
4496
|
+
* await box.network.update({
|
|
4497
|
+
* allowList: ["192.168.1.0/24", "8.8.8.8/32"]
|
|
4498
|
+
* });
|
|
4499
|
+
* ```
|
|
4500
|
+
*
|
|
4501
|
+
* @example Expose ports dynamically
|
|
4502
|
+
* ```typescript
|
|
4503
|
+
* const url = await box.network.exposePort(8000);
|
|
4504
|
+
* console.log(`Service available at: ${url}`);
|
|
4505
|
+
* ```
|
|
4506
|
+
*/
|
|
4507
|
+
get network(): NetworkManager;
|
|
4508
|
+
private networkUpdate;
|
|
4509
|
+
private networkExposePort;
|
|
4510
|
+
private networkListUrls;
|
|
4511
|
+
private networkGetConfig;
|
|
4512
|
+
/**
|
|
4513
|
+
* Validate CIDR notation (IPv4 and IPv6)
|
|
4514
|
+
*/
|
|
4515
|
+
private isValidCidr;
|
|
4516
|
+
/**
|
|
4517
|
+
* Preview link management.
|
|
4518
|
+
*
|
|
4519
|
+
* Create publicly accessible HTTPS URLs for TCP ports inside the sandbox.
|
|
4520
|
+
*
|
|
4521
|
+
* @example
|
|
4522
|
+
* ```typescript
|
|
4523
|
+
* const link = await box.previewLinks.create(3000);
|
|
4524
|
+
* console.log(link.url);
|
|
4525
|
+
*
|
|
4526
|
+
* const links = await box.previewLinks.list();
|
|
4527
|
+
* await box.previewLinks.remove(link.previewId);
|
|
4528
|
+
* ```
|
|
4529
|
+
*/
|
|
4530
|
+
get previewLinks(): PreviewLinkManager;
|
|
4531
|
+
private previewLinkCreate;
|
|
4532
|
+
private previewLinkList;
|
|
4533
|
+
private previewLinkRemove;
|
|
4534
|
+
/**
|
|
4535
|
+
* Get information about the infrastructure driver for this sandbox.
|
|
4536
|
+
*
|
|
4537
|
+
* @example
|
|
4538
|
+
* ```typescript
|
|
4539
|
+
* const info = await box.getDriverInfo();
|
|
4540
|
+
* console.log(`Driver: ${info.type}, CRIU: ${info.capabilities.criu}`);
|
|
4541
|
+
* ```
|
|
4542
|
+
*/
|
|
4543
|
+
getDriverInfo(): Promise<DriverInfo>;
|
|
4544
|
+
private toolsInstall;
|
|
4545
|
+
private toolsUse;
|
|
4546
|
+
private toolsList;
|
|
4547
|
+
private toolsRun;
|
|
4548
|
+
/**
|
|
4549
|
+
* Create a snapshot of the sandbox state.
|
|
4550
|
+
* Snapshots can be used to save workspace state for later restoration.
|
|
4551
|
+
*
|
|
4552
|
+
* If `storage` is provided (BYOS3), the snapshot is created directly
|
|
4553
|
+
* directly on the sandbox and uploaded to customer-provided S3 storage.
|
|
4554
|
+
*
|
|
4555
|
+
* @param options - Snapshot options (tags, paths, storage)
|
|
4556
|
+
* @returns Snapshot result with ID and metadata
|
|
4557
|
+
*
|
|
4558
|
+
* @example Standard snapshot (our storage)
|
|
4559
|
+
* ```typescript
|
|
4560
|
+
* const snap = await box.snapshot({
|
|
4561
|
+
* tags: ["v1.0", "stable"],
|
|
4562
|
+
* });
|
|
4563
|
+
* console.log(`Snapshot: ${snap.snapshotId}`);
|
|
4564
|
+
* ```
|
|
4565
|
+
*
|
|
4566
|
+
* @example BYOS3 snapshot (customer storage)
|
|
4567
|
+
* ```typescript
|
|
4568
|
+
* const snap = await box.snapshot({
|
|
4569
|
+
* tags: ["production"],
|
|
4570
|
+
* storage: {
|
|
4571
|
+
* type: "s3",
|
|
4572
|
+
* bucket: "my-snapshots",
|
|
4573
|
+
* credentials: { accessKeyId: "...", secretAccessKey: "..." },
|
|
4574
|
+
* },
|
|
4575
|
+
* });
|
|
4576
|
+
* ```
|
|
4577
|
+
*/
|
|
4578
|
+
snapshot(options?: SnapshotOptions): Promise<SnapshotResult>;
|
|
4579
|
+
/**
|
|
4580
|
+
* List all snapshots for this sandbox.
|
|
4581
|
+
*
|
|
4582
|
+
* If `storage` is provided (BYOS3), lists snapshots from customer-provided
|
|
4583
|
+
* S3 storage.
|
|
4584
|
+
*
|
|
4585
|
+
* @param storage - Optional customer storage config for BYOS3
|
|
4586
|
+
* @returns Array of snapshot metadata
|
|
4587
|
+
*
|
|
4588
|
+
* @example List from our storage
|
|
4589
|
+
* ```typescript
|
|
4590
|
+
* const snapshots = await box.listSnapshots();
|
|
4591
|
+
* for (const snap of snapshots) {
|
|
4592
|
+
* console.log(`${snap.snapshotId}: ${snap.createdAt}`);
|
|
4593
|
+
* }
|
|
4594
|
+
* ```
|
|
4595
|
+
*
|
|
4596
|
+
* @example List from customer S3 (BYOS3)
|
|
4597
|
+
* ```typescript
|
|
4598
|
+
* const snapshots = await box.listSnapshots({
|
|
4599
|
+
* type: "s3",
|
|
4600
|
+
* bucket: "my-snapshots",
|
|
4601
|
+
* credentials: { accessKeyId: "...", secretAccessKey: "..." },
|
|
4602
|
+
* });
|
|
4603
|
+
* ```
|
|
4604
|
+
*/
|
|
4605
|
+
listSnapshots(storage?: SnapshotOptions["storage"]): Promise<SnapshotInfo[]>;
|
|
4606
|
+
revertToSnapshot(snapshotId: string): Promise<SnapshotResult>;
|
|
4607
|
+
private waitForSnapshotRestore;
|
|
4608
|
+
private waitForSnapshotVisible;
|
|
4609
|
+
deleteSnapshot(snapshotId: string): Promise<void>;
|
|
4610
|
+
/**
|
|
4611
|
+
* Restore from the latest snapshot in customer-provided storage.
|
|
4612
|
+
* Only available when using BYOS3 (calls the runtime directly).
|
|
4613
|
+
*
|
|
4614
|
+
* @param storage - Customer storage config (required)
|
|
4615
|
+
* @param destinationPath - Optional path to restore to
|
|
4616
|
+
* @returns Snapshot info if restored, null if no snapshot found
|
|
4617
|
+
*
|
|
4618
|
+
* @example Restore from customer S3
|
|
4619
|
+
* ```typescript
|
|
4620
|
+
* const result = await box.restoreFromStorage({
|
|
4621
|
+
* type: "s3",
|
|
4622
|
+
* bucket: "my-snapshots",
|
|
4623
|
+
* credentials: { accessKeyId: "...", secretAccessKey: "..." },
|
|
4624
|
+
* });
|
|
4625
|
+
*
|
|
4626
|
+
* if (result) {
|
|
4627
|
+
* console.log(`Restored from ${result.snapshotId}`);
|
|
4628
|
+
* } else {
|
|
4629
|
+
* console.log("No snapshot found");
|
|
4630
|
+
* }
|
|
4631
|
+
* ```
|
|
4632
|
+
*/
|
|
4633
|
+
restoreFromStorage(storage: SnapshotOptions["storage"], options?: RestoreSnapshotOptions): Promise<SnapshotResult | null>;
|
|
4634
|
+
/**
|
|
4635
|
+
* Create a CRIU checkpoint of the sandbox's memory state.
|
|
4636
|
+
*
|
|
4637
|
+
* Checkpoints capture the complete memory state of the running sandbox,
|
|
4638
|
+
* enabling true pause/resume and fork operations. Unlike snapshots which
|
|
4639
|
+
* only preserve filesystem state, checkpoints preserve process memory,
|
|
4640
|
+
* open file descriptors, and execution state.
|
|
4641
|
+
*
|
|
4642
|
+
* **Requirements:** CRIU must be available on the host. Check availability
|
|
4643
|
+
* with `client.criuStatus()` before calling.
|
|
4644
|
+
*
|
|
4645
|
+
* **Note:** By default, checkpoint stops the sandbox. Use `leaveRunning: true`
|
|
4646
|
+
* to keep it running (creates a copy-on-write checkpoint).
|
|
4647
|
+
*
|
|
4648
|
+
* @param options - Checkpoint options
|
|
4649
|
+
* @returns Checkpoint result with ID and metadata
|
|
4650
|
+
*
|
|
4651
|
+
* @example Basic checkpoint (stops sandbox)
|
|
4652
|
+
* ```typescript
|
|
4653
|
+
* const checkpoint = await box.checkpoint();
|
|
4654
|
+
* console.log(`Checkpoint: ${checkpoint.checkpointId}`);
|
|
4655
|
+
* // Sandbox is now stopped, resume with box.resume()
|
|
4656
|
+
* ```
|
|
4657
|
+
*
|
|
4658
|
+
* @example Checkpoint without stopping
|
|
4659
|
+
* ```typescript
|
|
4660
|
+
* const checkpoint = await box.checkpoint({
|
|
4661
|
+
* tags: ["before-deploy"],
|
|
4662
|
+
* leaveRunning: true,
|
|
4663
|
+
* });
|
|
4664
|
+
* // Sandbox continues running
|
|
4665
|
+
* ```
|
|
4666
|
+
*/
|
|
4667
|
+
checkpoint(options?: CheckpointOptions): Promise<CheckpointResult>;
|
|
4668
|
+
/**
|
|
4669
|
+
* List all checkpoints for this sandbox.
|
|
4670
|
+
*
|
|
4671
|
+
* @returns Array of checkpoint metadata
|
|
4672
|
+
*
|
|
4673
|
+
* @example
|
|
4674
|
+
* ```typescript
|
|
4675
|
+
* const checkpoints = await box.listCheckpoints();
|
|
4676
|
+
* for (const cp of checkpoints) {
|
|
4677
|
+
* console.log(`${cp.checkpointId}: ${cp.createdAt}`);
|
|
4678
|
+
* }
|
|
4679
|
+
* ```
|
|
4680
|
+
*/
|
|
4681
|
+
listCheckpoints(): Promise<CheckpointInfo[]>;
|
|
4682
|
+
/**
|
|
4683
|
+
* Delete a checkpoint.
|
|
4684
|
+
*
|
|
4685
|
+
* @param checkpointId - ID of the checkpoint to delete
|
|
4686
|
+
*/
|
|
4687
|
+
deleteCheckpoint(checkpointId: string): Promise<void>;
|
|
4688
|
+
/**
|
|
4689
|
+
* Fork a new sandbox from a checkpoint.
|
|
4690
|
+
*
|
|
4691
|
+
* Creates a new sandbox with the same memory state as this sandbox
|
|
4692
|
+
* at the time of the checkpoint. The fork has a new identity but
|
|
4693
|
+
* preserves the execution state.
|
|
4694
|
+
*
|
|
4695
|
+
* **Use cases:**
|
|
4696
|
+
* - Branch workflows: Create parallel execution paths
|
|
4697
|
+
* - A/B testing: Run same state with different configurations
|
|
4698
|
+
* - Debugging: Fork at a specific point to investigate
|
|
4699
|
+
*
|
|
4700
|
+
* @param checkpointId - ID of the checkpoint to fork from
|
|
4701
|
+
* @param options - Fork configuration
|
|
4702
|
+
* @returns The new sandbox instance
|
|
4703
|
+
*
|
|
4704
|
+
* @example Basic fork
|
|
4705
|
+
* ```typescript
|
|
4706
|
+
* const checkpoint = await box.checkpoint({ leaveRunning: true });
|
|
4707
|
+
* const forked = await box.fork(checkpoint.checkpointId);
|
|
4708
|
+
* // forked has same memory state as box at checkpoint time
|
|
4709
|
+
* ```
|
|
4710
|
+
*
|
|
4711
|
+
* @example Fork with custom config
|
|
4712
|
+
* ```typescript
|
|
4713
|
+
* const forked = await box.fork(checkpointId, {
|
|
4714
|
+
* name: "experiment-branch",
|
|
4715
|
+
* env: { EXPERIMENT: "true" },
|
|
4716
|
+
* });
|
|
4717
|
+
* ```
|
|
4718
|
+
*/
|
|
4719
|
+
fork(checkpointId: string, options?: ForkOptions): Promise<SandboxInstance>;
|
|
4720
|
+
/**
|
|
4721
|
+
* Stop the sandbox (keeps state for resume).
|
|
4722
|
+
*/
|
|
4723
|
+
stop(): Promise<void>;
|
|
4724
|
+
/**
|
|
4725
|
+
* Resume a stopped sandbox.
|
|
4726
|
+
*/
|
|
4727
|
+
resume(): Promise<void>;
|
|
4728
|
+
/**
|
|
4729
|
+
* Delete the sandbox permanently.
|
|
4730
|
+
*/
|
|
4731
|
+
delete(): Promise<void>;
|
|
4732
|
+
/**
|
|
4733
|
+
* keepAlive is intentionally unavailable until the API exposes timeout updates.
|
|
4734
|
+
* @param seconds - Reserved for future support
|
|
4735
|
+
*/
|
|
4736
|
+
keepAlive(_seconds?: number): Promise<void>;
|
|
4737
|
+
/**
|
|
4738
|
+
* Upload a local directory to the sandbox via tar.
|
|
4739
|
+
* @param localPath - Local directory path to upload
|
|
4740
|
+
* @param remotePath - Destination path in the sandbox (default: /home/user)
|
|
4741
|
+
*/
|
|
4742
|
+
uploadDirectory(localPath: string, remotePath?: string): Promise<void>;
|
|
4743
|
+
/**
|
|
4744
|
+
* Wait for the sandbox to reach a specific status.
|
|
4745
|
+
*
|
|
4746
|
+
* When `onProgress` is provided and the sandbox is still provisioning,
|
|
4747
|
+
* uses SSE events for real-time progress instead of polling. Falls back
|
|
4748
|
+
* to polling if the SSE connection fails or is unavailable.
|
|
4749
|
+
*
|
|
4750
|
+
* @example Basic wait
|
|
4751
|
+
* ```typescript
|
|
4752
|
+
* await box.waitFor("running");
|
|
4753
|
+
* ```
|
|
4754
|
+
*
|
|
4755
|
+
* @example Wait with progress tracking
|
|
4756
|
+
* ```typescript
|
|
4757
|
+
* await box.waitFor("running", {
|
|
4758
|
+
* onProgress: (event) => {
|
|
4759
|
+
* console.log(`[${event.step}] ${event.status} — ${event.message}`);
|
|
4760
|
+
* if (event.percent !== undefined) {
|
|
4761
|
+
* updateProgressBar(event.percent);
|
|
4762
|
+
* }
|
|
4763
|
+
* },
|
|
4764
|
+
* });
|
|
4765
|
+
* ```
|
|
4766
|
+
*/
|
|
4767
|
+
waitFor(status: SandboxStatus | SandboxStatus[], options?: WaitForOptions): Promise<void>;
|
|
4768
|
+
/**
|
|
4769
|
+
* SSE-based wait implementation. Subscribes to provisioning events and
|
|
4770
|
+
* delivers progress callbacks while waiting for a target status.
|
|
4771
|
+
*/
|
|
4772
|
+
private waitForWithSSE;
|
|
4773
|
+
private parseCheckpointInfo;
|
|
4774
|
+
private ensureRunning;
|
|
4775
|
+
private runtimeFetch;
|
|
4776
|
+
/**
|
|
4777
|
+
* Delegates to the shared `parseSSEStream` in `lib/sse-parser.ts`
|
|
4778
|
+
* — one canonical SSE implementation for the whole SDK. The
|
|
4779
|
+
* shared parser throws `AbortError` on cancellation (so consumers
|
|
4780
|
+
* can distinguish cancel from clean EOF), but agent/task streaming
|
|
4781
|
+
* callers of this method historically relied on a silent-return
|
|
4782
|
+
* abort: they check `options?.signal?.aborted` AFTER the loop and
|
|
4783
|
+
* decide whether to reconnect. The try/catch below preserves that
|
|
4784
|
+
* legacy contract by swallowing AbortError at the delegate layer.
|
|
4785
|
+
*/
|
|
4786
|
+
private parseSSEStream;
|
|
4787
|
+
/**
|
|
4788
|
+
* Associate a session ID with a user ID so the Sandbox API can route
|
|
4789
|
+
* subsequent WebSocket connections to this sandbox.
|
|
4790
|
+
*
|
|
4791
|
+
* @param opts - Session and user identifiers
|
|
4792
|
+
*
|
|
4793
|
+
* @example
|
|
4794
|
+
* ```typescript
|
|
4795
|
+
* await box.registerSessionMapping({
|
|
4796
|
+
* sessionId: "sess_abc",
|
|
4797
|
+
* userId: "user_123",
|
|
4798
|
+
* });
|
|
4799
|
+
* ```
|
|
4800
|
+
*/
|
|
4801
|
+
registerSessionMapping(opts: {
|
|
4802
|
+
sessionId: string;
|
|
4803
|
+
userId: string;
|
|
4804
|
+
}): Promise<void>;
|
|
4805
|
+
private parseInfo;
|
|
4806
|
+
private sleep;
|
|
4807
|
+
/**
|
|
4808
|
+
* Get a session reference bound to this sandbox. Lazy: does not hit the
|
|
4809
|
+
* network until you call a method on the returned `SandboxSession`.
|
|
4810
|
+
* Use {@link sessions} to discover existing session ids.
|
|
4811
|
+
*/
|
|
4812
|
+
session(id: string): SandboxSession;
|
|
4813
|
+
/**
|
|
4814
|
+
* List sessions on this sandbox, optionally filtering by status. Returns
|
|
4815
|
+
* `SandboxSession` instances paired with their last-known
|
|
4816
|
+
* {@link SessionInfo} so callers can avoid an extra round-trip per
|
|
4817
|
+
* session for status.
|
|
4818
|
+
*/
|
|
4819
|
+
sessions(opts?: SessionListOptions): Promise<Array<{
|
|
4820
|
+
session: SandboxSession;
|
|
4821
|
+
info: SessionInfo;
|
|
4822
|
+
}>>;
|
|
4823
|
+
/**
|
|
4824
|
+
* Dispatch a prompt and return immediately with the session id (Issue
|
|
4825
|
+
* #913 Gap 2). The sandbox keeps running the prompt after this call
|
|
4826
|
+
* returns; reconnect via `box.session(id).events()` or wait for
|
|
4827
|
+
* completion with `box.session(id).result()`.
|
|
4828
|
+
*
|
|
4829
|
+
* Idempotent on `opts.sessionId`: re-dispatching with the same id when
|
|
4830
|
+
* the session is already running is a lookup, not a re-create. This
|
|
4831
|
+
* lets queue retries and reconnect-after-Worker-restart be safe by
|
|
4832
|
+
* construction.
|
|
4833
|
+
*/
|
|
4834
|
+
dispatchPrompt(message: string | PromptInputPart[], opts?: DispatchPromptOptions): Promise<DispatchedSession>;
|
|
4835
|
+
/**
|
|
4836
|
+
* Mint a scoped, time-bounded JWT for direct browser access to this
|
|
4837
|
+
* sandbox (Issue #913 Gap 1). Authority is the caller's
|
|
4838
|
+
* `TANGLE_API_KEY` (sk-tan-*) — the Sandbox API mints the token;
|
|
4839
|
+
* signing secrets stay server-side.
|
|
4840
|
+
*
|
|
4841
|
+
* Use this to give a browser direct read access to the sandbox without
|
|
4842
|
+
* leaking the full bearer (`box.connection.authToken`). The returned
|
|
4843
|
+
* token verifies against the same sidecar middleware that already
|
|
4844
|
+
* gates ProductTokenIssuer-issued JWTs — no new sidecar surface.
|
|
4845
|
+
*/
|
|
4846
|
+
mintScopedToken(opts: MintScopedTokenOptions): Promise<ScopedToken>;
|
|
4847
|
+
/** @internal — invoked by SandboxSession.status(). */
|
|
4848
|
+
_sessionStatus(id: string): Promise<SessionInfo | null>;
|
|
4849
|
+
/** @internal — invoked by SandboxSession.events(). */
|
|
4850
|
+
_sessionEvents(id: string, opts?: SessionEventStreamOptions): AsyncGenerator<SandboxEvent>;
|
|
4851
|
+
/** @internal — invoked by SandboxSession.result(). */
|
|
4852
|
+
_sessionResult(id: string): Promise<PromptResult>;
|
|
4853
|
+
/** @internal — invoked by SandboxSession.cancel(). */
|
|
4854
|
+
_sessionCancel(id: string): Promise<void>;
|
|
4855
|
+
}
|
|
4856
|
+
//#endregion
|
|
4857
|
+
export { FleetExecDispatchOptions as $, StorageConfig as $n, SandboxClientConfig as $t, CreateIntelligenceReportOptions as A, SandboxInfo as An, defineInlineResource as Ar, ProcessLogEntry as At, DownloadProgress as B, ScopedToken as Bn, ProvisionStatus as Bt, BatchResult as C, SandboxFleetTraceExport as Cn, AgentProfileResourceRef as Cr, NetworkManager as Ct, CheckpointOptions as D, SandboxFleetWorkspaceReconcileResult as Dn, AgentSubagentProfile as Dr, PreviewLinkManager as Dt, CheckpointInfo as E, SandboxFleetWorkspace as En, AgentProfileValidationResult as Er, PreviewLinkInfo as Et, DeleteOptions as F, SandboxTraceBundle as Fn, SandboxMcpEndpoint as Fr, PromptInputPart as Ft, ExecOptions as G, SecretsManager as Gn, PublishPublicTemplateVersionOptions as Gt, DriverInfo as H, SearchMatch as Hn, PublicTemplateInfo as Ht, DirectoryPermission as I, SandboxTraceEvent as In, SandboxMcpServerEntry as Ir, PromptOptions as It, FileSystem as J, SessionListOptions as Jn, ReconcileSandboxFleetsOptions as Jt, ExecResult as K, SessionEventStreamOptions as Kn, ReapExpiredSandboxFleetsOptions as Kt, DispatchPromptOptions as L, SandboxTraceExport as Ln, buildSandboxMcpConfig as Lr, PromptResult as Lt, CreateSandboxFleetTokenOptions as M, SandboxPermissionsConfig as Mn, BuildSandboxMcpConfigOptions as Mr, ProcessSignal as Mt, CreateSandboxFleetWithCoordinatorOptions as N, SandboxResources as Nn, SANDBOX_MCP_SERVER_NAME as Nr, ProcessSpawnOptions as Nt, CheckpointResult as O, SandboxFleetWorkspaceRestoreResult as On, defineAgentProfile as Or, Process as Ot, CreateSandboxOptions as P, SandboxStatus as Pn, SandboxMcpConfig as Pr, ProcessStatus as Pt, FleetDispatchStreamOptions as Q, SnapshotResult as Qn, SSHCredentials as Qt, DispatchedSession as R, SandboxTraceOptions as Rn, ProvisionEvent as Rt, BatchOptions as S, SandboxFleetTraceEvent as Sn, AgentProfilePrompt as Sr, NetworkConfig as St, BatchTaskResult as T, SandboxFleetUsage as Tn, AgentProfileValidationIssue as Tr, PermissionsManager as Tt, DriverType as U, SearchOptions as Un, PublicTemplateVersionInfo as Ut, DriverConfig as V, ScopedTokenScope as Vn, ProvisionStep as Vt, EventStreamOptions as W, SecretInfo as Wn, PublishPublicTemplateOptions as Wt, FleetDispatchResultBuffer as X, SnapshotInfo as Xn, RunCodeOptions as Xt, FleetDispatchCancelResult as Y, SessionStatus as Yn, ReconcileSandboxFleetsResult as Yt, FleetDispatchResultBufferOptions as Z, SnapshotOptions as Zn, SSHCommandDescriptor as Zt, BackendInfo as _, SandboxFleetManifestMachine as _n, AgentProfileConfidential as _r, ListSandboxFleetOptions as _t, TraceExportSink as a, SandboxFleetCostEstimate as an, TeeAttestationResponse as ar, ForkResult as at, BackendType as b, SandboxFleetToken as bn, AgentProfileModelHints as br, MintScopedTokenOptions as bt, otelTraceIdForTangleTrace as c, SandboxFleetDriverCapability as cn, TokenRefreshHandler as cr, GitCommit as ct, AcceleratorKind as d, SandboxFleetIntelligenceEnvelope as dn, UploadOptions as dr, GitStatus as dt, SandboxConnection as en, SubscriptionInfo as er, FleetExecDispatchResult as et, AccessPolicyRule as f, SandboxFleetMachine as fn, UploadProgress as fr, GpuType as ft, BackendConfig as g, SandboxFleetManifest as gn, AgentProfileCapabilities as gr, ListOptions as gt, BackendCapabilities as h, SandboxFleetMachineSpec as hn, AgentProfile as hr, IntelligenceReportBudget as ht, TraceExportResult as i, SandboxFleetArtifactSpec as in, TeeAttestationReport as ir, ForkOptions as it, CreateSandboxFleetOptions as j, SandboxIntelligenceEnvelope as jn, mergeAgentProfiles as jr, ProcessManager as jt, CodeResult as k, SandboxFleetWorkspaceSnapshotResult as kn, defineGitHubResource as kr, ProcessInfo as kt, toOtelJson as l, SandboxFleetDriverTimings as ln, ToolsConfig as lr, GitConfig as lt, AttachSandboxFleetMachineOptions as m, SandboxFleetMachineRecord as mn, WaitForOptions as mr, IntelligenceReport as mt, SandboxInstance as n, SandboxEvent as nn, TaskResult as nr, FleetPromptDispatchOptions as nt, buildTraceExportPayload as o, SandboxFleetDispatchFailureClass as on, TeePublicKey as or, GitAuth as ot, AddUserOptions as p, SandboxFleetMachineMeteredUsage as pn, UsageInfo as pr, InstalledTool as pt, FileInfo as q, SessionInfo as qn, ReapExpiredSandboxFleetsResult as qt, TraceExportFormat as r, SandboxFleetArtifact as rn, TeeAttestationOptions as rr, FleetPromptDispatchResult as rt, exportTraceBundle as s, SandboxFleetDispatchResponse as sn, TeePublicKeyResponse as sr, GitBranch as st, HttpClient as t, SandboxEnvironment as tn, TaskOptions as tr, FleetMachineId as tt, SandboxSession as u, SandboxFleetInfo as un, UpdateUserOptions as ur, GitDiff as ut, BackendManager as v, SandboxFleetOperationsSummary as vn, AgentProfileFileMount as vr, ListSandboxOptions as vt, BatchTask as w, SandboxFleetTraceOptions as wn, AgentProfileResources as wr, PermissionLevel as wt, BatchEvent as x, SandboxFleetTraceBundle as xn, AgentProfilePermissionValue as xr, MkdirOptions as xt, BackendStatus as y, SandboxFleetPolicy as yn, AgentProfileMcpServer as yr, McpServerConfig as yt, DownloadOptions as z, SandboxUser as zn, ProvisionResult as zt };
|