@tangle-network/sandbox 0.1.2 → 0.2.1

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.
@@ -1,3 +1,87 @@
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
1
85
  //#region src/agent-profile.d.ts
2
86
  /**
3
87
  * Provider-neutral agent profile types for public SDK consumers.
@@ -10,6 +94,7 @@
10
94
  * Permission policy value for a capability.
11
95
  */
12
96
  type AgentProfilePermissionValue = "allow" | "ask" | "deny";
97
+ type AgentProfilePermission = AgentProfilePermissionValue | Record<string, AgentProfilePermissionValue>;
13
98
  /**
14
99
  * Generic resource reference that can be resolved into a file or instruction.
15
100
  */
@@ -19,6 +104,11 @@ type AgentProfileResourceRef = {
19
104
  content: string;
20
105
  } | {
21
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;
22
112
  path: string;
23
113
  ref?: string;
24
114
  name?: string;
@@ -31,6 +121,7 @@ declare function defineInlineResource(name: string, content: string): AgentProfi
31
121
  * Helper for creating typed GitHub-backed resource refs.
32
122
  */
33
123
  declare function defineGitHubResource(path: string, options?: {
124
+ repository?: string;
34
125
  ref?: string;
35
126
  name?: string;
36
127
  }): AgentProfileResourceRef;
@@ -44,19 +135,38 @@ interface AgentProfileFileMount {
44
135
  }
45
136
  /**
46
137
  * Provider-neutral resource bundle.
47
- *
48
- * Provider-specific concepts such as "skills" or "commands" should be modeled
49
- * under `extensions` unless they become portable across multiple backends.
50
138
  */
51
139
  interface AgentProfileResources {
52
140
  /**
53
141
  * Generic files to materialize into the agent workspace before execution.
54
142
  */
55
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[];
56
162
  /**
57
163
  * Additional instructions injected into the agent context.
58
164
  */
59
165
  instructions?: string | AgentProfileResourceRef;
166
+ /**
167
+ * Fail initialization when a provider cannot materialize a resource.
168
+ */
169
+ failOnError?: boolean;
60
170
  }
61
171
  /**
62
172
  * Model selection hints for backends.
@@ -100,10 +210,25 @@ interface AgentSubagentProfile {
100
210
  prompt?: string;
101
211
  model?: string;
102
212
  tools?: Record<string, boolean>;
103
- permissions?: Record<string, AgentProfilePermissionValue>;
213
+ permissions?: Record<string, AgentProfilePermission>;
104
214
  maxSteps?: number;
105
215
  metadata?: Record<string, unknown>;
106
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
+ }
107
232
  /**
108
233
  * Confidential-execution options for sandbox backends.
109
234
  *
@@ -153,11 +278,13 @@ interface AgentProfile {
153
278
  tags?: string[];
154
279
  prompt?: AgentProfilePrompt;
155
280
  model?: AgentProfileModelHints;
156
- permissions?: Record<string, AgentProfilePermissionValue>;
281
+ permissions?: Record<string, AgentProfilePermission>;
157
282
  tools?: Record<string, boolean>;
158
283
  mcp?: Record<string, AgentProfileMcpServer>;
159
284
  subagents?: Record<string, AgentSubagentProfile>;
160
285
  resources?: AgentProfileResources;
286
+ hooks?: Record<string, AgentProfileHookCommand[]>;
287
+ modes?: Record<string, AgentProfileMode>;
161
288
  confidential?: AgentProfileConfidential;
162
289
  metadata?: Record<string, unknown>;
163
290
  /**
@@ -186,7 +313,13 @@ interface AgentProfileCapabilities {
186
313
  resources: {
187
314
  files: boolean;
188
315
  instructions: boolean;
316
+ tools?: boolean;
317
+ skills?: boolean;
318
+ agents?: boolean;
319
+ commands?: boolean;
189
320
  };
321
+ hooks?: boolean;
322
+ modes?: boolean;
190
323
  runtimeUpdate: boolean;
191
324
  validation: boolean;
192
325
  /**
@@ -219,6 +352,9 @@ interface AgentProfileValidationResult {
219
352
  declare function mergeAgentProfiles(base: AgentProfile | undefined, overlay: AgentProfile | undefined): AgentProfile | undefined;
220
353
  //#endregion
221
354
  //#region src/types.d.ts
355
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
356
+ [key: string]: JsonValue;
357
+ };
222
358
  /**
223
359
  * A development environment.
224
360
  *
@@ -235,6 +371,61 @@ interface SandboxEnvironment {
235
371
  base?: string;
236
372
  /** Environment version tag */
237
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;
238
429
  }
239
430
  /**
240
431
  * Git authentication configuration.
@@ -357,6 +548,21 @@ interface SandboxClientConfig {
357
548
  baseUrl: string;
358
549
  /** Request timeout in milliseconds. Defaults to 30000 (30 seconds) */
359
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;
360
566
  }
361
567
  /**
362
568
  * Status of a sandbox instance.
@@ -381,7 +587,11 @@ interface SandboxResources {
381
587
  memoryMB?: number;
382
588
  /** Disk space in gigabytes */
383
589
  diskGB?: number;
590
+ /** Accelerator request for GPU-class workloads. */
591
+ accelerator?: SandboxAccelerator;
384
592
  }
593
+ /** @deprecated Use SandboxAccelerator.kind via SandboxResources.accelerator. */
594
+ type GpuType = string;
385
595
  /**
386
596
  * Configuration for creating a new sandbox.
387
597
  *
@@ -566,6 +776,37 @@ interface CreateSandboxOptions {
566
776
  resources?: SandboxResources;
567
777
  /** Environment variables injected into the sandbox */
568
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;
569
810
  /**
570
811
  * Maximum lifetime in seconds.
571
812
  * Sandbox is automatically deleted after this time.
@@ -586,6 +827,10 @@ interface CreateSandboxOptions {
586
827
  sshEnabled?: boolean;
587
828
  /** Custom SSH public key for access (optional) */
588
829
  sshPublicKey?: string;
830
+ /** Custom SSH public keys for access (optional) */
831
+ sshPublicKeys?: string[];
832
+ /** Stored SSH key IDs or names to authorize at creation time */
833
+ sshKeyIds?: string[];
589
834
  /**
590
835
  * Enable web terminal access.
591
836
  * Provides a browser-based terminal via websocket.
@@ -603,6 +848,35 @@ interface CreateSandboxOptions {
603
848
  fromSnapshot?: string;
604
849
  /** Source sandbox ID that owns the snapshot (required when fromSnapshot is set) */
605
850
  fromSandboxId?: string;
851
+ /**
852
+ * Apply a saved template at create time. Templates seed the
853
+ * sandbox with a snapshot, default environment, and config defaults
854
+ * so a team can publish a golden-path starting point once and have
855
+ * every member spin up the same baseline.
856
+ *
857
+ * The template must either be personal (owned by the caller) or
858
+ * belong to a team the caller is an active member of. Explicit
859
+ * fields on this call win over template defaults — so you can layer
860
+ * a one-off override on top of the golden path without forking the
861
+ * template itself.
862
+ *
863
+ * @example
864
+ * ```typescript
865
+ * const box = await client.create({
866
+ * templateId: "tpl_abc123",
867
+ * teamId: "team_...", // optional; sandbox is shared with the team
868
+ * });
869
+ * ```
870
+ */
871
+ templateId?: string;
872
+ /**
873
+ * Create from a published public template by id or slug.
874
+ * The API resolves the latest published version unless
875
+ * `publicTemplateVersionId` is also provided.
876
+ */
877
+ publicTemplateId?: string;
878
+ /** Pin sandbox creation to a specific published public-template version. */
879
+ publicTemplateVersionId?: string;
606
880
  /**
607
881
  * Names of secrets to inject as environment variables.
608
882
  *
@@ -634,17 +908,101 @@ interface CreateSandboxOptions {
634
908
  * (accessible only to the creator).
635
909
  */
636
910
  teamId?: string;
911
+ /**
912
+ * Sidecar capabilities to enable at boot. Each capability boots an
913
+ * additional subsystem inside the sandbox; absent capabilities incur
914
+ * zero startup cost.
915
+ *
916
+ * Currently supported:
917
+ * - `"computer_use"` — boots Xvfb, dbus, AT-SPI, and an MCP server
918
+ * exposing mouse/keyboard/screenshot via the Anthropic + OpenAI
919
+ * Responses computer-use surface. Required if you plan to call
920
+ * {@link SandboxInstance.getMcpAccessToken | `getMcpAccessToken`}
921
+ * with `capabilities: ["computer_use"]`.
922
+ *
923
+ * The capability is enforced at two layers:
924
+ * 1. The sidecar refuses to start if a capability's binaries are
925
+ * missing (computer_use needs the universal Nix profile, which
926
+ * Docker / host-agent / Firecracker drivers ship via the host
927
+ * bind-mount or the universal sidecar image variant; Firecracker
928
+ * host profiles built without the universal flake do not).
929
+ * 2. The MCP token endpoint refuses to mint a `cap: ["computer_use"]`
930
+ * JWT for a sandbox that wasn't created with that capability.
931
+ *
932
+ * **Sizing note:** `computer_use` boots an always-on Xvfb + dbus
933
+ * stack costing roughly **~100 MB resident memory** inside the
934
+ * container. Billing is by reserved capacity (not measured RSS), so
935
+ * this comes out of your sandbox's RAM envelope rather than adding
936
+ * a separate line item. On a 1 GB sandbox that is ~10% of your
937
+ * workload's headroom; bump `resources.memoryMb` to 1.5–2 GB if
938
+ * the agent will run anything memory-hungry alongside it.
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * const box = await client.create({
943
+ * environment: "universal",
944
+ * capabilities: ["computer_use"],
945
+ * });
946
+ * const { token } = await box.getMcpAccessToken({
947
+ * capabilities: ["computer_use"],
948
+ * });
949
+ * ```
950
+ */
951
+ capabilities?: ReadonlyArray<"computer_use">;
952
+ /**
953
+ * Privacy controls for the sandbox. Two independent layers:
954
+ *
955
+ * - **`egress`** — what happens when the sandbox sends a request to a
956
+ * model vendor (Anthropic, OpenAI, your own router, etc.):
957
+ * - `"redact"` — PII spans are masked before the request leaves
958
+ * the sandbox. Emails, JWTs, API keys, credit cards (Luhn-
959
+ * validated), SSNs, phone numbers, IPv4 addresses are caught
960
+ * today; names / postal addresses / DOBs land when the OPF
961
+ * model service is enabled. The agent receives normal
962
+ * responses; the vendor sees masked input.
963
+ * - `"block"` — PII presence fails the egress request closed.
964
+ * For high-compliance flows that prefer fail-closed to leak.
965
+ * - `"off"` — no egress filtering. Default for free tier; opt-in
966
+ * for tasks that genuinely need raw PII (form-filling,
967
+ * customer-support agents reading customer details).
968
+ *
969
+ * - **`logs`** — whether infrastructure logs / telemetry / Sentry
970
+ * redact PII before recording. This is OUR side, not the model
971
+ * vendor's, and there's basically never a reason to leak PII into
972
+ * our own logs. Default `"on"`.
973
+ *
974
+ * Note: privacy controls operate at the boundary between the
975
+ * sandbox and external systems. They do NOT redact contents inside
976
+ * the sandbox workspace itself — files / code / database fixtures
977
+ * the customer puts there are the customer's data and stay
978
+ * unmodified. Snapshots preserve those contents verbatim.
979
+ *
980
+ * @example
981
+ * ```typescript
982
+ * const box = await client.create({
983
+ * privacy: { egress: "redact", logs: "on" },
984
+ * });
985
+ * ```
986
+ */
987
+ privacy?: {
988
+ egress?: "redact" | "block" | "off";
989
+ logs?: "on" | "off";
990
+ };
637
991
  }
