@tangle-network/sandbox 0.9.4-develop.20260629071229.145161 → 0.9.4-develop.20260701122931.9698e96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,6 +50,34 @@ If sandbox creation hangs or times out, do not generate fallback code that
50
50
  pretends to have run in a sandbox. Surface the failure, keep the `sandboxId` or
51
51
  request id, and retry with the same idempotency key when available.
52
52
 
53
+ ### Temporary GPU for evals
54
+
55
+ Keep the base sandbox cheap and attach a GPU only around the command that needs it.
56
+ Omit `provider` to let the platform choose the cheapest configured GPU cloud.
57
+ Every GPU lease needs a hard spend cap and lifetime.
58
+
59
+ ```typescript
60
+ const lease = await box.gpu.attach({
61
+ accelerator: { kind: "nvidia-3090", count: 1, memoryMB: 24_000 },
62
+ maxSpendUsd: 1,
63
+ maxLifetimeSeconds: 900,
64
+ idleTimeoutSeconds: 120,
65
+ });
66
+
67
+ try {
68
+ const result = await box.gpu.exec(lease.id, {
69
+ command: "python eval.py",
70
+ timeoutMs: 15 * 60 * 1000,
71
+ });
72
+ console.log(result.result.stdout);
73
+ } finally {
74
+ await box.gpu.detach(lease.id);
75
+ }
76
+ ```
77
+
78
+ The detached lease includes `billing.seconds`, `billing.customerCostUsd`, and provider cost basis fields once billing is finalized.
79
+ See `examples/gpu-eval-lease.ts` for the full create, run, detach, and sandbox cleanup flow.
80
+
53
81
  ## Installation
54
82
 
