@tangle-network/sandbox 0.9.4-develop.20260629071229.145161 → 0.9.4-develop.20260701061438.a81baba

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/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { a as collectAgentResponseText, c as buildTraceExportPayload, d as toOtelJson, g as serializeForSidecar, h as normalizeRuntimeBackendConfig, i as applySandboxEventText, l as exportTraceBundle, m as parseSSEStream, n as SandboxSession, o as getSandboxEventText, p as encodeTextForWire, r as InteractiveSessionHandle, t as SandboxInstance, u as otelTraceIdForTangleTrace } from "./sandbox-BTBbZupV.js";
1
+ import { a as collectAgentResponseText, c as buildTraceExportPayload, d as toOtelJson, g as serializeForSidecar, h as normalizeRuntimeBackendConfig, i as applySandboxEventText, l as exportTraceBundle, m as parseSSEStream, n as SandboxSession, o as getSandboxEventText, p as encodeTextForWire, r as InteractiveSessionHandle, t as SandboxInstance, u as otelTraceIdForTangleTrace } from "./sandbox-CDKpHv6-.js";
2
2
  import { a as PartialFailureError, c as ServerError, d as ValidationError, i as NotFoundError, l as StateError, n as CapabilityError, o as QuotaError, r as NetworkError, s as SandboxError, t as AuthError, u as TimeoutError } from "./errors-DZsfJUuc.js";
3
- import { a as DEFAULT_SANDBOX_SIZE, c as resolveSandboxResources, i as SandboxFleetClient, l as sandboxResourcesForSize, n as SandboxClient, o as SANDBOX_SIZE_PRESETS, r as SandboxFleet, s as SANDBOX_SIZE_PRESET_NAMES, t as IntelligenceClient } from "./client-BHEh7X6F.js";
3
+ import { a as DEFAULT_SANDBOX_SIZE, c as resolveSandboxResources, i as SandboxFleetClient, l as sandboxResourcesForSize, n as SandboxClient, o as SANDBOX_SIZE_PRESETS, r as SandboxFleet, s as SANDBOX_SIZE_PRESET_NAMES, t as IntelligenceClient } from "./client-9lYm4XHo.js";
4
4
  import { a as CollaborationClient, i as parseCollaborationDocumentId, n as buildCollaborationDocumentId, r as normalizeCollaborationPath, t as CollaborationFileBridge } from "./collaboration-BxlfZ2Uh.js";
5
- import { t as TangleSandboxClient } from "./tangle-D1c-2Jr2.js";
5
+ import { t as TangleSandboxClient } from "./tangle-DdHzeMUH.js";
6
6
  import { defineAgentProfile, defineGitHubResource, defineInlineResource, mergeAgentProfiles } from "@tangle-network/agent-interface";
7
7
  //#region src/confidential.ts