638
992
  /**
639
993
  * SSH connection credentials.
640
994
  */
641
995
  interface SSHCredentials {
642
- /** SSH server hostname */
643
- host: string;
644
- /** SSH server port */
645
- port: number;
646
996
  /** Username for SSH authentication */
647
997
  username: string;
998
+ /** SSH server port */
999
+ port: number;
1000
+ /** ProxyCommand for sandbox API tunnel-based SSH. */
1001
+ proxyCommand: string;
1002
+ }
1003
+ interface SSHCommandDescriptor {
1004
+ command: string;
1005
+ env: Record<string, string>;
648
1006
  }
649
1007
  /**
650
1008
  * Connection information for a sandbox.
@@ -799,7 +1157,7 @@ interface ExecOptions {
799
1157
  *
800
1158
  * @example Search TypeScript files
801
1159
  * ```typescript
802
- * const matches = await box.search("TODO", {
1160
+ * const matches = await box.search("export function", {
803
1161
  * glob: "**\/*.ts",
804
1162
  * maxResults: 100,
805
1163
  * });
@@ -974,6 +1332,21 @@ interface PromptOptions {
974
1332
  context?: Record<string, unknown>;
975
1333
  /** AbortSignal for cancellation */
976
1334
  signal?: AbortSignal;
1335
+ /**
1336
+ * Stable execution id for cross-process reconnect. When passed, the same
1337
+ * id on a retry lands on the same substrate execution — the orchestrator
1338
+ * replays its buffered event stream instead of spawning a duplicate run.
1339
+ * Forwarded as the `X-Execution-ID` header. Omit to let the SDK extract
1340
+ * one from the response stream's `execution.started` event (in-call
1341
+ * reconnect only).
1342
+ */
1343
+ executionId?: string;
1344
+ /**
1345
+ * Last event id the caller has already acknowledged. The substrate
1346
+ * replays strictly after this id on reconnect. Forwarded as the
1347
+ * `Last-Event-ID` header. Omit on first attempt.
1348
+ */
1349
+ lastEventId?: string;
977
1350
  }
978
1351
  /**
979
1352
  * SSE event from sandbox streaming.
@@ -986,6 +1359,142 @@ interface SandboxEvent {
986
1359
  /** Event ID */
987
1360
  id?: string;
988
1361
  }
1362
+ interface SandboxTraceEvent {
1363
+ type: "sandbox.lifecycle.snapshot" | "sandbox.runtime.snapshot" | "sandbox.usage.snapshot" | "sandbox.insight.summary";
1364
+ timestamp: string;
1365
+ sandboxId: string;
1366
+ durationMs?: number;
1367
+ attributes: Record<string, unknown>;
1368
+ }
1369
+ interface SandboxTraceExport {
1370
+ schemaVersion: "sandbox.trace.v1";
1371
+ traceId: string;
1372
+ sandboxId: string;
1373
+ exportedAt: string;
1374
+ timings: {
1375
+ observedLifecycleMs: number;
1376
+ observedRuntimeMs: number;
1377
+ idleObservedMs: number;
1378
+ };
1379
+ criticalPath: {
1380
+ durationMs: number;
1381
+ phases: Array<{
1382
+ name: string;
1383
+ durationMs: number;
1384
+ }>;
1385
+ };
1386
+ events: SandboxTraceEvent[];
1387
+ }
1388
+ interface SandboxIntelligenceEnvelope {
1389
+ schemaVersion: "sandbox.intelligence.v1";
1390
+ source: "sandbox-api";
1391
+ subject: {
1392
+ type: "sandbox";
1393
+ sandboxId: string;
1394
+ };
1395
+ billing: {
1396
+ billable: false;
1397
+ billedTo: "platform";
1398
+ costUsd: 0;
1399
+ reason: "deterministic_platform_insight";
1400
+ };
1401
+ metrics: Record<string, number>;
1402
+ signals: Array<{
1403
+ name: string;
1404
+ value: string | number | boolean;
1405
+ severity: "info" | "warn" | "critical";
1406
+ rationale: string;
1407
+ }>;
1408
+ recommendedActions: string[];
1409
+ }
1410
+ interface SandboxTraceBundle {
1411
+ trace: SandboxTraceExport;
1412
+ intelligence?: SandboxIntelligenceEnvelope;
1413
+ }
1414
+ interface SandboxTraceOptions {
1415
+ /**
1416
+ * Include the platform-generated intelligence envelope. Defaults to false.
1417
+ * Set true when a customer wants generated insight with the raw trace export.
1418
+ */
1419
+ includeIntelligence?: boolean;
1420
+ }
1421
+ /**
1422
+ * Subject types for an Intelligence Report.
1423
+ *
1424
+ * - `sandbox`: one container's run.
1425
+ * - `fleet`: one managed grouping of sandboxes. Add `subject.dispatchId`
1426
+ * to narrow to a single coordinated command within the fleet
1427
+ * (previously a standalone `dispatch` subject type — now expressed
1428
+ * as a fleet refinement).
1429
+ */
1430
+ type IntelligenceReportSubjectType = "sandbox" | "fleet";
1431
+ interface IntelligenceReport {
1432
+ jobId: string;
1433
+ subject: {
1434
+ type: IntelligenceReportSubjectType;
1435
+ id: string; /** Present when the report was narrowed to a single fleet dispatch. */
1436
+ dispatchId?: string;
1437
+ };
1438
+ mode: "deterministic" | "agentic";
1439
+ status: "queued" | "running" | "completed" | "failed";
1440
+ billing: {
1441
+ billable: boolean;
1442
+ billedTo: "platform" | "customer";
1443
+ costUsd: number;
1444
+ reason: string;
1445
+ budgetMaxUsd?: number;
1446
+ };
1447
+ result: Record<string, unknown> | null;
1448
+ error?: string;
1449
+ createdAt: string;
1450
+ updatedAt: string;
1451
+ completedAt?: string;
1452
+ }
1453
+ interface IntelligenceReportBudget {
1454
+ maxUsd?: number;
1455
+ billTo?: "customer" | "platform";
1456
+ }
1457
+ /**
1458
+ * Time window for an intelligence report. Both bounds are millisecond
1459
+ * epochs. Omit `since` to mean "from the subject's first observation";
1460
+ * omit `until` to mean "now". `since` must be <= `until` when both are
1461
+ * set; the server enforces this at the schema layer.
1462
+ */
1463
+ interface IntelligenceReportWindow {
1464
+ since?: number;
1465
+ until?: number;
1466
+ }
1467
+ /**
1468
+ * Comparison baseline. When present, the report includes an explicit
1469
+ * delta between the primary subject and this baseline. Must be the
1470
+ * same `type` as the primary subject — the analyzer rejects mixed
1471
+ * subject-type comparisons because the delta would be meaningless.
1472
+ *
1473
+ * `dispatchId` is only valid when `type === "fleet"`.
1474
+ */
1475
+ interface IntelligenceReportCompareTo {
1476
+ type: IntelligenceReportSubjectType;
1477
+ id: string;
1478
+ /** Narrow the baseline to a single dispatch within the fleet. */
1479
+ dispatchId?: string;
1480
+ }
1481
+ interface CreateIntelligenceReportOptions {
1482
+ subject: {
1483
+ type: IntelligenceReportSubjectType;
1484
+ id: string;
1485
+ /**
1486
+ * Narrow the analysis to a single coordinated command within a
1487
+ * fleet. Only valid when `type === "fleet"`.
1488
+ */
1489
+ dispatchId?: string; /** Bound the analysis to a time window. */
1490
+ window?: IntelligenceReportWindow; /** Compare the primary subject against a same-type baseline. */
1491
+ compareTo?: IntelligenceReportCompareTo;
1492
+ };
1493
+ mode?: "deterministic" | "agentic";
1494
+ acknowledgeCost?: boolean;
1495
+ budget?: IntelligenceReportBudget;
1496
+ metadata?: Record<string, unknown>;
1497
+ }
989
1498
  /**
990
1499
  * Options for event streaming.
991
1500
  */