55
83
  ```bash
@@ -1,5 +1,5 @@
1
- import { G as CodeExecutionOptions, K as CodeExecutionResult, Y as CodeResultPart, n as SandboxInstance, q as CodeLanguage } from "../sandbox-DcOyvnIy.js";
2
- import { i as SandboxClient } from "../client-DUY6Pdwf.js";
1
+ import { G as CodeExecutionResult, J as CodeResultPart, K as CodeLanguage, W as CodeExecutionOptions, n as SandboxInstance } from "../sandbox-CglV4-cN.js";
2
+ import { i as SandboxClient } from "../client-CgYipCL0.js";
3
3
  import * as _$_modelcontextprotocol_sdk_server_index_js0 from "@modelcontextprotocol/sdk/server/index.js";
4
4
 
5
5
  //#region src/agent/tools/_specs.d.ts
@@ -1,4 +1,4 @@
1
- import { f as encodePromptForWire, l as exportTraceBundle, m as parseSSEStream, s as normalizeConnection, t as SandboxInstance } from "./sandbox-BTBbZupV.js";
1
+ import { f as encodePromptForWire, l as exportTraceBundle, m as parseSSEStream, s as normalizeConnection, t as SandboxInstance } from "./sandbox-CDKpHv6-.js";
2
2
  import { d as ValidationError, f as parseErrorResponse, i as NotFoundError, r as NetworkError, t as AuthError, u as TimeoutError } from "./errors-DZsfJUuc.js";
3
3
  //#region src/resources.ts
4
4
  /**
@@ -140,6 +140,7 @@ function mergeCreateOptions(defaults, machine) {
140
140
  }
141
141
  } : void 0;
142
142
  const driver = machine.driver ?? defaults?.driver;
143
+ const gpuLease = mergeGpuLeaseOptions(defaults?.gpuLease, machine.gpuLease);
143
144
  return {
144
145
  ...defaults,
145
146
  ...rest,
@@ -152,7 +153,26 @@ function mergeCreateOptions(defaults, machine) {
152
153
  ...machine.env
153
154
  },
154
155
  backend,
155
- driver
156
+ driver,
157
+ gpuLease
158
+ };
159
+ }
160
+ function mergeGpuLeaseOptions(defaults, machine) {
161
+ if (!defaults && !machine) return void 0;
162
+ const maxSpendUsd = machine?.maxSpendUsd ?? defaults?.maxSpendUsd;
163
+ const maxLifetimeSeconds = machine?.maxLifetimeSeconds ?? defaults?.maxLifetimeSeconds;
164
+ if (maxSpendUsd === void 0 || maxLifetimeSeconds === void 0) return;
165
+ const env = defaults?.env || machine?.env ? {
166
+ ...defaults?.env,
167
+ ...machine?.env
168
+ } : void 0;
169
+ return {
170
+ ...machine?.provider ?? defaults?.provider ? { provider: machine?.provider ?? defaults?.provider } : {},
171
+ ...machine?.image ?? defaults?.image ? { image: machine?.image ?? defaults?.image } : {},
172
+ ...env ? { env } : {},
173
+ maxSpendUsd,
174
+ maxLifetimeSeconds,
175
+ ...machine?.idleTimeoutSeconds ?? defaults?.idleTimeoutSeconds ? { idleTimeoutSeconds: machine?.idleTimeoutSeconds ?? defaults?.idleTimeoutSeconds } : {}
156
176
  };
157
177
  }
158
178
  function assertPolicy(machines, defaults, policy) {
@@ -165,17 +185,21 @@ function assertPolicy(machines, defaults, policy) {
165
185
  let totalMemoryMb = 0;
166
186
  let totalStorageMb = 0;
167
187
  let totalAccelerators = 0;
188
+ let totalGpuLeaseMaxSpendUsd = 0;
168
189
  for (const machine of machines) {
169
- const resources = mergeCreateOptions(defaults, machine).resources;
190
+ const options = mergeCreateOptions(defaults, machine);
191
+ const resources = options.resources;
170
192
  totalCpu += resources?.cpuCores ?? 0;
171
193
  totalMemoryMb += resources?.memoryMB ?? 0;
172
194
  totalStorageMb += resources?.diskGB ? resources.diskGB * 1024 : 0;
173
195
  totalAccelerators += resources?.accelerator?.count ?? (resources?.accelerator ? 1 : 0);
196
+ if (options.gpuLease) totalGpuLeaseMaxSpendUsd += options.gpuLease.maxSpendUsd;
174
197
  }
175
198
  if (policy?.maxTotalCpu !== void 0 && totalCpu > policy.maxTotalCpu) throw new ValidationError(`Fleet create requested ${totalCpu} CPU cores but policy.maxTotalCpu is ${policy.maxTotalCpu}`, { "policy.maxTotalCpu": "exceeded" });
176
199
  if (policy?.maxTotalMemoryMb !== void 0 && totalMemoryMb > policy.maxTotalMemoryMb) throw new ValidationError(`Fleet create requested ${totalMemoryMb} MB RAM but policy.maxTotalMemoryMb is ${policy.maxTotalMemoryMb}`, { "policy.maxTotalMemoryMb": "exceeded" });
177
200
  if (policy?.maxTotalStorageMb !== void 0 && totalStorageMb > policy.maxTotalStorageMb) throw new ValidationError(`Fleet create requested ${totalStorageMb} MB storage but policy.maxTotalStorageMb is ${policy.maxTotalStorageMb}`, { "policy.maxTotalStorageMb": "exceeded" });
178
201
  if (policy?.maxTotalAccelerators !== void 0 && totalAccelerators > policy.maxTotalAccelerators) throw new ValidationError(`Fleet create requested ${totalAccelerators} accelerator devices but policy.maxTotalAccelerators is ${policy.maxTotalAccelerators}`, { "policy.maxTotalAccelerators": "exceeded" });
202
+ if (policy?.maxSpendUsd !== void 0 && totalGpuLeaseMaxSpendUsd > policy.maxSpendUsd) throw new ValidationError(`Fleet GPU lease max spend $${totalGpuLeaseMaxSpendUsd} exceeds policy.maxSpendUsd $${policy.maxSpendUsd}`, { "policy.maxSpendUsd": "exceeded" });
179
203
  const maxLifetimeSeconds = Math.max(...machines.map((machine) => mergeCreateOptions(defaults, machine).maxLifetimeSeconds ?? DEFAULT_MACHINE_LIFETIME_SECONDS));
180
204
  if (policy?.maxLifetimeSeconds !== void 0 && maxLifetimeSeconds > policy.maxLifetimeSeconds) throw new ValidationError(`Fleet create requested ${maxLifetimeSeconds}s max lifetime but policy.maxLifetimeSeconds is ${policy.maxLifetimeSeconds}`, { "policy.maxLifetimeSeconds": "exceeded" });
181
205
  for (const machine of machines) {
@@ -184,14 +208,20 @@ function assertPolicy(machines, defaults, policy) {
184
208
  }
185
209
  }
186
210
  function assertMachineDescriptorPolicy(machineId, options, policy) {
187
- if (!policy) return;
188
211
  const driverType = options.driver?.type;
189
- if (policy.allowedDrivers && driverType && !policy.allowedDrivers.includes(driverType)) throw new ValidationError(`Fleet machine '${machineId}' requested driver '${driverType}' outside policy.allowedDrivers`, { "policy.allowedDrivers": "exceeded" });
212
+ if (policy?.allowedDrivers && driverType && !policy.allowedDrivers.includes(driverType)) throw new ValidationError(`Fleet machine '${machineId}' requested driver '${driverType}' outside policy.allowedDrivers`, { "policy.allowedDrivers": "exceeded" });
190
213
  const image = options.environment ?? options.image;
191
- if (policy.allowedImages && image && !policy.allowedImages.includes(image)) throw new ValidationError(`Fleet machine '${machineId}' requested image '${image}' outside policy.allowedImages`, { "policy.allowedImages": "exceeded" });
214
+ if (policy?.allowedImages && image && !policy.allowedImages.includes(image)) throw new ValidationError(`Fleet machine '${machineId}' requested image '${image}' outside policy.allowedImages`, { "policy.allowedImages": "exceeded" });
192
215
  const templateId = options.templateId ?? options.publicTemplateId;
193
- if (policy.allowedTemplateIds && templateId && !policy.allowedTemplateIds.includes(templateId)) throw new ValidationError(`Fleet machine '${machineId}' requested template '${templateId}' outside policy.allowedTemplateIds`, { "policy.allowedTemplateIds": "exceeded" });
194
- if (policy.allowAccelerators === false && (options.resources?.accelerator?.count ?? (options.resources?.accelerator ? 1 : 0)) > 0) throw new ValidationError(`Fleet machine '${machineId}' requested accelerators but policy.allowAccelerators is false`, { "policy.allowAccelerators": "exceeded" });
216
+ if (policy?.allowedTemplateIds && templateId && !policy.allowedTemplateIds.includes(templateId)) throw new ValidationError(`Fleet machine '${machineId}' requested template '${templateId}' outside policy.allowedTemplateIds`, { "policy.allowedTemplateIds": "exceeded" });
217
+ if (policy?.allowAccelerators === false && (options.resources?.accelerator?.count ?? (options.resources?.accelerator ? 1 : 0)) > 0) throw new ValidationError(`Fleet machine '${machineId}' requested accelerators but policy.allowAccelerators is false`, { "policy.allowAccelerators": "exceeded" });
218
+ const acceleratorCount = options.resources?.accelerator?.count ?? (options.resources?.accelerator ? 1 : 0);
219
+ if (acceleratorCount > 0 && !options.gpuLease) throw new ValidationError(`Fleet machine '${machineId}' requested accelerators but gpuLease is missing`, { gpuLease: "required" });
220
+ if (acceleratorCount === 0 && options.gpuLease) throw new ValidationError(`Fleet machine '${machineId}' set gpuLease without resources.accelerator`, { gpuLease: "unexpected" });
221
+ if (options.gpuLease) {
222
+ if (!Number.isFinite(options.gpuLease.maxSpendUsd) || options.gpuLease.maxSpendUsd <= 0) throw new ValidationError(`Fleet machine '${machineId}' gpuLease.maxSpendUsd must be positive`, { "gpuLease.maxSpendUsd": "invalid" });
223
+ if (!Number.isInteger(options.gpuLease.maxLifetimeSeconds) || options.gpuLease.maxLifetimeSeconds <= 0) throw new ValidationError(`Fleet machine '${machineId}' gpuLease.maxLifetimeSeconds must be a positive integer`, { "gpuLease.maxLifetimeSeconds": "invalid" });
224
+ }
195
225
  }
196
226
  function calculateResourceTotals(machines, defaults) {
197
227
  let totalCpu = 0;
@@ -933,6 +963,7 @@ const DEFAULT_TIMEOUT_MS = 3e4;
933
963
  * safe server-side, but polling is cheaper and avoids duplicate work).
934
964
  */
935
965
  const DEFAULT_CREATE_TIMEOUT_MS = 12e4;
966
+ const DEFAULT_GPU_CREATE_TIMEOUT_MS = 900 * 1e3;
936
967
  /**
937
968
  * Extra grace the SDK's client-side batch deadline gets on top of
938
969
  * the server-side `timeoutMs`. The server's clock starts when the
@@ -1194,7 +1225,7 @@ var SandboxClient = class {
1194
1225
  * ```