8
8
  function generateAttestationNonce(bytes = 32) {
@@ -595,6 +595,20 @@ function generateDockerfile(spec) {
595
595
  return lines.join("\n");
596
596
  }
597
597
  //#endregion
598
+ //#region src/types.ts
599
+ const GPU_LEASE_PROVIDER_NAMES = [
600
+ "runpod",
601
+ "vast-ai",
602
+ "lambda-labs",
603
+ "tensordock",
604
+ "paperspace",
605
+ "aws",
606
+ "gcp",
607
+ "azure",
608
+ "crusoe",
609
+ "fluidstack"
610
+ ];
611
+ //#endregion
598
612
  //#region src/manage-sandboxes.ts
599
613
  const MANAGE_SANDBOXES_TOOL_NAME = "manageSandboxes";
600
614
  function createManageSandboxesTool(client, options = {}) {
@@ -605,8 +619,8 @@ function createManageSandboxesTool(client, options = {}) {
605
619
  async execute(input) {
606
620
  switch (input.action) {
607
621
  case "capabilities": return client.fleets.capabilities();
608
- case "create": return client.fleets.create(applyToolPolicy(requireCreateOptions(input), options.policy));
609
- case "createWithCoordinator": return client.fleets.createWithCoordinator(applyToolPolicy(requireCreateWithCoordinatorOptions(input), options.policy));
622
+ case "create": return client.fleets.create(applyFleetGpuPolicy(applyToolPolicy(requireCreateOptions(input), options.policy), options.gpuPolicy));
623
+ case "createWithCoordinator": return client.fleets.createWithCoordinator(applyFleetGpuPolicyToCoordinator(applyToolPolicy(requireCreateWithCoordinatorOptions(input), options.policy), options.gpuPolicy));
610
624
  case "list": return client.fleets.list({ fleetId: requireString(input, "fleetId") });
611
625
  case "delete": return client.fleets.delete(requireString(input, "fleetId"));
612
626
  case "attachMachine": return client.fleets.attachMachine(requireString(input, "fleetId"), requireMachine(input));
@@ -619,6 +633,13 @@ function createManageSandboxesTool(client, options = {}) {
619
633
  case "createWorkspaceSnapshot": return client.fleets.createWorkspaceSnapshot(requireString(input, "fleetId"));
620
634
  case "restoreWorkspaceSnapshot": return client.fleets.restoreWorkspaceSnapshot(requireString(input, "fleetId"), requireString(input, "snapshotId"));
621
635
  case "reconcileWorkspace": return client.fleets.reconcileWorkspace(requireString(input, "fleetId"));
636
+ case "attachGpuLease": {
637
+ const attachOptions = applyGpuToolPolicy(requireGpuAttachOptions(input), options.gpuPolicy);
638
+ return (await requireSandbox(client, requireString(input, "sandboxId"))).gpu.attach(attachOptions);
639
+ }
640
+ case "listGpuLeases": return (await requireSandbox(client, requireString(input, "sandboxId"))).gpu.list();
641
+ case "execGpuLease": return (await requireSandbox(client, requireString(input, "sandboxId"))).gpu.exec(requireString(input, "leaseId"), requireGpuCommand(input));
642
+ case "detachGpuLease": return (await requireSandbox(client, requireString(input, "sandboxId"))).gpu.detach(requireString(input, "leaseId"));
622
643
  default: throw new Error(`Unsupported manageSandboxes action: ${String(input.action)}`);
623
644
  }
624
645
  }
@@ -650,6 +671,77 @@ function applyToolPolicy(options, policy) {
650
671
  policy
651
672
  };
652
673
  }
674
+ function applyFleetGpuPolicy(options, gpuPolicy) {
675
+ return {
676
+ ...options,
677
+ defaults: options.defaults ? applyGpuPolicyToCreateFragment(options.defaults, gpuPolicy, "fleet defaults") : void 0,
678
+ machines: options.machines.map((machine) => applyGpuPolicyToCreateFragment(machine, gpuPolicy, `machine ${machine.machineId}`))
679
+ };
680
+ }
681
+ function applyFleetGpuPolicyToCoordinator(options, gpuPolicy) {
682
+ return {
683
+ ...options,
684
+ coordinator: options.coordinator ? applyGpuPolicyToCreateFragment(options.coordinator, gpuPolicy, "coordinator") : void 0,
685
+ workers: options.workers.map((worker) => applyGpuPolicyToCreateFragment(worker, gpuPolicy, `worker ${worker.machineId}`))
686
+ };
687
+ }
688
+ function applyGpuPolicyToCreateFragment(fragment, gpuPolicy, label) {
689
+ if (fragment.gpuLease !== void 0) throw new Error("manageSandboxes GPU lease budget fields must be supplied by the tool host");
690
+ if (!fragment.resources?.accelerator) return fragment;
691
+ if (!gpuPolicy) throw new Error(`manageSandboxes ${label} requested accelerators but no host-owned GPU policy was supplied`);
692
+ return {
693
+ ...fragment,
694
+ gpuLease: gpuLeaseFromPolicy(gpuPolicy)
695
+ };
696
+ }
697
+ function gpuLeaseFromPolicy(policy) {
698
+ return {
699
+ ...policy.provider ? { provider: policy.provider } : {},
700
+ maxSpendUsd: policy.maxSpendUsd,
701
+ maxLifetimeSeconds: policy.maxLifetimeSeconds,
702
+ ...policy.idleTimeoutSeconds !== void 0 ? { idleTimeoutSeconds: policy.idleTimeoutSeconds } : {}
703
+ };
704
+ }
705
+ async function requireSandbox(client, sandboxId) {
706
+ const box = await client.get(sandboxId);
707
+ if (!box) throw new Error(`Sandbox not found: ${sandboxId}`);
708
+ return box;
709
+ }
710
+ function requireGpuAttachOptions(input) {
711
+ const value = input.options;
712
+ if (!value || typeof value !== "object") throw new Error("manageSandboxes requires options");
713
+ const options = value;
714
+ for (const key of [
715
+ "maxSpendUsd",
716
+ "maxLifetimeSeconds",
717
+ "idleTimeoutSeconds"
718
+ ]) if (key in options && options[key] !== void 0) throw new Error("manageSandboxes GPU lease budget fields must be supplied by the tool host");
719
+ const acceleratorValue = options.accelerator;
720
+ if (!acceleratorValue || typeof acceleratorValue !== "object") throw new Error("manageSandboxes GPU lease attach requires accelerator");
721
+ requireString(acceleratorValue, "kind");
722
+ return value;
723
+ }
724
+ function applyGpuToolPolicy(options, policy) {
725
+ if (!policy) throw new Error("manageSandboxes GPU lease attach requires a host-owned policy");
726
+ const requestedProvider = options.provider;
727
+ if (requestedProvider && policy.allowProviders && !policy.allowProviders.includes(requestedProvider)) throw new Error(`GPU provider ${requestedProvider} is not allowed by policy`);
728
+ const acceleratorCount = options.accelerator.count ?? 1;
729
+ if (policy.maxAcceleratorCount !== void 0 && acceleratorCount > policy.maxAcceleratorCount) throw new Error(`GPU lease requested ${acceleratorCount} accelerator(s) but policy.maxAcceleratorCount is ${policy.maxAcceleratorCount}`);
730
+ const provider = policy.provider ?? requestedProvider;
731
+ return {
732
+ ...options,
733
+ ...provider ? { provider } : {},
734
+ maxSpendUsd: policy.maxSpendUsd,
735
+ maxLifetimeSeconds: policy.maxLifetimeSeconds,
736
+ ...policy.idleTimeoutSeconds !== void 0 ? { idleTimeoutSeconds: policy.idleTimeoutSeconds } : {}
737
+ };
738
+ }
739
+ function requireGpuCommand(input) {
740
+ const value = input.command;
741
+ if (!value || typeof value !== "object") throw new Error("manageSandboxes requires command");
742
+ requireString(value, "command");
743
+ return value;
744
+ }
653
745
  function requireMachine(input) {
654
746
  const value = input.machine;
655
747
  if (!value || typeof value !== "object") throw new Error("manageSandboxes requires machine");
@@ -662,6 +754,135 @@ const fleetId = {
662
754
  type: "string",
663
755
  pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"
664
756
  };
757
+ const accelerator = {
758
+ type: "object",
759
+ additionalProperties: false,
760
+ required: ["kind"],
761
+ properties: {
762
+ kind: {
763
+ type: "string",
764
+ pattern: "^[A-Za-z0-9][A-Za-z0-9._-]*$",
765
+ description: "Accelerator kind such as gpu, nvidia, nvidia-l4, or nvidia-h100."
766
+ },
767
+ count: {
768
+ type: "integer",
769
+ minimum: 1,
770
+ maximum: 16
771
+ },
772
+ memoryMB: {
773
+ type: "integer",
774
+ minimum: 1
775
+ }
776
+ }
777
+ };
778
+ const gpuLeaseAttachOptions = {
779
+ type: "object",
780
+ additionalProperties: false,
781
+ required: ["accelerator"],
782
+ properties: {
783
+ provider: {
784
+ type: "string",
785
+ enum: [...GPU_LEASE_PROVIDER_NAMES]
786
+ },
787
+ accelerator,
788
+ image: {
789
+ type: "string",
790
+ minLength: 1
791
+ },
792
+ env: {
793
+ type: "object",
794
+ additionalProperties: { type: "string" }
795
+ }
796
+ }
797
+ };
798
+ const gpuLeaseCommand = {
799
+ type: "object",
800
+ additionalProperties: false,
801
+ required: ["command"],
802
+ properties: {
803
+ command: {
804
+ type: "string",
805
+ minLength: 1
806
+ },
807
+ timeoutMs: {
808
+ type: "integer",
809
+ minimum: 1,
810
+ maximum: 36e5
811
+ },
812
+ cwd: {
813
+ type: "string",
814
+ minLength: 1
815
+ },
816
+ env: {
817
+ type: "object",
818
+ additionalProperties: { type: "string" }
819
+ }
820
+ }
821
+ };
822
+ const resources = {
823
+ type: "object",
824
+ additionalProperties: false,
825
+ properties: {
826
+ cpuCores: {
827
+ type: "number",
828
+ exclusiveMinimum: 0
829
+ },
830
+ memoryMB: {
831
+ type: "integer",
832
+ minimum: 1
833
+ },
834
+ diskGB: {
835
+ type: "integer",
836
+ minimum: 1
837
+ },
838
+ accelerator
839
+ }
840
+ };
841
+ const driver = {
842
+ type: "object",
843
+ additionalProperties: true,
844
+ properties: {
845
+ type: {
846
+ type: "string",
847
+ enum: [
848
+ "docker",
849
+ "firecracker",
850
+ "host-agent",
851
+ "tangle"
852
+ ]
853
+ },
854
+ runtimeBackend: {
855
+ type: "string",
856
+ enum: ["docker", "firecracker"]
857
+ }
858
+ }
859
+ };
860
+ const fleetMachineSpec = {
861
+ type: "object",
862
+ additionalProperties: true,
863
+ required: ["machineId"],
864
+ properties: {
865
+ machineId: fleetId,
866
+ name: {
867
+ type: "string",
868
+ minLength: 1
869
+ },
870
+ role: {
871
+ type: "string",
872
+ enum: ["coordinator", "worker"]
873
+ },
874
+ image: {
875
+ type: "string",
876
+ minLength: 1
877
+ },
878
+ environment: {
879
+ type: "string",
880
+ minLength: 1
881
+ },
882
+ resources,
883
+ driver
884
+ }
885
+ };
665
886
  const MANAGE_SANDBOXES_PARAMETERS = {
666
887
  type: "object",
667
888
  additionalProperties: false,
@@ -684,16 +905,72 @@ const MANAGE_SANDBOXES_PARAMETERS = {
684
905
  "cost",
685
906
  "createWorkspaceSnapshot",
686
907
  "restoreWorkspaceSnapshot",
687
- "reconcileWorkspace"
908
+ "reconcileWorkspace",
909
+ "attachGpuLease",
910
+ "listGpuLeases",
911
+ "execGpuLease",
912
+ "detachGpuLease"
688
913
  ]
689
914
  },
690
915
  fleetId,
691
916
  machineId: fleetId,
917
+ sandboxId: {
918
+ type: "string",
919
+ minLength: 1,
920
+ maxLength: 128
921
+ },
922
+ leaseId: {
923
+ type: "string",
924
+ minLength: 1,
925
+ maxLength: 128
926
+ },
692
927
  snapshotId: {
693
928
  type: "string",
694
929
  minLength: 1
695
930
  },
696
- options: { type: "object" },
931
+ options: { anyOf: [{
932
+ type: "object",
933
+ additionalProperties: true,
934
+ properties: {
935
+ fleetId,
936
+ defaults: {
937
+ type: "object",
938
+ additionalProperties: true,
939
+ properties: {
940
+ image: {
941
+ type: "string",
942
+ minLength: 1
943
+ },
944
+ environment: {
945
+ type: "string",
946
+ minLength: 1
947
+ },
948
+ resources,
949
+ driver
950
+ }
951
+ },
952
+ machines: {
953
+ type: "array",
954
+ items: fleetMachineSpec,
955
+ minItems: 1
956
+ },
957
+ workers: {
958
+ type: "array",
959
+ items: fleetMachineSpec,
960
+ minItems: 1
961
+ },
962
+ coordinator: fleetMachineSpec,
963
+ workspace: {
964
+ type: "object",
965
+ additionalProperties: true,
966
+ properties: { mode: {
967
+ type: "string",
968
+ enum: ["isolated", "shared"]
969
+ } }
970
+ }
971
+ }
972
+ }, gpuLeaseAttachOptions] },
973
+ command: gpuLeaseCommand,
697
974
  machine: {
698
975
  type: "object",
699
976
  required: ["machineId", "sandboxId"],
@@ -1452,4 +1729,4 @@ function stripUndefined(value) {
1452
1729
  return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== void 0).map(([k, v]) => [k, stripUndefined(v)]));
1453
1730
  }
1454
1731
  //#endregion
1455
- export { AuthError, CONTROL_PLANE_MCP_SERVER_NAME, CapabilityError, CollaborationClient, CollaborationFileBridge, DEFAULT_SANDBOX_SIZE, Image, ImageBuilder, IntelligenceClient, InteractiveSessionHandle, MANAGE_SANDBOXES_PARAMETERS, MANAGE_SANDBOXES_TOOL_NAME, NetworkError, NotFoundError, PartialFailureError, QuotaError, SANDBOX_MCP_SERVER_NAME, SANDBOX_SIZE_PRESETS, SANDBOX_SIZE_PRESET_NAMES, SandboxClient as Sandbox, SandboxClient, SandboxError, SandboxFleet, SandboxFleetClient, SandboxInstance, SandboxSession, ServerError, StateError, TangleSandboxClient, TimeoutError, ValidationError, applySandboxEventText, buildCollaborationDocumentId, buildControlPlaneMcpConfig, buildSandboxMcpConfig, buildTangleRouterEvalMatrixRequest, buildTangleRouterResponsesWebSearchRequest, buildTangleRouterSearchBackend, buildTangleRouterSearchProfile, buildTraceExportPayload, collectAgentResponseText, createConfidentialSandbox, createManageSandboxesTool, defineAgentProfile, defineGitHubResource, defineInlineResource, exportTraceBundle, fetchTangleRouterSearchConfig, generateAttestationNonce, generateDockerfile, getSandboxEventText, materializeProfileFileMounts, mergeAgentProfiles, normalizeCollaborationPath, normalizeRuntimeBackendConfig, otelTraceIdForTangleTrace, parseCollaborationDocumentId, parseSSEStream, resolveSandboxResources, runTangleRouterEvalMatrixInSandbox, sandboxResourcesForSize, serializeForSidecar, splitInlineProfileFileMounts, startTeeAttestationHeartbeat, toOtelJson };
1732
+ export { AuthError, CONTROL_PLANE_MCP_SERVER_NAME, CapabilityError, CollaborationClient, CollaborationFileBridge, DEFAULT_SANDBOX_SIZE, GPU_LEASE_PROVIDER_NAMES, Image, ImageBuilder, IntelligenceClient, InteractiveSessionHandle, MANAGE_SANDBOXES_PARAMETERS, MANAGE_SANDBOXES_TOOL_NAME, NetworkError, NotFoundError, PartialFailureError, QuotaError, SANDBOX_MCP_SERVER_NAME, SANDBOX_SIZE_PRESETS, SANDBOX_SIZE_PRESET_NAMES, SandboxClient as Sandbox, SandboxClient, SandboxError, SandboxFleet, SandboxFleetClient, SandboxInstance, SandboxSession, ServerError, StateError, TangleSandboxClient, TimeoutError, ValidationError, applySandboxEventText, buildCollaborationDocumentId, buildControlPlaneMcpConfig, buildSandboxMcpConfig, buildTangleRouterEvalMatrixRequest, buildTangleRouterResponsesWebSearchRequest, buildTangleRouterSearchBackend, buildTangleRouterSearchProfile, buildTraceExportPayload, collectAgentResponseText, createConfidentialSandbox, createManageSandboxesTool, defineAgentProfile, defineGitHubResource, defineInlineResource, exportTraceBundle, fetchTangleRouterSearchConfig, generateAttestationNonce, generateDockerfile, getSandboxEventText, materializeProfileFileMounts, mergeAgentProfiles, normalizeCollaborationPath, normalizeRuntimeBackendConfig, otelTraceIdForTangleTrace, parseCollaborationDocumentId, parseSSEStream, resolveSandboxResources, runTangleRouterEvalMatrixInSandbox, sandboxResourcesForSize, serializeForSidecar, splitInlineProfileFileMounts, startTeeAttestationHeartbeat, toOtelJson };
@@ -1,4 +1,4 @@
1
- import { c as ServerError, d as ValidationError, f as parseErrorResponse, l as StateError, o as QuotaError, r as NetworkError, s as SandboxError, t as AuthError, u as TimeoutError } from "./errors-DZsfJUuc.js";
1
+ import { c as ServerError, d as ValidationError, f as parseErrorResponse, l as StateError, n as CapabilityError, o as QuotaError, r as NetworkError, s as SandboxError, t as AuthError, u as TimeoutError } from "./errors-DZsfJUuc.js";
2
2
  import { addTokenUsage, readTokenCostUsd, readTokenUsage } from "@tangle-network/agent-core";
3
3
  //#region src/backend-config.ts
4
4
  function parseModelString(model) {
@@ -21,6 +21,10 @@ function normalizeRuntimeBackendConfig(backend, options = {}) {
21
21
  const inlineProfile = portableProfile ? toBackendProfile(portableProfile) : void 0;
22
22
  const callerInlineProfile = backend?.inlineProfile;
23
23
  if (callerInlineProfile && !inlineProfile) console.warn("[sandbox-sdk] backend.inlineProfile is deprecated. Use backend.profile (AgentPortableProfile) instead.");
24
+ if (inlineProfile && portableProfile) {
25
+ const reasoningEffort = portableProfile.model?.reasoningEffort ?? portableProfile.extensions?.[backend?.type ?? ""]?.reasoningEffort;
26
+ if (typeof reasoningEffort === "string" && reasoningEffort !== "auto" && reasoningEffort !== "none") inlineProfile.reasoningEffort = reasoningEffort;
27
+ }
24
28
  return {
25
29
  ...backend?.type ? { type: backend.type } : {},
26
30
  ...typeof backend?.profile === "string" ? { profile: backend.profile } : {},
@@ -1041,6 +1045,10 @@ var SandboxInstance = class SandboxInstance {
1041
1045
  get error() {
1042
1046
  return this.info.error;
1043
1047
  }
1048
+ /** GPU lease attached during sandbox creation, when requested. */
1049
+ get gpuLease() {
1050
+ return this.info.gpuLease;
1051
+ }
1044
1052
  /** Web terminal URL for browser-based access */
1045
1053
  get url() {
1046
1054
  return this.info.connection?.webTerminalUrl;
@@ -1081,7 +1089,8 @@ var SandboxInstance = class SandboxInstance {
1081
1089
  startedAt: this.startedAt,
1082
1090
  lastActivityAt: this.lastActivityAt,
1083
1091
  expiresAt: this.expiresAt,
1084
- error: this.error
1092
+ error: this.error,
1093
+ gpuLease: this.gpuLease
1085
1094
  };
1086
1095
  }
1087
1096
  /**
@@ -3038,6 +3047,20 @@ var SandboxInstance = class SandboxInstance {
3038
3047
  update: (policy) => this.egressUpdate(policy)
3039
3048
  };
3040
3049
  }
3050
+ /**
3051
+ * On-demand GPU leases attached to this sandbox.
3052
+ *
3053
+ * The base sandbox stays cheap; `attach` starts a temporary external GPU
3054
+ * worker with an explicit spend cap, and `detach` destroys it.
3055
+ */
3056
+ get gpu() {
3057
+ return {
3058
+ attach: (options) => this.gpuAttach(options),
3059
+ list: () => this.gpuList(),
3060
+ exec: (leaseId, options) => this.gpuExec(leaseId, options),
3061
+ detach: (leaseId) => this.gpuDetach(leaseId)
3062
+ };
3063
+ }
3041
3064
  async networkUpdate(config) {
3042
3065
  if (config.blockOutbound !== void 0 && config.allowList !== void 0) {
3043
3066
  if (config.blockOutbound && config.allowList.length > 0) throw new Error("blockOutbound and allowList are mutually exclusive");
@@ -3115,6 +3138,44 @@ var SandboxInstance = class SandboxInstance {
3115
3138
  source: data.source
3116
3139
  };
3117
3140
  }
3141
+ async gpuAttach(options) {
3142
+ const response = await this.client.fetch(`/v1/sandboxes/${encodeURIComponent(this.id)}/gpu/leases`, {
3143
+ method: "POST",
3144
+ body: JSON.stringify(options)
3145
+ });
3146
+ if (!response.ok) {
3147
+ const body = await response.text();
3148
+ throw parseErrorResponse(response.status, body, void 0, response.headers);
3149
+ }
3150
+ return (await response.json()).lease;
3151
+ }
3152
+ async gpuList() {
3153
+ const response = await this.client.fetch(`/v1/sandboxes/${encodeURIComponent(this.id)}/gpu/leases`);
3154
+ if (!response.ok) {
3155
+ const body = await response.text();
3156
+ throw parseErrorResponse(response.status, body, void 0, response.headers);
3157
+ }
3158
+ return (await response.json()).leases ?? [];
3159
+ }
3160
+ async gpuExec(leaseId, options) {
3161
+ const response = await this.client.fetch(`/v1/sandboxes/${encodeURIComponent(this.id)}/gpu/leases/${encodeURIComponent(leaseId)}/exec`, {
3162
+ method: "POST",
3163
+ body: JSON.stringify(options)
3164
+ });
3165
+ if (!response.ok) {
3166
+ const body = await response.text();
3167
+ throw parseErrorResponse(response.status, body, void 0, response.headers);
3168
+ }
3169
+ return await response.json();
3170
+ }
3171
+ async gpuDetach(leaseId) {
3172
+ const response = await this.client.fetch(`/v1/sandboxes/${encodeURIComponent(this.id)}/gpu/leases/${encodeURIComponent(leaseId)}`, { method: "DELETE" });
3173
+ if (!response.ok) {
3174
+ const body = await response.text();
3175
+ throw parseErrorResponse(response.status, body, void 0, response.headers);
3176
+ }
3177
+ return (await response.json()).lease;
3178
+ }
3118
3179
  /**
3119
3180
  * Validate CIDR notation (IPv4 and IPv6)
3120
3181
  */
@@ -3515,130 +3576,59 @@ var SandboxInstance = class SandboxInstance {
3515
3576
  };
3516
3577
  }
3517
3578
  /**
3518
- * Create a CRIU checkpoint of the sandbox's memory state.
3519
- *
3520
- * Checkpoints capture the complete memory state of the running sandbox,
3521
- * enabling true pause/resume and fork operations. Unlike snapshots which
3522
- * only preserve filesystem state, checkpoints preserve process memory,
3523
- * open file descriptors, and execution state.
3524
- *
3525
- * **Requirements:** CRIU must be available on the host. Check availability
3526
- * with `client.criuStatus()` before calling.
3527
- *
3528
- * **Note:** By default, checkpoint stops the sandbox. Use `leaveRunning: true`
3529
- * to keep it running (creates a copy-on-write checkpoint).
3530
- *
3531
- * @param options - Checkpoint options
3532
- * @returns Checkpoint result with ID and metadata
3533
- *
3534
- * @example Basic checkpoint (stops sandbox)
3535
- * ```typescript
3536
- * const checkpoint = await box.checkpoint();
3537
- * console.log(`Checkpoint: ${checkpoint.checkpointId}`);
3538
- * // Sandbox is now stopped, resume with box.resume()
3539
- * ```
3540
- *
3541
- * @example Checkpoint without stopping
3542
- * ```typescript
3543
- * const checkpoint = await box.checkpoint({
3544
- * tags: ["before-deploy"],
3545
- * leaveRunning: true,
3546
- * });
3547
- * // Sandbox continues running
3548
- * ```
3579
+ * @deprecated CRIU checkpoints were removed. To branch live memory into
3580
+ * copy-on-write children of a running sandbox use {@link branch}; for durable
3581
+ * filesystem state use {@link snapshot}. This method now throws.
3549
3582
  */
3550
- async checkpoint(options) {
3551
- const response = await this.client.fetch(`/v1/sandboxes/${this.id}/checkpoints`, {
3552
- method: "POST",
3553
- body: JSON.stringify({
3554
- tags: options?.tags,
3555
- leaveRunning: options?.leaveRunning,
3556
- includeSnapshot: options?.includeSnapshot
3557
- })
3558
- });
3559
- if (!response.ok) {
3560
- const body = await response.text();
3561
- throw parseErrorResponse(response.status, body, void 0, response.headers);
3562
- }
3563
- const data = await response.json();
3564
- return {
3565
- checkpointId: data.checkpointId ?? data.id,
3566
- createdAt: new Date(data.createdAt ?? ""),
3567
- sizeBytes: data.sizeBytes,
3568
- tags: data.tags ?? []
3569
- };
3583
+ checkpoint() {
3584
+ throw new CapabilityError("checkpoint() was removed: use branch() to fork live memory into copy-on-write children, or snapshot() for durable disk state", "CHECKPOINT_REMOVED", 410);
3570
3585
  }
3571
3586
  /**
3572
- * List all checkpoints for this sandbox.
3573
- *
3574
- * @returns Array of checkpoint metadata
3575
- *
3576
- * @example
3577
- * ```typescript
3578
- * const checkpoints = await box.listCheckpoints();
3579
- * for (const cp of checkpoints) {
3580
- * console.log(`${cp.checkpointId}: ${cp.createdAt}`);
3581
- * }
3582
- * ```
3587
+ * @deprecated CRIU checkpoints were removed. List durable filesystem state
3588
+ * with {@link listSnapshots}. This method now throws.
3583
3589
  */
3584
- async listCheckpoints() {
3585
- const response = await this.client.fetch(`/v1/sandboxes/${this.id}/checkpoints`);
3586
- if (!response.ok) {
3587
- const body = await response.text();
3588
- throw parseErrorResponse(response.status, body, void 0, response.headers);
3589
- }
3590
- const data = await response.json();
3591
- return (Array.isArray(data) ? data : data.checkpoints ?? []).map((cp) => this.parseCheckpointInfo(cp));
3590
+ listCheckpoints() {
3591
+ throw new CapabilityError("listCheckpoints() was removed: checkpoints no longer exist; use listSnapshots() for durable disk state", "CHECKPOINT_REMOVED", 410);
3592
3592
  }
3593
3593
  /**
3594
- * Delete a checkpoint.
3595
- *
3596
- * @param checkpointId - ID of the checkpoint to delete
3594
+ * @deprecated CRIU checkpoints were removed. This method now throws.
3597
3595
  */
3598
- async deleteCheckpoint(checkpointId) {
3599
- const response = await this.client.fetch(`/v1/sandboxes/${this.id}/checkpoints/${encodeURIComponent(checkpointId)}`, { method: "DELETE" });
3600
- if (!response.ok) {
3601
- const body = await response.text();
3602
- throw parseErrorResponse(response.status, body, void 0, response.headers);
3603
- }
3596
+ deleteCheckpoint() {
3597
+ throw new CapabilityError("deleteCheckpoint() was removed: checkpoints no longer exist", "CHECKPOINT_REMOVED", 410);
3604
3598
  }
3605
3599
  /**
3606
- * Fork a new sandbox from a checkpoint.
3607
- *
3608
- * Creates a new sandbox with the same memory state as this sandbox
3609
- * at the time of the checkpoint. The fork has a new identity but
3610
- * preserves the execution state.
3611
- *
3612
- * **Use cases:**
3613
- * - Branch workflows: Create parallel execution paths
3614
- * - A/B testing: Run same state with different configurations
3615
- * - Debugging: Fork at a specific point to investigate
3616
- *
3617
- * @param checkpointId - ID of the checkpoint to fork from
3618
- * @param options - Fork configuration
3619
- * @returns The new sandbox instance
3600
+ * @deprecated Forking from a CRIU checkpoint was removed. Use {@link branch}
3601
+ * to fork a running sandbox's live memory into copy-on-write children, or
3602
+ * `client.create({ fromSnapshot })` to provision from durable disk state.
3603
+ * This method now throws.
3604
+ */
3605
+ fork() {
3606
+ throw new CapabilityError("fork() was removed: use branch() to fork live memory into copy-on-write children, or create({ fromSnapshot }) for durable disk state", "FORK_REMOVED", 410);
3607
+ }
3608
+ /**
3609
+ * Branch this RUNNING sandbox into `count` copy-on-write children
3610
+ * (Morph Infinibranch parity). Unlike {@link fork} — which rehydrates one
3611
+ * sandbox from a CRIU checkpoint — branch forks the live VM's memory into
3612
+ * many children at once via Firecracker UFFD copy-on-write: the children
3613
+ * share the parent's clean pages instead of each copying full guest
3614
+ * memory. The parent stays running.
3620
3615
  *
3621
- * @example Basic fork
3622
- * ```typescript
3623
- * const checkpoint = await box.checkpoint({ leaveRunning: true });
3624
- * const forked = await box.fork(checkpoint.checkpointId);
3625
- * // forked has same memory state as box at checkpoint time
3626
- * ```
3616
+ * @param count - Number of children to create (must be >= 1).
3617
+ * @param options - Per-child overrides.
3618
+ * @returns Exactly `count` new sandbox instances.
3627
3619
  *
3628
- * @example Fork with custom config
3620
+ * @example
3629
3621
  * ```typescript
3630
- * const forked = await box.fork(checkpointId, {
3631
- * name: "experiment-branch",
3632
- * env: { EXPERIMENT: "true" },
3633
- * });
3622
+ * const [a, b, c] = await box.branch(3);
3623
+ * // a, b, c each share box's memory state at branch time
3634
3624
  * ```
3635
3625
  */
3636
- async fork(checkpointId, options) {
3637
- const response = await this.client.fetch(`/v1/sandboxes/${this.id}/fork`, {
3626
+ async branch(count, options) {
3627
+ if (!Number.isInteger(count) || count < 1) throw new ValidationError(`branch count must be an integer >= 1 (got ${count})`);
3628
+ const response = await this.client.fetch(`/v1/sandboxes/${this.id}/branch`, {
3638
3629
  method: "POST",
3639
3630
  body: JSON.stringify({
3640
- checkpointId,
3641
- name: options?.name,
3631
+ count,
3642
3632
  env: options?.env,
3643
3633
  resources: options?.resources,
3644
3634
  metadata: options?.metadata
@@ -3648,8 +3638,7 @@ var SandboxInstance = class SandboxInstance {
3648
3638
  const body = await response.text();
3649
3639
  throw parseErrorResponse(response.status, body, void 0, response.headers);
3650
3640
  }
3651
- const data = await response.json();
3652
- return new SandboxInstance(this.client, this.parseInfo(data.sandbox ?? data), this.defaultRuntimeBackend);
3641
+ return ((await response.json()).children ?? []).map((child) => new SandboxInstance(this.client, this.parseInfo(child), this.defaultRuntimeBackend));
3653
3642
  }
3654
3643
  /**
3655
3644
  * Stop the sandbox (keeps state for resume).
@@ -3886,17 +3875,6 @@ var SandboxInstance = class SandboxInstance {
3886
3875
  abortController.abort();
3887
3876
  }
3888
3877
  }
3889
- parseCheckpointInfo(cp) {
3890
- return {
3891
- checkpointId: cp.checkpointId ?? cp.id,
3892
- sandboxId: cp.sandboxId ?? cp.projectRef ?? this.id,
3893
- createdAt: new Date(cp.createdAt),
3894
- tags: cp.tags ?? [],
3895
- sizeBytes: cp.sizeBytes,
3896
- hasMemoryState: cp.hasMemoryState ?? true,
3897
- hasFilesystemSnapshot: cp.hasFilesystemSnapshot ?? false
3898
- };
3899
- }
3900
3878
  async ensureRunning() {
3901
3879
  await this.refresh();
3902
3880
  if (this.status !== "running") throw new StateError(`Sandbox is not running (status: ${this.status})`, this.status, "running");
@@ -3970,6 +3948,7 @@ var SandboxInstance = class SandboxInstance {
3970
3948
  lastActivityAt: data.lastActivityAt ? new Date(data.lastActivityAt) : void 0,
3971
3949
  expiresAt: data.expiresAt ? new Date(data.expiresAt) : void 0,
3972
3950
  error: data.error,
3951
+ gpuLease: data.gpuLease ?? this.info.gpuLease,
3973
3952
  startupDiagnostics: normalizeStartupDiagnostics(data.startupDiagnostics) ?? this.info?.startupDiagnostics
3974
3953
  };
3975
3954
  }