@@ -1089,7 +1598,9 @@ interface SubscriptionInfo {
1089
1598
  *
1090
1599
  * **May be negative** for overage-enabled plans (pro/enterprise):
1091
1600
  * overage charges can push the stored balance below zero. Free-tier
1092
- * plans cap at 0 at the charge path (`capAtZero: true`).
1601
+ * plans floor at 0 at the charge path free users top up their
1602
+ * prepaid balance via Stripe Checkout (`POST /v1/billing/topup`,
1603
+ * issue #874) when they hit zero rather than going into the red.
1093
1604
  *
1094
1605
  * Freshness semantics differ by deployment backend: the
1095
1606
  * Cloudflare/D1 backend includes real-time projected cost of
@@ -1193,6 +1704,120 @@ interface TaskResult extends PromptResult {
1193
1704
  /** Session ID for the task (can be used to continue) */
1194
1705
  sessionId: string;
1195
1706
  }
1707
+ /**
1708
+ * Lifecycle state of an agent session inside a sandbox.
1709
+ */
1710
+ type SessionStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
1711
+ /**
1712
+ * Snapshot of a session's state at the moment it was queried. Returned
1713
+ * by `box.session(id).status()` and `box.sessions()`.
1714
+ */
1715
+ interface SessionInfo {
1716
+ /** Stable session id assigned by the sandbox runtime. */
1717
+ id: string;
1718
+ /** Current lifecycle state. */
1719
+ status: SessionStatus;
1720
+ /** Backend identifier (e.g. provider name). */
1721
+ backend?: string;
1722
+ /** Model id the session was created with. */
1723
+ model?: string;
1724
+ /** Number of prompts the session has processed. */
1725
+ promptCount?: number;
1726
+ /** When the session was created in the sandbox. */
1727
+ createdAt?: Date;
1728
+ /** When the session began executing. */
1729
+ startedAt?: Date;
1730
+ /** When the session reached a terminal state. */
1731
+ endedAt?: Date;
1732
+ /** Raw payload from the sidecar — stable subset above; this carries
1733
+ * everything else for forward-compatibility. */
1734
+ raw?: Record<string, unknown>;
1735
+ }
1736
+ /**
1737
+ * Options for `box.sessions()` listing.
1738
+ */
1739
+ interface SessionListOptions {
1740
+ /** Filter by status. */
1741
+ status?: SessionStatus;
1742
+ /** Filter by backend identifier. */
1743
+ backend?: string;
1744
+ }
1745
+ /**
1746
+ * Options for `SandboxSession.events()` streaming.
1747
+ */
1748
+ interface SessionEventStreamOptions {
1749
+ /** Replay starting from this event id (inclusive). Omit to start at
1750
+ * the live tail. Useful for reconnect-after-disconnect flows. */
1751
+ since?: string;
1752
+ /** Cancel the stream by aborting this signal. */
1753
+ signal?: AbortSignal;
1754
+ }
1755
+ /**
1756
+ * Options for `box.dispatchPrompt()` — fire-and-detach prompt semantics.
1757
+ */
1758
+ interface DispatchPromptOptions extends PromptOptions {
1759
+ /** Client-supplied session id for idempotency. Re-dispatching with
1760
+ * the same id while the session is running is a lookup, not a
1761
+ * re-create. Lets queue retries and reconnect-after-restart be safe
1762
+ * by construction. */
1763
+ sessionId?: string;
1764
+ }
1765
+ /**
1766
+ * Returned by `box.dispatchPrompt()` — minimum the caller needs to track
1767
+ * the session afterward. The sandbox keeps running the prompt; use
1768
+ * `box.session(sessionId)` to follow it.
1769
+ */
1770
+ interface DispatchedSession {
1771
+ /** Session id (either the one the caller supplied or one the sandbox
1772
+ * minted). */
1773
+ sessionId: string;
1774
+ /** Lifecycle state at the moment dispatch returned. */
1775
+ status: SessionStatus;
1776
+ /** True when an existing session with the supplied id was found and
1777
+ * dispatch was a no-op (idempotency). */
1778
+ alreadyExisted: boolean;
1779
+ }
1780
+ /**
1781
+ * Scope of a `box.mintScopedToken()` request. Each value narrows the
1782
+ * token's authority compared to the full sandbox bearer.
1783
+ */
1784
+ type ScopedTokenScope = "session" | "project" | "read-only";
1785
+ /**
1786
+ * Options for `box.mintScopedToken()`.
1787
+ */
1788
+ interface MintScopedTokenOptions {
1789
+ /** Scope to mint. `session` narrows to a single session id; `project`
1790
+ * grants read access to the whole sandbox; `read-only` is a project
1791
+ * scope without prompt-dispatch capabilities. */
1792
+ scope: ScopedTokenScope;
1793
+ /** Required when `scope === "session"`. */
1794
+ sessionId?: string;
1795
+ /** TTL in minutes. Default 5; clamped to [1, 15]. Browser-side
1796
+ * bearers must be short-lived; pair with `client.onTokenRefresh()`
1797
+ * for long-running consumers. */
1798
+ ttlMinutes?: number;
1799
+ }
1800
+ /**
1801
+ * Returned by `box.mintScopedToken()`. The token verifies against the
1802
+ * same sidecar middleware that already gates ProductTokenIssuer-issued
1803
+ * JWTs — no new sidecar surface.
1804
+ */
1805
+ interface ScopedToken {
1806
+ /** Bearer token (JWT). Send as `Authorization: Bearer <token>` or
1807
+ * via the `EventSource` URL with token query param. */
1808
+ token: string;
1809
+ /** When the token expires. */
1810
+ expiresAt: Date;
1811
+ /** Echo of the requested scope. */
1812
+ scope: ScopedTokenScope;
1813
+ }
1814
+ /**
1815
+ * Callback invoked when the SDK refreshes a sandbox bearer transparently
1816
+ * (e.g. after a 401 retry against the runtime endpoint). Lets long-
1817
+ * running consumers propagate the new token to dependents (live
1818
+ * `EventSource` connections, browser-side caches, etc.).
1819
+ */
1820
+ type TokenRefreshHandler = (sandboxId: string, newToken: string) => void;
1196
1821
  /**
1197
1822
  * Options for creating a snapshot.
1198
1823
  */
@@ -1268,6 +1893,8 @@ interface BatchOptions {
1268
1893
  backend?: Partial<BackendConfig>;
1269
1894
  /** Keep sandboxes alive after completion (default: false) */
1270
1895
  persistent?: boolean;
1896
+ /** Milliseconds to keep non-persistent batch sandboxes alive after completion. */
1897
+ graceMs?: number;
1271
1898
  /**
1272
1899
  * AbortSignal to cancel the batch mid-stream. When aborted, the HTTP
1273
1900
  * request to `/batch/run` is torn down; the SSE generator stops
@@ -1332,6 +1959,524 @@ interface BatchEvent {
1332
1959
  */
1333
1960
  id?: string;
1334
1961
  }
1962
+ /**
1963
+ * Stable worker identifier inside a sandbox fleet.
1964
+ *
1965
+ * Machine IDs are intentionally narrower than sandbox names so agents
1966
+ * can route work without smuggling shell metacharacters or path-like
1967
+ * values through tool calls.
1968
+ */
1969
+ type FleetMachineId = string;
1970
+ type SandboxFleetMachineRole = "coordinator" | "worker";
1971
+ /**
1972
+ * Resource policy for a single fleet create call.
1973
+ *
1974
+ * These caps are enforced client-side before any sandbox is created.
1975
+ * Server-side plan quotas still apply and remain the source of truth.
1976
+ */
1977
+ interface SandboxFleetPolicy {
1978
+ /** Maximum number of machines in this create call. Defaults to machines.length. */
1979
+ maxMachines?: number;
1980
+ /** Maximum sandbox create fanout allowed for this fleet request. */
1981
+ maxConcurrentCreates?: number;
1982
+ /** Maximum total requested CPU cores across machines with explicit resources. */
1983
+ maxTotalCpu?: number;
1984
+ /** Maximum total requested memory across machines with explicit resources. */
1985
+ maxTotalMemoryMb?: number;
1986
+ /** Maximum total requested storage across machines with explicit resources. */
1987
+ maxTotalStorageMb?: number;
1988
+ /** Maximum total requested accelerator devices across machines. */
1989
+ maxTotalAccelerators?: number;
1990
+ /** Maximum lifetime in seconds for any machine in this fleet. */
1991
+ maxLifetimeSeconds?: number;
1992
+ /** Maximum estimated USD spend for the fleet's configured lifetime. */
1993
+ maxSpendUsd?: number;
1994
+ /** Allowed infrastructure drivers for fleet machines. */
1995
+ allowedDrivers?: DriverType[];
1996
+ /** Allowed images/environments for fleet machines. */
1997
+ allowedImages?: string[];
1998
+ /** Allowed personal or public template identifiers for fleet machines. */
1999
+ allowedTemplateIds?: string[];
2000
+ /** Whether machines may request accelerator devices. Defaults to allowed. */
2001
+ allowAccelerators?: boolean;
2002
+ }
2003
+ interface SandboxFleetWorkspace {
2004
+ mode: "isolated" | "shared";
2005
+ id?: string;
2006
+ quotaMb?: number;
2007
+ mountPath?: string;
2008
+ snapshotId?: string;
2009
+ }
2010
+ /**
2011
+ * Per-machine create spec for a sandbox fleet.
2012
+ */
2013
+ interface SandboxFleetMachineSpec extends Omit<CreateSandboxOptions, "metadata" | "name"> {
2014
+ /** Stable agent-facing machine id, e.g. "coordinator" or "worker-1". */
2015
+ machineId: FleetMachineId;
2016
+ /** Optional display name. Defaults to `${fleetId}-${machineId}`. */
2017
+ name?: string;
2018
+ /** Machine-specific metadata. Fleet tags are added automatically. */
2019
+ metadata?: Record<string, unknown>;
2020
+ /** Optional orchestration role. Defaults to worker. */
2021
+ role?: SandboxFleetMachineRole;
2022
+ }
2023
+ /**
2024
+ * Create a named set of sandboxes for one workload.
2025
+ */
2026
+ interface CreateSandboxFleetOptions {
2027
+ /** Stable fleet id. Generated when omitted. */
2028
+ fleetId?: string;
2029
+ /** Shared defaults applied to every machine before per-machine overrides. */
2030
+ defaults?: Omit<CreateSandboxOptions, "metadata" | "name">;
2031
+ /** Machines to create. */
2032
+ machines: SandboxFleetMachineSpec[];
2033
+ /** Fleet-level metadata copied to each sandbox under stable tags. */
2034
+ metadata?: Record<string, unknown>;
2035
+ /** Workspace policy for isolated or driver-supported shared mounts. */
2036
+ workspace?: SandboxFleetWorkspace;
2037
+ /**
2038
+ * Client-side safety caps for this create call. These do not replace
2039
+ * server-side quota enforcement.
2040
+ */
2041
+ policy?: SandboxFleetPolicy;
2042
+ /**
2043
+ * Delete already-created machines if a later machine fails to create.
2044
+ * Defaults to true so partial fleets do not silently burn quota.
2045
+ */
2046
+ cleanupOnFailure?: boolean;
2047
+ /**
2048
+ * Maximum concurrent sandbox creates for this fleet request.
2049
+ * Defaults to 4 to avoid accidental control-plane stampedes while still
2050
+ * provisioning worker fleets faster than serial creation.
2051
+ */
2052
+ maxConcurrentCreates?: number;
2053
+ /**
2054
+ * Idempotency key for the server-backed fleet record. Defaults to fleetId.
2055
+ */
2056
+ idempotencyKey?: string;
2057
+ }
2058
+ interface CreateSandboxFleetWithCoordinatorOptions extends Omit<CreateSandboxFleetOptions, "machines"> {
2059
+ /** Coordinator machine. Defaults to machineId "coordinator". */
2060
+ coordinator?: Omit<SandboxFleetMachineSpec, "machineId" | "role"> & {
2061
+ machineId?: FleetMachineId;
2062
+ };
2063
+ /** Worker machines attached to the same fleet. */
2064
+ workers: SandboxFleetMachineSpec[];
2065
+ }
2066
+ /**
2067
+ * A sandbox with its fleet-local machine id.
2068
+ */
2069
+ interface SandboxFleetMachine {
2070
+ machineId: FleetMachineId;
2071
+ sandbox: SandboxInfo;
2072
+ role?: SandboxFleetMachineRole;
2073
+ }
2074
+ /**
2075
+ * Fleet create/list result.
2076
+ */
2077
+ interface SandboxFleetInfo {
2078
+ fleetId: string;
2079
+ machines: SandboxFleetMachine[];
2080
+ }
2081
+ interface FleetExecDispatchOptions extends Pick<ExecOptions, "cwd" | "env" | "timeoutMs"> {
2082
+ machines?: FleetMachineId[];
2083
+ maxConcurrent?: number;
2084
+ retry?: {
2085
+ attempts?: number;
2086
+ };
2087
+ /** Caller-supplied dispatch id for idempotency/result lookup when supported by the API. */
2088
+ dispatchId?: string;
2089
+ /** Ask the API to retain branch results for later `dispatchResults` calls. */
2090
+ bufferResults?: boolean;
2091
+ }
2092
+ interface FleetExecDispatchResult {
2093
+ machineId: FleetMachineId;
2094
+ sandboxId: string;
2095
+ ok: boolean;
2096
+ durationMs: number;
2097
+ attempts?: number;
2098
+ result?: ExecResult;
2099
+ error?: {
2100
+ message: string;
2101
+ status?: number;
2102
+ failureClass?: SandboxFleetDispatchFailureClass;
2103
+ };
2104
+ }
2105
+ interface FleetPromptDispatchOptions extends Pick<PromptOptions, "sessionId" | "model" | "backend" | "timeoutMs" | "context"> {
2106
+ machines?: FleetMachineId[];
2107
+ maxConcurrent?: number;
2108
+ retry?: {
2109
+ attempts?: number;
2110
+ };
2111
+ /** Caller-supplied dispatch id for idempotency/result lookup when supported by the API. */
2112
+ dispatchId?: string;
2113
+ /** Ask the API to retain branch results for later `dispatchResults` calls. */
2114
+ bufferResults?: boolean;
2115
+ }
2116
+ interface FleetPromptDispatchResult {
2117
+ machineId: FleetMachineId;
2118
+ sandboxId: string;
2119
+ ok: boolean;
2120
+ durationMs: number;
2121
+ attempts?: number;
2122
+ prompt?: PromptResult & {
2123
+ metadata?: Record<string, unknown>;
2124
+ };
2125
+ error?: {
2126
+ message: string;
2127
+ status?: number;
2128
+ failureClass?: SandboxFleetDispatchFailureClass;
2129
+ };
2130
+ }
2131
+ type SandboxFleetDispatchFailureClass = "oom" | "timeout" | "dependency" | "infra" | "model" | "user_code";
2132
+ interface FleetDispatchStreamOptions {
2133
+ signal?: AbortSignal;
2134
+ }
2135
+ interface FleetDispatchResultBufferOptions {
2136
+ cursor?: string;
2137
+ limit?: number;
2138
+ machines?: FleetMachineId[];
2139
+ }
2140
+ interface FleetDispatchResultBuffer<T = FleetExecDispatchResult | FleetPromptDispatchResult> {
2141
+ fleetId: string;
2142
+ dispatchId: string;
2143
+ results: T[];
2144
+ cursor?: string;
2145
+ nextCursor?: string;
2146
+ done?: boolean;
2147
+ truncated?: boolean;
2148
+ trace?: SandboxFleetTraceExport;
2149
+ intelligence?: SandboxFleetIntelligenceEnvelope;
2150
+ }
2151
+ interface FleetDispatchCancelResult {
2152
+ fleetId: string;
2153
+ dispatchId: string;
2154
+ cancelled: boolean;
2155
+ status?: string;
2156
+ }
2157
+ interface SandboxFleetArtifactSpec {
2158
+ machineId: FleetMachineId;
2159
+ /**
2160
+ * Absolute path under /workspace. Fleet artifact collection intentionally
2161
+ * rejects host/system paths so caller-provided manifests cannot turn artifact
2162
+ * collection into arbitrary sandbox file reads.
2163
+ */
2164
+ path: string;
2165
+ label?: string;
2166
+ /** Maximum allowed artifact content size in bytes. Defaults to 5 MiB. */
2167
+ maxBytes?: number;
2168
+ }
2169
+ interface SandboxFleetArtifact extends SandboxFleetArtifactSpec {
2170
+ sandboxId: string;
2171
+ content: string;
2172
+ }
2173
+ interface SandboxFleetDriverTimings {
2174
+ queueMs?: number;
2175
+ placementMs?: number;
2176
+ provisionMs?: number;
2177
+ startupMs?: number;
2178
+ cleanupMs?: number;
2179
+ }
2180
+ interface SandboxFleetMachineMeteredUsage {
2181
+ runtimeMs: number;
2182
+ updatedAt: string;
2183
+ }
2184
+ interface AttachSandboxFleetMachineOptions {
2185
+ machineId: FleetMachineId;
2186
+ sandboxId: string;
2187
+ status?: string;
2188
+ role?: SandboxFleetMachineRole;
2189
+ driverType?: DriverType;
2190
+ image?: string;
2191
+ environment?: string;
2192
+ templateId?: string;
2193
+ publicTemplateId?: string;
2194
+ acceleratorCount?: number;
2195
+ driverTimings?: SandboxFleetDriverTimings;
2196
+ }
2197
+ interface SandboxFleetMachineRecord extends AttachSandboxFleetMachineOptions {
2198
+ workspaceMountPath?: string;
2199
+ meteredUsage?: SandboxFleetMachineMeteredUsage;
2200
+ createdAt?: string;
2201
+ updatedAt?: string;
2202
+ }
2203
+ interface SandboxFleetManifestMachine {
2204
+ machineId: FleetMachineId;
2205
+ sandboxId: string;
2206
+ role?: SandboxFleetMachineRole;
2207
+ status?: string;
2208
+ driverType?: DriverType;
2209
+ image?: string;
2210
+ environment?: string;
2211
+ templateId?: string;
2212
+ publicTemplateId?: string;
2213
+ acceleratorCount?: number;
2214
+ workspaceMountPath?: string;
2215
+ driverTimings?: SandboxFleetDriverTimings;
2216
+ meteredUsage?: SandboxFleetMachineMeteredUsage;
2217
+ createdAt?: string;
2218
+ updatedAt?: string;
2219
+ }
2220
+ interface SandboxFleetManifest {
2221
+ fleetId?: string;
2222
+ id?: string;
2223
+ metadata?: Record<string, unknown>;
2224
+ policy?: SandboxFleetPolicy;
2225
+ resources?: Record<string, unknown>;
2226
+ workspace?: SandboxFleetWorkspace & {
2227
+ status?: string;
2228
+ createdAt?: string;
2229
+ updatedAt?: string;
2230
+ deletedAt?: string;
2231
+ };
2232
+ machines: SandboxFleetManifestMachine[];
2233
+ createdAt?: string;
2234
+ updatedAt?: string;
2235
+ }
2236
+ interface SandboxFleetDispatchResponse<T = FleetExecDispatchResult | FleetPromptDispatchResult> {
2237
+ fleetId: string;
2238
+ dispatchId: string;
2239
+ type: "exec" | "prompt";
2240
+ results: T[];
2241
+ durationMs: number;
2242
+ trace?: SandboxFleetTraceExport;
2243
+ intelligence?: SandboxFleetIntelligenceEnvelope;
2244
+ }
2245
+ interface SandboxFleetWorkspaceSnapshotResult {
2246
+ snapshotId?: string;
2247
+ id?: string;
2248
+ status?: string;
2249
+ createdAt?: string;
2250
+ [key: string]: JsonValue | undefined;
2251
+ }
2252
+ interface SandboxFleetWorkspaceRestoreResult {
2253
+ restored?: boolean;
2254
+ snapshotId?: string;
2255
+ status?: string;
2256
+ [key: string]: JsonValue | undefined;
2257
+ }
2258
+ interface SandboxFleetWorkspaceReconcileResult {
2259
+ fleetId: string;
2260
+ workspaceId?: string;
2261
+ checked: number;
2262
+ orphanedMounts: number;
2263
+ machines: Array<{
2264
+ machineId: string;
2265
+ sandboxId: string;
2266
+ mounted: boolean;
2267
+ }>;
2268
+ }
2269
+ interface SandboxFleetDriverCapability {
2270
+ driverType: DriverType;
2271
+ sharedWorkspace: boolean;
2272
+ accelerators: boolean;
2273
+ queueTimings: boolean;
2274
+ }
2275
+ interface SandboxFleetOperationsSummary {
2276
+ capacity: {
2277
+ fleets: number;
2278
+ machines: number;
2279
+ runningMachines: number;
2280
+ failedMachines: number;
2281
+ requestedCpu: number;
2282
+ requestedMemoryMb: number;
2283
+ requestedStorageMb: number;
2284
+ requestedAccelerators: number;
2285
+ };
2286
+ alerts: Array<{
2287
+ name: string;
2288
+ severity: "info" | "warn" | "critical";
2289
+ fleetId?: string;
2290
+ machineId?: string;
2291
+ message: string;
2292
+ runbook: string[];
2293
+ }>;
2294
+ }
2295
+ interface ReconcileSandboxFleetsOptions {
2296
+ dryRun?: boolean;
2297
+ }
2298
+ interface ReconcileSandboxFleetsResult {
2299
+ dryRun: boolean;
2300
+ checked: number;
2301
+ orphaned: number;
2302
+ removed: number;
2303
+ machines: Array<{
2304
+ fleetId: string;
2305
+ machineId: string;
2306
+ sandboxId: string;
2307
+ removed: boolean;
2308
+ status?: number;
2309
+ error?: string;
2310
+ }>;
2311
+ }
2312
+ interface SandboxFleetUsage {
2313
+ usage: {
2314
+ fleetId: string;
2315
+ status: string;
2316
+ machineCount: number;
2317
+ coordinatorCount: number;
2318
+ workerCount: number;
2319
+ runningMachines: number;
2320
+ failedMachines: number;
2321
+ resources?: {
2322
+ machines: number;
2323
+ totalCpu: number;
2324
+ totalMemoryMb: number;
2325
+ totalStorageMb: number;
2326
+ totalAccelerators: number;
2327
+ maxLifetimeSeconds?: number;
2328
+ };
2329
+ meteredUsage?: {
2330
+ runtimeMs: number;
2331
+ machineRuntimeMs: Record<string, number>;
2332
+ updatedAt: string;
2333
+ };
2334
+ createdAt: string;
2335
+ updatedAt: string;
2336
+ };
2337
+ insights: {
2338
+ reliabilityScore: number;
2339
+ parallelismEfficiencyScore: number;
2340
+ failureRate: number;
2341
+ recommendedActions: string[];
2342
+ };
2343
+ trace: SandboxFleetTraceExport;
2344
+ intelligence: SandboxFleetIntelligenceEnvelope;
2345
+ }
2346
+ interface SandboxFleetTraceEvent {
2347
+ type: "fleet.lifecycle.snapshot" | "fleet.machine.lifecycle.snapshot" | "fleet.workspace.lifecycle.snapshot" | "fleet.usage.snapshot" | "fleet.dispatch.result" | "fleet.insight.summary";
2348
+ timestamp: string;
2349
+ fleetId: string;
2350
+ machineId?: string;
2351
+ durationMs?: number;
2352
+ attributes: Record<string, unknown>;
2353
+ }
2354
+ interface SandboxFleetTraceExport {
2355
+ schemaVersion: "fleet.trace.v1";
2356
+ traceId: string;
2357
+ fleetId: string;
2358
+ exportedAt: string;
2359
+ timings: {
2360
+ observedLifecycleMs: number;
2361
+ machineObservedLifecycleMs: number;
2362
+ dispatchFanoutMs: number;
2363
+ dispatchRuntimeMs: number;
2364
+ cleanupObservedMs: number;
2365
+ driverQueueMs: number;
2366
+ driverPlacementMs: number;
2367
+ driverProvisionMs: number;
2368
+ driverStartupMs: number;
2369
+ driverCleanupMs: number;
2370
+ };
2371
+ criticalPath: {
2372
+ durationMs: number;
2373
+ phases: Array<{
2374
+ name: string;
2375
+ durationMs: number;
2376
+ machineId?: string;
2377
+ }>;
2378
+ };
2379
+ events: SandboxFleetTraceEvent[];
2380
+ }
2381
+ interface SandboxFleetIntelligenceEnvelope {
2382
+ schemaVersion: "fleet.intelligence.v1";
2383
+ source: "sandbox-api";
2384
+ subject: {
2385
+ type: "sandbox_fleet";
2386
+ fleetId: string;
2387
+ };
2388
+ billing: {
2389
+ billable: false;
2390
+ billedTo: "platform";
2391
+ costUsd: 0;
2392
+ reason: "deterministic_platform_insight";
2393
+ };
2394
+ metrics: Record<string, number>;
2395
+ signals: Array<{
2396
+ name: string;
2397
+ value: string | number | boolean;
2398
+ severity: "info" | "warn" | "critical";
2399
+ rationale: string;
2400
+ }>;
2401
+ recommendedActions: string[];
2402
+ }
2403
+ interface SandboxFleetTraceBundle {
2404
+ trace: SandboxFleetTraceExport;
2405
+ intelligence?: SandboxFleetIntelligenceEnvelope;
2406
+ }
2407
+ interface SandboxFleetTraceOptions {
2408
+ /**
2409
+ * Include the platform-generated intelligence envelope. Defaults to false.
2410
+ * Set true when a customer wants generated insight with the raw trace export.
2411
+ */
2412
+ includeIntelligence?: boolean;
2413
+ }
2414
+ interface SandboxFleetCostEstimate {
2415
+ plan: "free" | "pro" | "enterprise";
2416
+ currency: "USD";
2417
+ hourlyUsd: number;
2418
+ maxLifetimeSeconds: number;
2419
+ estimatedMaxLifetimeUsd: number;
2420
+ requestedResources: {
2421
+ machines: number;
2422
+ totalCpu: number;
2423
+ totalMemoryMb: number;
2424
+ totalStorageMb: number;
2425
+ totalAccelerators: number;
2426
+ maxLifetimeSeconds?: number;
2427
+ };
2428
+ rates: {
2429
+ cpuPerHr: number;
2430
+ ramPerGbHr: number;
2431
+ diskPerGbHr: number;
2432
+ acceleratorPerDeviceHr: number;
2433
+ minChargePerHr: number;
2434
+ entDiscount: number;
2435
+ };
2436
+ }
2437
+ type SandboxFleetTokenAction = "list" | "create" | "delete" | "exec" | "prompt" | "read" | "write";
2438
+ interface CreateSandboxFleetTokenOptions {
2439
+ /** Allowed fleet actions. Defaults to read/list/exec. */
2440
+ actions?: SandboxFleetTokenAction[];
2441
+ /** Optional token-side policy caps enforced by the Sandbox API. */
2442
+ policy?: SandboxFleetPolicy;
2443
+ /** Token lifetime in minutes. API clamps to its server-side maximum. */
2444
+ ttlMinutes?: number;
2445
+ }
2446
+ interface SandboxFleetToken {
2447
+ token: string;
2448
+ expiresAt: number;
2449
+ fleetId: string;
2450
+ actions: SandboxFleetTokenAction[];
2451
+ policy?: SandboxFleetPolicy;
2452
+ }
2453
+ interface ReapExpiredSandboxFleetsOptions {
2454
+ dryRun?: boolean;
2455
+ }
2456
+ interface ReapExpiredSandboxFleetsResult {
2457
+ dryRun: boolean;
2458
+ expired: number;
2459
+ deleted: number;
2460
+ fleets: Array<{
2461
+ fleetId: string;
2462
+ expiredAt: string;
2463
+ deleted: boolean;
2464
+ machines: Array<{
2465
+ machineId: string;
2466
+ sandboxId: string;
2467
+ ok: boolean;
2468
+ status?: number;
2469
+ error?: string;
2470
+ }>;
2471
+ }>;
2472
+ }
2473
+ /**
2474
+ * Options for listing fleet machines.
2475
+ */
2476
+ interface ListSandboxFleetOptions extends ListSandboxOptions {
2477
+ /** Fleet id to filter by. */
2478
+ fleetId: string;
2479
+ }
1335
2480
  /**
1336
2481
  * Options for creating a checkpoint.
1337
2482
  */
@@ -1408,9 +2553,29 @@ interface ForkResult {
1408
2553
  */
1409
2554
  type DriverType = "docker" | "firecracker" | "host-agent" | "tangle";
1410
2555
  /**
1411
- * Accelerator class for GPU-enabled sandboxes.
2556
+ * Accelerator class for GPU-class workloads.
2557
+ *
2558
+ * Examples: `nvidia-h100`, `nvidia-l4`, `nvidia-rtx-4090`, `amd-mi300x`.
2559
+ * Providers can introduce new SKU labels without requiring an SDK release.
2560
+ */
2561
+ type AcceleratorKind = string;
2562
+ /**
2563
+ * Compute accelerator request.
2564
+ *
2565
+ * Accelerators are requested as resources because they are part of workload
2566
+ * shape and billing, not a driver option.
1412
2567
  */
1413
- type GpuType = "nvidia-a100" | "nvidia-h100" | "nvidia-l4" | "amd-mi250";
2568
+ interface SandboxAccelerator {
2569
+ /** Accelerator class required by the workload. */
2570
+ kind: AcceleratorKind;
2571
+ /**
2572
+ * Number of accelerator devices required.
2573
+ * @default 1
2574
+ */
2575
+ count?: number;
2576
+ /** Minimum device memory in megabytes when the exact GPU class is flexible. */
2577
+ memoryMB?: number;
2578
+ }
1414
2579
  /**
1415
2580
  * Infrastructure driver configuration.
1416
2581
  *
@@ -1424,12 +2589,10 @@ type GpuType = "nvidia-a100" | "nvidia-h100" | "nvidia-l4" | "amd-mi250";
1424
2589
  * driver: { type: "firecracker", enableCriu: true }
1425
2590
  * ```
1426
2591
  *
1427
- * @example GPU-enabled sandbox
2592
+ * @example Accelerator-backed sandbox
1428
2593
  * ```typescript
1429
- * driver: {
1430
- * type: "host-agent",
1431
- * gpuRequired: true,
1432
- * gpuType: "nvidia-a100",
2594
+ * resources: {
2595
+ * accelerator: { kind: "nvidia-a100", count: 1 },
1433
2596
  * }
1434
2597
  * ```
1435
2598
  */
@@ -1444,20 +2607,23 @@ interface DriverConfig {
1444
2607
  * Support depends on the selected driver.
1445
2608
  */
1446
2609
  enableCriu?: boolean;
1447
- /** Require a GPU for this sandbox. */
1448
- gpuRequired?: boolean;
1449
- /** Accelerator class preference. */
1450
- gpuType?: GpuType;
1451
- /**
1452
- * Number of GPUs required.
1453
- * @default 1 (when gpuRequired is true)
1454
- */
1455
- gpuCount?: number;
1456
2610
  /**
1457
2611
  * Preferred placement region.
1458
2612
  * e.g., "us-east-1", "eu-west-1".
1459
2613
  */
1460
2614
  preferredRegion?: string;
2615
+ /**
2616
+ * @deprecated Use `resources.accelerator` on sandbox or fleet machine specs.
2617
+ */
2618
+ gpuRequired?: boolean;
2619
+ /**
2620
+ * @deprecated Use `resources.accelerator.kind`.
2621
+ */
2622
+ gpuType?: GpuType;
2623
+ /**
2624
+ * @deprecated Use `resources.accelerator.count`.
2625
+ */
2626
+ gpuCount?: number;
1461
2627
  }
1462
2628
  /**
1463
2629
  * Driver capabilities and status.
@@ -1482,6 +2648,11 @@ interface DriverInfo {
1482
2648
  available: number;
1483
2649
  total: number;
1484
2650
  };
2651
+ acceleratorCapacity?: {
2652
+ available: number;
2653
+ total: number;
2654
+ kinds: AcceleratorKind[];
2655
+ };
1485
2656
  }
1486
2657
  /**
1487
2658
  * Backend type identifier. Controls which AI agent runtime runs inside the sandbox.
@@ -1508,9 +2679,10 @@ interface DriverInfo {
1508
2679
  * - `"acp"` — Agent Client Protocol bridge — fronts any ACP-compliant
1509
2680
  * agent binary (claude-agent-acp, codex-acp, gemini, openclaw acp).
1510
2681
  * Pick the backing agent via config.subAgent.
2682
+ * - `"cursor"` — Cursor Agent SDK local/cloud backend.
1511
2683
  * - `"cli-base"` — Minimal CLI-only (no AI agent).
1512
2684
  */
1513
- type BackendType = "opencode" | "claude-code" | "kimi-code" | "codex" | "amp" | "factory-droids" | "pi" | "hermes" | "forge" | "openclaw" | "acp" | "cli-base";
2685
+ type BackendType = "opencode" | "claude-code" | "kimi-code" | "codex" | "amp" | "factory-droids" | "pi" | "hermes" | "forge" | "openclaw" | "acp" | "cursor" | "cli-base";
1514
2686
  /**
1515
2687
  * MCP (Model Context Protocol) server configuration.
1516
2688
  */
@@ -1643,6 +2815,60 @@ interface BackendInfo {
1643
2815
  tags?: string[];
1644
2816
  }>;
1645
2817
  }
2818
+ interface BackendListOptions {
2819
+ limit?: number;
2820
+ cursor?: string;
2821
+ }
2822
+ interface BackendListResult<TItem> {
2823
+ items: TItem[];
2824
+ nextCursor?: string;
2825
+ }
2826
+ interface BackendAccount {
2827
+ apiKeyName?: string;
2828
+ userId?: number;
2829
+ userEmail?: string;
2830
+ userFirstName?: string;
2831
+ userLastName?: string;
2832
+ createdAt?: string;
2833
+ metadata?: Record<string, unknown>;
2834
+ }
2835
+ interface BackendModel {
2836
+ id: string;
2837
+ displayName?: string;
2838
+ description?: string;
2839
+ parameters?: Array<Record<string, unknown>>;
2840
+ variants?: Array<Record<string, unknown>>;
2841
+ }
2842
+ interface BackendRepository {
2843
+ url: string;
2844
+ }
2845
+ interface BackendAgent {
2846
+ agentId: string;
2847
+ name?: string;
2848
+ summary?: string;
2849
+ lastModified?: number;
2850
+ status?: "running" | "finished" | "error";
2851
+ createdAt?: number;
2852
+ archived?: boolean;
2853
+ runtime?: "local" | "cloud";
2854
+ cwd?: string;
2855
+ env?: Record<string, unknown>;
2856
+ repos?: string[];
2857
+ }
2858
+ interface BackendRun {
2859
+ id: string;
2860
+ agentId?: string;
2861
+ status?: "running" | "finished" | "cancelled" | "error";
2862
+ result?: string;
2863
+ durationMs?: number;
2864
+ model?: Record<string, unknown>;
2865
+ git?: Record<string, unknown>;
2866
+ }
2867
+ interface BackendArtifact {
2868
+ path: string;
2869
+ sizeBytes?: number;
2870
+ updatedAt?: string;
2871
+ }
1646
2872
  /**
1647
2873
  * Network configuration for sandbox network isolation.
1648
2874
  *
@@ -1981,6 +3207,34 @@ interface BackendManager {
1981
3207
  }>>;
1982
3208
  /** Update backend configuration */
1983
3209
  updateConfig(config: Partial<BackendConfig>): Promise<void>;
3210
+ /** Provider account metadata, when exposed by the backend SDK */
3211
+ account(): Promise<BackendAccount>;
3212
+ /** Provider model catalog, when exposed by the backend SDK */
3213
+ models(): Promise<BackendModel[]>;
3214
+ /** Provider repository catalog, when exposed by the backend SDK */
3215
+ repositories(): Promise<BackendRepository[]>;
3216
+ /** Provider-native agent list */
3217
+ agents(options?: BackendListOptions): Promise<BackendListResult<BackendAgent>>;
3218
+ /** Provider-native agent lookup */
3219
+ agent(agentId: string): Promise<BackendAgent>;
3220
+ /** Archive provider-native agent */
3221
+ archiveAgent(agentId: string): Promise<void>;
3222
+ /** Unarchive provider-native agent */
3223
+ unarchiveAgent(agentId: string): Promise<void>;
3224
+ /** Delete provider-native agent */
3225
+ deleteAgent(agentId: string): Promise<void>;
3226
+ /** Provider-native runs for an agent */
3227
+ runs(agentId: string, options?: BackendListOptions): Promise<BackendListResult<BackendRun>>;
3228
+ /** Provider-native run lookup */
3229
+ run(runId: string, options?: {
3230
+ agentId?: string;
3231
+ }): Promise<BackendRun>;
3232
+ /** Provider-native agent messages */
3233
+ agentMessages(agentId: string, options?: BackendListOptions): Promise<unknown>;
3234
+ /** Artifacts for an active backend session */
3235
+ artifacts(sessionId: string): Promise<BackendArtifact[]>;
3236
+ /** Download an artifact from an active backend session */
3237
+ downloadArtifact(sessionId: string, path: string): Promise<Uint8Array>;
1984
3238
  /**
1985
3239
  * Validate a provider-neutral profile against the active backend.
1986
3240
  *
@@ -2248,6 +3502,20 @@ interface SecretInfo {
2248
3502
  /** When the secret was last updated */
2249
3503
  updatedAt: Date;
2250
3504
  }
3505
+ interface SshKeyInfo {
3506
+ id: string;
3507
+ name: string;
3508
+ publicKey: string;
3509
+ fingerprint: string;
3510
+ keyType: string;
3511
+ createdAt: Date;
3512
+ updatedAt: Date;
3513
+ }
3514
+ interface SshKeysManager {
3515
+ create(name: string, publicKey: string): Promise<SshKeyInfo>;
3516
+ list(): Promise<SshKeyInfo[]>;
3517
+ delete(id: string): Promise<void>;
3518
+ }
2251
3519
  /**
2252
3520
  * Secrets manager for storing and retrieving encrypted secrets.
2253
3521
  * Access via `client.secrets`.
@@ -2452,12 +3720,10 @@ interface DeleteOptions {
2452
3720
  recursive?: boolean;
2453
3721
  }
2454
3722
  /**
2455
- * Enhanced file system operations for sandboxes.
2456
- * Access via `sandbox.fs`.
3723
+ * File system operations for sandboxes. Access via `sandbox.fs`.
2457
3724
  *
2458
- * Provides comprehensive file operations beyond basic read/write,
2459
- * including binary file upload/download, directory operations,
2460
- * and progress reporting for large files.
3725
+ * Beyond basic read/write: binary upload/download, directory operations,
3726
+ * progress reporting for large files.
2461
3727
  *
2462
3728
  * @example Upload and download files
2463
3729
  * ```typescript
@@ -2673,12 +3939,107 @@ interface FileSystem {
2673
3939
  exists(path: string): Promise<boolean>;
2674
3940
  }
2675
3941
  //#endregion
3942
+ //#region src/session.d.ts
3943
+ /**
3944
+ * The subset of `SandboxInstance` a `SandboxSession` drives. Declared here
3945
+ * (rather than importing the concrete class) so `session.ts` stays a leaf
3946
+ * of `sandbox.ts` — `sandbox.ts` constructs `SandboxSession`, so the reverse
3947
+ * import would form a cycle. `SandboxInstance` satisfies this structurally.
3948
+ */
3949
+ interface SandboxSessionHost {
3950
+ prompt(message: string | PromptInputPart[], options?: PromptOptions): Promise<PromptResult>;
3951
+ _sessionStatus(id: string): Promise<SessionInfo | null>;
3952
+ _sessionEvents(id: string, opts?: SessionEventStreamOptions): AsyncGenerator<SandboxEvent>;
3953
+ _sessionResult(id: string): Promise<PromptResult>;
3954
+ _sessionCancel(id: string): Promise<void>;
3955
+ }
3956
+ /**
3957
+ * A single agent session inside a sandbox. Created via
3958
+ * `box.session(id)` — does not hit the network until a method is called.
3959
+ */
3960
+ declare class SandboxSession {
3961
+ private readonly box;
3962
+ /** Stable session id assigned by the sandbox runtime. */
3963
+ readonly id: string;
3964
+ /**
3965
+ * @internal SDK-internal constructor — apps should call `box.session(id)`.
3966
+ */
3967
+ constructor(box: SandboxSessionHost, /** Stable session id assigned by the sandbox runtime. */
3968
+
3969
+ id: string);
3970
+ /**
3971
+ * Fetch the current session state from the sandbox. Includes status,
3972
+ * model, prompt count, token usage if known, and timing metadata.
3973
+ *
3974
+ * Throws on transport error; returns `null` if the session id is not
3975
+ * known to the sandbox (e.g. it ended and was reaped, or the id is
3976
+ * invalid).
3977
+ */
3978
+ status(): Promise<SessionInfo | null>;
3979
+ /**
3980
+ * Stream events from this session as they arrive. With no `since`,
3981
+ * starts at the live tail; with `since`, replays from that event id
3982
+ * forward — useful for reconnect-after-disconnect flows.
3983
+ *
3984
+ * The async iterator terminates when the session reaches a terminal
3985
+ * state (`completed`, `failed`, `cancelled`) and the corresponding
3986
+ * terminal event has been yielded, OR when the caller's signal aborts.
3987
+ */
3988
+ events(opts?: SessionEventStreamOptions): AsyncGenerator<SandboxEvent>;
3989
+ /**
3990
+ * Await the session's terminal result. Polls status + drains events
3991
+ * until the session reaches a terminal state, then returns the
3992
+ * aggregated `PromptResult`.
3993
+ *
3994
+ * Use this to wait for a session that was started by another caller
3995
+ * (e.g. `dispatchPrompt`).
3996
+ */
3997
+ result(): Promise<PromptResult>;
3998
+ /**
3999
+ * Continue this session with an additional prompt. Equivalent to
4000
+ * `box.prompt(message, { ...opts, sessionId: this.id })` but reads
4001
+ * naturally on a Session reference.
4002
+ */
4003
+ prompt(message: string | PromptInputPart[], opts?: PromptOptions): Promise<PromptResult>;
4004
+ /**
4005
+ * Cancel the session. Best-effort: an in-flight LLM call may still
4006
+ * complete one more token before the abort takes effect. Idempotent —
4007
+ * cancelling a completed session is a no-op.
4008
+ */
4009
+ cancel(): Promise<void>;
4010
+ }
4011
+ //#endregion
4012
+ //#region src/trace-exporter.d.ts
4013
+ type JsonObject = {
4014
+ [key: string]: JsonValue;
4015
+ };
4016
+ type TraceExportFormat = "tangle" | "otel-json";
4017
+ type TraceExportBundle = SandboxTraceBundle | SandboxFleetTraceBundle;
4018
+ interface TraceExportSink {
4019
+ url: string;
4020
+ headers?: Record<string, string>;
4021
+ format?: TraceExportFormat;
4022
+ serviceName?: string;
4023
+ timeoutMs?: number;
4024
+ fetch?: typeof fetch;
4025
+ }
4026
+ interface TraceExportResult {
4027
+ status: number;
4028
+ ok: boolean;
4029
+ body: string;
4030
+ }
4031
+ declare function buildTraceExportPayload(bundle: TraceExportBundle, format?: TraceExportFormat, serviceName?: string): TraceExportBundle | JsonObject;
4032
+ declare function exportTraceBundle(bundle: TraceExportBundle, sink: TraceExportSink): Promise<TraceExportResult>;
4033
+ declare function toOtelJson(bundle: TraceExportBundle, serviceName?: string): JsonObject;
4034
+ declare function otelTraceIdForTangleTrace(traceId: string): string;
4035
+ //#endregion
2676
4036
  //#region src/sandbox.d.ts
2677
4037
  /**
2678
4038
  * HTTP client interface for making requests.
2679
4039
  */
2680
4040
  interface HttpClient {
2681
4041
  fetch(path: string, options?: RequestInit): Promise<Response>;
4042
+ getApiKey?(): string | undefined;
2682
4043
  }
2683
4044
  /**
2684
4045
  * Git capability for repository operations.
@@ -2755,9 +4116,26 @@ declare class SandboxInstance {
2755
4116
  /** Web terminal URL for browser-based access */
2756
4117
  get url(): string | undefined;
2757
4118
  /**
2758
- * Serialize to the public sandbox shape for CLI JSON output.
4119
+ * Serialize to the public sandbox shape for logs and structured
4120
+ * output. Secrets in `connection` (currently `authToken`) are
4121
+ * redacted so that `JSON.stringify(box)` is safe to ship to log
4122
+ * sinks. Use {@link toDebugJSON} when the bearer is required (e.g.
4123
+ * one-off CLI commands that print credentials to the user).
2759
4124
  */
2760
4125
  toJSON(): SandboxInfo;
4126
+ /**
4127
+ * Serialize the sandbox **including secrets** when `includeSecrets`
4128
+ * is true. The default behavior matches {@link toJSON} and redacts
4129
+ * `connection.authToken`.
4130
+ *
4131
+ * Use only when the caller has an explicit need for the bearer
4132
+ * (e.g. presenting it once to the human operator). Never wire the
4133
+ * result of `toDebugJSON({ includeSecrets: true })` into a structured
4134
+ * logger — the bearer will land in any log sink consuming that output.
4135
+ */
4136
+ toDebugJSON(options?: {
4137
+ includeSecrets?: boolean;
4138
+ }): SandboxInfo;
2761
4139
  /**
2762
4140
  * Create an advanced direct-runtime view of this sandbox.
2763
4141
  *
@@ -2766,6 +4144,30 @@ declare class SandboxInstance {
2766
4144
  * Lifecycle methods still go through the parent SDK client.
2767
4145
  */
2768
4146
  direct(): SandboxInstance;
4147
+ /**
4148
+ * Get an MCP endpoint for this sandbox. Returns a paste-able config
4149
+ * for any MCP-capable host (Claude Desktop, Cursor, claude-code,
4150
+ * codex, opencode, …) plus a freshly-minted, capability-scoped JWT.
4151
+ *
4152
+ * The token is short-lived and limited to the requested capabilities
4153
+ * — it cannot be used against admin endpoints (`/exec`, `/files`,
4154
+ * etc.) on the sandbox. Call `getMcpEndpoint()` again to rotate.
4155
+ *
4156
+ * Requires the sandbox to have been created with `capabilities`
4157
+ * including the requested capability (default: `computer_use`).
4158
+ *
4159
+ * @example
4160
+ * ```typescript
4161
+ * const ep = await box.getMcpEndpoint();
4162
+ * // Save ep.config to your IDE's mcp.json — that's it.
4163
+ * fs.writeFileSync("mcp.json", JSON.stringify(ep.config, null, 2));
4164
+ * ```
4165
+ */
4166
+ getMcpEndpoint(options?: {
4167
+ capabilities?: ReadonlyArray<"computer_use">; /** Override server entry name (default: "tangle-sandbox"). */
4168
+ serverName?: string; /** Token TTL in minutes (server clamps to its policy). */
4169
+ ttlMinutes?: number;
4170
+ }): Promise<SandboxMcpEndpoint>;
2769
4171
  /**
2770
4172
  * Refresh sandbox information from the server.
2771
4173
  */
@@ -2828,6 +4230,7 @@ declare class SandboxInstance {
2828
4230
  * Throws if SSH is not enabled or sandbox is not running.
2829
4231
  */
2830
4232
  ssh(): Promise<SSHCredentials>;
4233
+ sshCommand(): Promise<SSHCommandDescriptor>;
2831
4234
  /**
2832
4235
  * Execute a command in the sandbox.
2833
4236
  */
@@ -2881,6 +4284,21 @@ declare class SandboxInstance {
2881
4284
  * Stream sandbox lifecycle and activity events.
2882
4285
  */
2883
4286
  events(options?: EventStreamOptions): AsyncGenerator<SandboxEvent>;
4287
+ trace(options?: SandboxTraceOptions): Promise<SandboxTraceBundle>;
4288
+ intelligence(): Promise<NonNullable<SandboxTraceBundle["intelligence"]>>;
4289
+ createIntelligenceReport(options?: {
4290
+ mode?: "deterministic" | "agentic";
4291
+ acknowledgeCost?: boolean;
4292
+ budget?: IntelligenceReportBudget;
4293
+ metadata?: Record<string, unknown>; /** Bound the analysis to a time window. */
4294
+ window?: IntelligenceReportWindow; /** Compare this sandbox against a same-type baseline sandbox. */
4295
+ compareTo?: IntelligenceReportCompareTo;
4296
+ }): Promise<IntelligenceReport>;
4297
+ createAgenticIntelligenceReport(options: {
4298
+ maxUsd: number;
4299
+ metadata?: Record<string, unknown>;
4300
+ }): Promise<IntelligenceReport>;
4301
+ exportTrace(sink: TraceExportSink): Promise<TraceExportResult>;
2884
4302
  /**
2885
4303
  * Stream real-time provisioning progress events.
2886
4304
  *
@@ -2999,12 +4417,10 @@ declare class SandboxInstance {
2999
4417
  */
3000
4418
  get tools(): ToolsCapability;
3001
4419
  /**
3002
- * Enhanced file system operations.
3003
- *
3004
- * Provides comprehensive file operations beyond basic read/write:
3005
- * - Binary file upload/download
3006
- * - Directory operations (uploadDir, downloadDir, list, mkdir)
3007
- * - File metadata (stat, exists)
4420
+ * File system operations beyond basic read/write:
4421
+ * - Binary upload/download
4422
+ * - Directory ops (uploadDir, downloadDir, list, mkdir)
4423
+ * - Metadata (stat, exists)
3008
4424
  * - Progress reporting for large files
3009
4425
  *
3010
4426
  * @example Upload and download
@@ -3084,6 +4500,13 @@ declare class SandboxInstance {
3084
4500
  * args: ["-y", "@anthropic/web-search"],
3085
4501
  * });
3086
4502
  * ```
4503
+ *
4504
+ * @example Read provider-native Cursor metadata
4505
+ * ```typescript
4506
+ * const models = await box.backend.models();
4507
+ * const agents = await box.backend.agents({ limit: 20 });
4508
+ * const runs = await box.backend.runs(agents.items[0].agentId);
4509
+ * ```
3087
4510
  */
3088
4511
  get backend(): BackendManager;
3089
4512
  private backendStatus;
@@ -3091,6 +4514,22 @@ declare class SandboxInstance {
3091
4514
  private backendAddMcp;
3092
4515
  private backendGetMcpStatus;
3093
4516
  private backendUpdateConfig;
4517
+ private backendControlData;
4518
+ private backendControlAction;
4519
+ private backendListSearch;
4520
+ private backendAccount;
4521
+ private backendModels;
4522
+ private backendRepositories;
4523
+ private backendAgents;
4524
+ private backendAgent;
4525
+ private backendArchiveAgent;
4526
+ private backendUnarchiveAgent;
4527
+ private backendDeleteAgent;
4528
+ private backendRuns;
4529
+ private backendRun;
4530
+ private backendAgentMessages;
4531
+ private backendArtifacts;
4532
+ private backendDownloadArtifact;
3094
4533
  private backendRestart;
3095
4534
  /**
3096
4535
  * Process manager for spawning and controlling processes.
@@ -3454,6 +4893,54 @@ declare class SandboxInstance {
3454
4893
  }): Promise<void>;
3455
4894
  private parseInfo;
3456
4895
  private sleep;
4896
+ /**
4897
+ * Get a session reference bound to this sandbox. Lazy: does not hit the
4898
+ * network until you call a method on the returned `SandboxSession`.
4899
+ * Use {@link sessions} to discover existing session ids.
4900
+ */
4901
+ session(id: string): SandboxSession;
4902
+ /**
4903
+ * List sessions on this sandbox, optionally filtering by status. Returns
4904
+ * `SandboxSession` instances paired with their last-known
4905
+ * {@link SessionInfo} so callers can avoid an extra round-trip per
4906
+ * session for status.
4907
+ */
4908
+ sessions(opts?: SessionListOptions): Promise<Array<{
4909
+ session: SandboxSession;
4910
+ info: SessionInfo;
4911
+ }>>;
4912
+ /**
4913
+ * Dispatch a prompt and return immediately with the session id (Issue
4914
+ * #913 Gap 2). The sandbox keeps running the prompt after this call
4915
+ * returns; reconnect via `box.session(id).events()` or wait for
4916
+ * completion with `box.session(id).result()`.
4917
+ *
4918
+ * Idempotent on `opts.sessionId`: re-dispatching with the same id when
4919
+ * the session is already running is a lookup, not a re-create. This
4920
+ * lets queue retries and reconnect-after-Worker-restart be safe by
4921
+ * construction.
4922
+ */
4923
+ dispatchPrompt(message: string | PromptInputPart[], opts?: DispatchPromptOptions): Promise<DispatchedSession>;
4924
+ /**
4925
+ * Mint a scoped, time-bounded JWT for direct browser access to this
4926
+ * sandbox (Issue #913 Gap 1). Authority is the caller's
4927
+ * `TANGLE_API_KEY` (sk-tan-*) — the Sandbox API mints the token;
4928
+ * signing secrets stay server-side.
4929
+ *
4930
+ * Use this to give a browser direct read access to the sandbox without
4931
+ * leaking the full bearer (`box.connection.authToken`). The returned
4932
+ * token verifies against the same sidecar middleware that already
4933
+ * gates ProductTokenIssuer-issued JWTs — no new sidecar surface.
4934
+ */
4935
+ mintScopedToken(opts: MintScopedTokenOptions): Promise<ScopedToken>;
4936
+ /** @internal — invoked by SandboxSession.status(). */
4937
+ _sessionStatus(id: string): Promise<SessionInfo | null>;
4938
+ /** @internal — invoked by SandboxSession.events(). */
4939
+ _sessionEvents(id: string, opts?: SessionEventStreamOptions): AsyncGenerator<SandboxEvent>;
4940
+ /** @internal — invoked by SandboxSession.result(). */
4941
+ _sessionResult(id: string): Promise<PromptResult>;
4942
+ /** @internal — invoked by SandboxSession.cancel(). */
4943
+ _sessionCancel(id: string): Promise<void>;
3457
4944
  }
3458
4945
  //#endregion
3459
- export { Process as $, AgentProfileResourceRef as $t, ExecResult as A, StorageConfig as At, GitStatus as B, UpdateUserOptions as Bt, DownloadOptions as C, SearchMatch as Ct, DriverType as D, SnapshotInfo as Dt, DriverInfo as E, SecretsManager as Et, GitAuth as F, TeeAttestationReport as Ft, McpServerConfig as G, AgentProfile as Gt, InstalledTool as H, UploadProgress as Ht, GitBranch as I, TeeAttestationResponse as It, NetworkManager as J, AgentProfileFileMount as Jt, MkdirOptions as K, AgentProfileCapabilities as Kt, GitCommit as L, TeePublicKey as Lt, FileSystem as M, TaskOptions as Mt, ForkOptions as N, TaskResult as Nt, EventStreamOptions as O, SnapshotOptions as Ot, ForkResult as P, TeeAttestationOptions as Pt, PreviewLinkManager as Q, AgentProfilePrompt as Qt, GitConfig as R, TeePublicKeyResponse as Rt, DirectoryPermission as S, SandboxUser as St, DriverConfig as T, SecretInfo as Tt, ListOptions as U, UsageInfo as Ut, GpuType as V, UploadOptions as Vt, ListSandboxOptions as W, WaitForOptions as Wt, PermissionsManager as X, AgentProfileModelHints as Xt, PermissionLevel as Y, AgentProfileMcpServer as Yt, PreviewLinkInfo as Z, AgentProfilePermissionValue as Zt, CheckpointOptions as _, SandboxEvent as _t, BackendCapabilities as a, defineGitHubResource as an, ProcessStatus as at, CreateSandboxOptions as b, SandboxResources as bt, BackendManager as c, ProvisionEvent as ct, BatchEvent as d, ProvisionStep as dt, AgentProfileResources as en, ProcessInfo as et, BatchOptions as f, RunCodeOptions as ft, CheckpointInfo as g, SandboxEnvironment as gt, BatchTaskResult as h, SandboxConnection as ht, AddUserOptions as i, defineAgentProfile as in, ProcessSpawnOptions as it, FileInfo as j, SubscriptionInfo as jt, ExecOptions as k, SnapshotResult as kt, BackendStatus as l, ProvisionResult as lt, BatchTask as m, SandboxClientConfig as mt, SandboxInstance as n, AgentProfileValidationResult as nn, ProcessManager as nt, BackendConfig as o, defineInlineResource as on, PromptOptions as ot, BatchResult as p, SSHCredentials as pt, NetworkConfig as q, AgentProfileConfidential as qt, AccessPolicyRule as r, AgentSubagentProfile as rn, ProcessSignal as rt, BackendInfo as s, mergeAgentProfiles as sn, PromptResult as st, HttpClient as t, AgentProfileValidationIssue as tn, ProcessLogEntry as tt, BackendType as u, ProvisionStatus as ut, CheckpointResult as v, SandboxInfo as vt, DownloadProgress as w, SearchOptions as wt, DeleteOptions as x, SandboxStatus as xt, CodeResult as y, SandboxPermissionsConfig as yt, GitDiff as z, ToolsConfig as zt };
4946
+ export { FleetExecDispatchOptions as $, SnapshotInfo as $n, RunCodeOptions as $t, CreateIntelligenceReportOptions as A, SandboxFleetWorkspaceReconcileResult as An, AgentProfileValidationResult as Ar, PreviewLinkManager as At, DownloadProgress as B, SandboxTraceExport as Bn, SandboxMcpServerEntry as Br, PromptResult as Bt, BatchResult as C, SandboxFleetToken as Cn, AgentProfileMcpServer as Cr, MintScopedTokenOptions as Ct, CheckpointOptions as D, SandboxFleetTraceOptions as Dn, AgentProfileResourceRef as Dr, PermissionLevel as Dt, CheckpointInfo as E, SandboxFleetTraceExport as En, AgentProfilePrompt as Er, NetworkManager as Et, DeleteOptions as F, SandboxPermissionsConfig as Fn, mergeAgentProfiles as Fr, ProcessSignal as Ft, ExecOptions as G, SearchMatch as Gn, PublicTemplateInfo as Gt, DriverInfo as H, SandboxUser as Hn, ProvisionResult as Ht, DirectoryPermission as I, SandboxResources as In, BuildSandboxMcpConfigOptions as Ir, ProcessSpawnOptions as It, FileSystem as J, SecretsManager as Jn, PublishPublicTemplateVersionOptions as Jt, ExecResult as K, SearchOptions as Kn, PublicTemplateVersionInfo as Kt, DispatchPromptOptions as L, SandboxStatus as Ln, SANDBOX_MCP_SERVER_NAME as Lr, ProcessStatus as Lt, CreateSandboxFleetTokenOptions as M, SandboxFleetWorkspaceSnapshotResult as Mn, defineAgentProfile as Mr, ProcessInfo as Mt, CreateSandboxFleetWithCoordinatorOptions as N, SandboxInfo as Nn, defineGitHubResource as Nr, ProcessLogEntry as Nt, CheckpointResult as O, SandboxFleetUsage as On, AgentProfileResources as Or, PermissionsManager as Ot, CreateSandboxOptions as P, SandboxIntelligenceEnvelope as Pn, defineInlineResource as Pr, ProcessManager as Pt, FleetDispatchStreamOptions as Q, SessionStatus as Qn, ReconcileSandboxFleetsResult as Qt, DispatchedSession as R, SandboxTraceBundle as Rn, SandboxMcpConfig as Rr, PromptInputPart as Rt, BatchOptions as S, SandboxFleetPolicy as Sn, AgentProfileFileMount as Sr, McpServerConfig as St, BatchTaskResult as T, SandboxFleetTraceEvent as Tn, AgentProfilePermissionValue as Tr, NetworkConfig as Tt, DriverType as U, ScopedToken as Un, ProvisionStatus as Ut, DriverConfig as V, SandboxTraceOptions as Vn, buildSandboxMcpConfig as Vr, ProvisionEvent as Vt, EventStreamOptions as W, ScopedTokenScope as Wn, ProvisionStep as Wt, FleetDispatchResultBuffer as X, SessionInfo as Xn, ReapExpiredSandboxFleetsResult as Xt, FleetDispatchCancelResult as Y, SessionEventStreamOptions as Yn, ReapExpiredSandboxFleetsOptions as Yt, FleetDispatchResultBufferOptions as Z, SessionListOptions as Zn, ReconcileSandboxFleetsOptions as Zt, BackendInfo as _, SandboxFleetMachineRecord as _n, UsageInfo as _r, IntelligenceReportSubjectType as _t, TraceExportSink as a, SandboxEvent as an, TaskOptions as ar, ForkResult as at, BackendType as b, SandboxFleetManifestMachine as bn, AgentProfileCapabilities as br, ListSandboxFleetOptions as bt, otelTraceIdForTangleTrace as c, SandboxFleetCostEstimate as cn, TeeAttestationReport as cr, GitCommit as ct, AcceleratorKind as d, SandboxFleetDriverCapability as dn, TeePublicKeyResponse as dr, GitStatus as dt, SSHCommandDescriptor as en, SnapshotOptions as er, FleetExecDispatchResult as et, AccessPolicyRule as f, SandboxFleetDriverTimings as fn, TokenRefreshHandler as fr, GpuType as ft, BackendConfig as g, SandboxFleetMachineMeteredUsage as gn, UploadProgress as gr, IntelligenceReportCompareTo as gt, BackendCapabilities as h, SandboxFleetMachine as hn, UploadOptions as hr, IntelligenceReportBudget as ht, TraceExportResult as i, SandboxEnvironment as in, SubscriptionInfo as ir, ForkOptions as it, CreateSandboxFleetOptions as j, SandboxFleetWorkspaceRestoreResult as jn, AgentSubagentProfile as jr, Process as jt, CodeResult as k, SandboxFleetWorkspace as kn, AgentProfileValidationIssue as kr, PreviewLinkInfo as kt, toOtelJson as l, SandboxFleetDispatchFailureClass as ln, TeeAttestationResponse as lr, GitConfig as lt, AttachSandboxFleetMachineOptions as m, SandboxFleetIntelligenceEnvelope as mn, UpdateUserOptions as mr, IntelligenceReport as mt, SandboxInstance as n, SandboxClientConfig as nn, SshKeysManager as nr, FleetPromptDispatchOptions as nt, buildTraceExportPayload as o, SandboxFleetArtifact as on, TaskResult as or, GitAuth as ot, AddUserOptions as p, SandboxFleetInfo as pn, ToolsConfig as pr, InstalledTool as pt, FileInfo as q, SecretInfo as qn, PublishPublicTemplateOptions as qt, TraceExportFormat as r, SandboxConnection as rn, StorageConfig as rr, FleetPromptDispatchResult as rt, exportTraceBundle as s, SandboxFleetArtifactSpec as sn, TeeAttestationOptions as sr, GitBranch as st, HttpClient as t, SSHCredentials as tn, SnapshotResult as tr, FleetMachineId as tt, SandboxSession as u, SandboxFleetDispatchResponse as un, TeePublicKey as ur, GitDiff as ut, BackendManager as v, SandboxFleetMachineSpec as vn, WaitForOptions as vr, IntelligenceReportWindow as vt, BatchTask as w, SandboxFleetTraceBundle as wn, AgentProfileModelHints as wr, MkdirOptions as wt, BatchEvent as x, SandboxFleetOperationsSummary as xn, AgentProfileConfidential as xr, ListSandboxOptions as xt, BackendStatus as y, SandboxFleetManifest as yn, AgentProfile as yr, ListOptions as yt, DownloadOptions as z, SandboxTraceEvent as zn, SandboxMcpEndpoint as zr, PromptOptions as zt };