1195
1226
  */
1196
1227
  async create(options, requestOptions) {
1197
- const timeoutMs = requestOptions?.timeoutMs ?? DEFAULT_CREATE_TIMEOUT_MS;
1228
+ const timeoutMs = requestOptions?.timeoutMs ?? (options?.gpuLease ? DEFAULT_GPU_CREATE_TIMEOUT_MS : DEFAULT_CREATE_TIMEOUT_MS);
1198
1229
  const idempotencyKey = options?.idempotencyKey ?? generateIdempotencyKey();
1199
1230
  const deadline = Date.now() + timeoutMs;
1200
1231
  const git = options?.git ? {
@@ -1233,6 +1264,7 @@ var SandboxClient = class {
1233
1264
  permissions: options?.permissions,
1234
1265
  env: options?.env,
1235
1266
  resources,
1267
+ gpuLease: options?.gpuLease,
1236
1268
  sshEnabled: options?.sshEnabled,
1237
1269
  sshPublicKeys: options?.sshPublicKeys ?? (options?.sshPublicKey ? [options.sshPublicKey] : void 0),
1238
1270
  sshKeyIds: options?.sshKeyIds,
@@ -1240,6 +1272,7 @@ var SandboxClient = class {
1240
1272
  maxLifetimeSeconds: options?.maxLifetimeSeconds,
1241
1273
  idleTimeoutSeconds: options?.idleTimeoutSeconds,
1242
1274
  storage: options?.storage,
1275
+ ephemeral: options?.ephemeral,
1243
1276
  fromSnapshot: options?.fromSnapshot,
1244
1277
  fromSandboxId: options?.fromSandboxId,
1245
1278
  templateId: options?.templateId,
@@ -1373,6 +1406,9 @@ var SandboxClient = class {
1373
1406
  const data = await response.json();
1374
1407
  return {
1375
1408
  computeMinutes: data.computeMinutes ?? 0,
1409
+ gpuSeconds: data.gpuSeconds ?? 0,
1410
+ gpuCostUsd: data.gpuCostUsd ?? 0,
1411
+ gpuProviderCostUsd: data.gpuProviderCostUsd ?? 0,
1376
1412
  activeSandboxes: data.activeSandboxes ?? 0,
1377
1413
  totalSandboxes: data.totalSandboxes ?? 0,
1378
1414
  periodStart: new Date(data.periodStart),
@@ -1639,7 +1675,8 @@ var SandboxClient = class {
1639
1675
  startedAt: data.startedAt ? new Date(data.startedAt) : void 0,
1640
1676
  lastActivityAt: data.lastActivityAt ? new Date(data.lastActivityAt) : void 0,
1641
1677
  expiresAt: data.expiresAt ? new Date(data.expiresAt) : void 0,
1642
- error: data.error
1678
+ error: data.error,
1679
+ gpuLease: data.gpuLease
1643
1680
  };
1644
1681
  }
1645
1682
  _tokenRefreshHandlers = /* @__PURE__ */ new Set();
@@ -1,4 +1,4 @@
1
- import { $ as CreateSandboxFleetOptions, $n as SandboxFleetTraceBundle, A as AttachSandboxFleetMachineOptions, B as BatchTask, Bn as SandboxFleetDriverCapability, Cn as PublishPublicTemplateVersionOptions, Ct as FleetDispatchStreamOptions, Dn as ReconcileSandboxFleetsResult, Dt as FleetPromptDispatchOptions, En as ReconcileSandboxFleetsOptions, Et as FleetMachineId, Fn as SandboxFleetArtifact, Gr as TokenRefreshHandler, Gt as IntelligenceReportWindow, Hn as SandboxFleetInfo, Ht as IntelligenceReportBudget, In as SandboxFleetArtifactSpec, Jn as SandboxFleetManifest, Jt as ListSandboxFleetOptions, Kn as SandboxFleetMachineRecord, L as BatchEvent, Ln as SandboxFleetCostEstimate, Lr as SubscriptionInfo, Nn as SandboxEnvironment, Nr as SshKeysManager, Ot as FleetPromptDispatchResult, Q as CreateRequestOptions, Qn as SandboxFleetToken, R as BatchOptions, Sn as PublishPublicTemplateOptions, St as FleetDispatchResultBufferOptions, Tn as ReapExpiredSandboxFleetsResult, Tt as FleetExecDispatchResult, Ut as IntelligenceReportCompareTo, Vt as IntelligenceReport, Xn as SandboxFleetOperationsSummary, Yt as ListSandboxOptions, Z as CreateIntelligenceReportOptions, Zr as UsageInfo, _t as ExecResult, a as TraceExportSink, ar as SandboxFleetWorkspaceReconcileResult, bn as PublicTemplateInfo, bt as FleetDispatchCancelResult, cr as SandboxInfo, et as CreateSandboxFleetTokenOptions, gt as ExecOptions, hn as PromptResult, i as TraceExportResult, jn as SandboxClientConfig, mn as PromptOptions, n as SandboxInstance, nr as SandboxFleetTraceOptions, nt as CreateSandboxOptions, or as SandboxFleetWorkspaceRestoreResult, pn as PromptInputPart, rr as SandboxFleetUsage, sr as SandboxFleetWorkspaceSnapshotResult, t as HttpClient, tt as CreateSandboxFleetWithCoordinatorOptions, wn as ReapExpiredSandboxFleetsOptions, wr as SecretsManager, wt as FleetExecDispatchOptions, xn as PublicTemplateVersionInfo, xt as FleetDispatchResultBuffer, z as BatchResult, zn as SandboxFleetDispatchResponse } from "./sandbox-DcOyvnIy.js";
1
+ import { $ as CreateSandboxFleetOptions, $n as SandboxFleetMachineRecord, An as PublishPublicTemplateVersionOptions, B as BatchResult, Bn as SandboxEnvironment, Br as SshKeysManager, Ct as FleetDispatchStreamOptions, Dn as PublicTemplateInfo, Dt as FleetPromptDispatchOptions, Et as FleetMachineId, Hn as SandboxFleetArtifact, Jt as IntelligenceReport, Kn as SandboxFleetDispatchResponse, Mn as ReapExpiredSandboxFleetsResult, Nn as ReconcileSandboxFleetsOptions, On as PublicTemplateVersionInfo, Ot as FleetPromptDispatchResult, Pn as ReconcileSandboxFleetsResult, Q as CreateRequestOptions, Qr as TokenRefreshHandler, Qt as IntelligenceReportWindow, R as BatchEvent, Rn as SandboxClientConfig, Sn as PromptResult, St as FleetDispatchResultBufferOptions, Tt as FleetExecDispatchResult, Un as SandboxFleetArtifactSpec, V as BatchTask, Wn as SandboxFleetCostEstimate, Wr as SubscriptionInfo, Xt as IntelligenceReportCompareTo, Yn as SandboxFleetInfo, Yt as IntelligenceReportBudget, Z as CreateIntelligenceReportOptions, _t as ExecResult, a as TraceExportSink, ar as SandboxFleetToken, bn as PromptInputPart, bt as FleetDispatchCancelResult, et as CreateSandboxFleetTokenOptions, fr as SandboxFleetWorkspaceReconcileResult, gt as ExecOptions, hr as SandboxInfo, i as TraceExportResult, ii as UsageInfo, j as AttachSandboxFleetMachineOptions, jn as ReapExpiredSandboxFleetsOptions, jr as SecretsManager, kn as PublishPublicTemplateOptions, lr as SandboxFleetTraceOptions, mr as SandboxFleetWorkspaceSnapshotResult, n as SandboxInstance, nn as ListSandboxOptions, nt as CreateSandboxOptions, or as SandboxFleetTraceBundle, pr as SandboxFleetWorkspaceRestoreResult, qn as SandboxFleetDriverCapability, rr as SandboxFleetOperationsSummary, t as HttpClient, tn as ListSandboxFleetOptions, tr as SandboxFleetManifest, tt as CreateSandboxFleetWithCoordinatorOptions, ur as SandboxFleetUsage, wt as FleetExecDispatchOptions, xn as PromptOptions, xt as FleetDispatchResultBuffer, z as BatchOptions } from "./sandbox-CglV4-cN.js";
2
2
 
3
3
  //#region src/lib/sse-parser.d.ts
4
4
  /**
package/dist/core.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $t as NetworkConfig, _t as ExecResult, an as PreviewLinkManager, cr as SandboxInfo, gt as ExecOptions, in as PreviewLinkInfo, jn as SandboxClientConfig, n as SandboxInstance, nt as CreateSandboxOptions, pr as SandboxStatus } from "./sandbox-DcOyvnIy.js";
2
- import { i as SandboxClient } from "./client-DUY6Pdwf.js";
1
+ import { Rn as SandboxClientConfig, _t as ExecResult, br as SandboxStatus, dn as PreviewLinkInfo, fn as PreviewLinkManager, gt as ExecOptions, hr as SandboxInfo, n as SandboxInstance, nt as CreateSandboxOptions, on as NetworkConfig } from "./sandbox-CglV4-cN.js";
2
+ import { i as SandboxClient } from "./client-CgYipCL0.js";
3
3
  import { a as PartialFailureError, c as SandboxErrorJson, d as StateError, f as TimeoutError, i as NotFoundError, l as SandboxFailureDetail, n as CapabilityError, o as QuotaError, p as ValidationError, r as NetworkError, s as SandboxError, t as AuthError, u as ServerError } from "./errors-1Se5ATyZ.js";
4
4
  export { AuthError, CapabilityError, type CreateSandboxOptions, type ExecOptions, type ExecResult, type NetworkConfig, NetworkError, NotFoundError, PartialFailureError, type PreviewLinkInfo, type PreviewLinkManager, QuotaError, SandboxClient as Sandbox, SandboxClient, type SandboxClientConfig, SandboxError, type SandboxErrorJson, type SandboxFailureDetail, type SandboxInfo, SandboxInstance, type SandboxStatus, ServerError, StateError, TimeoutError, ValidationError };
package/dist/core.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as SandboxInstance } from "./sandbox-BTBbZupV.js";
1
+ import { t as SandboxInstance } 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 { n as SandboxClient } from "./client-BHEh7X6F.js";
3
+ import { n as SandboxClient } from "./client-9lYm4XHo.js";
4
4
  export { AuthError, CapabilityError, NetworkError, NotFoundError, PartialFailureError, QuotaError, SandboxClient as Sandbox, SandboxClient, SandboxError, SandboxInstance, ServerError, StateError, TimeoutError, ValidationError };
@@ -1,4 +1,4 @@
1
- import { n as SandboxInstance, nt as CreateSandboxOptions, t as HttpClient } from "./sandbox-DcOyvnIy.js";
1
+ import { n as SandboxInstance, nt as CreateSandboxOptions, t as HttpClient } from "./sandbox-CglV4-cN.js";
2
2
 
3
3
  //#region src/tangle/abi.d.ts
4
4
  /**