@tangle-network/sandbox 1.0.189 → 1.0.191

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.
Files changed (58) hide show
  1. package/README.md +7 -0
  2. package/dist/agent/index.d.ts +4 -4
  3. package/dist/agent/index.js +9 -6
  4. package/dist/agent/preview.d.ts +1 -1
  5. package/dist/agent/preview.js +1 -1
  6. package/dist/{agent-run-outcome-Cst4px_l.d.ts → agent-run-outcome-BO5paRhX.d.ts} +2 -2
  7. package/dist/{api-request-D4Ln_0F5.js → api-request-BvpTwQKs.js} +4 -1
  8. package/dist/{browser-interactive-control-controller-DHIS8edi.js → browser-interactive-control-controller-BYbNLahH.js} +1 -1
  9. package/dist/{browser-interactive-control-controller-DIvMQyer.d.ts → browser-interactive-control-controller-KOK6qn2s.d.ts} +1 -1
  10. package/dist/{chunked-upload-vAE2hVcP.js → chunked-upload-D5ytV_s6.js} +9 -13
  11. package/dist/{chunked-upload-file-HLSriv3V.js → chunked-upload-file-DL1-AqRp.js} +2 -2
  12. package/dist/{client-CwWS3a-i.js → client-XjkuWhog.js} +159 -109
  13. package/dist/{client-C4SnCCpF.d.ts → client-yWdLuj_P.d.ts} +5 -5
  14. package/dist/collaboration/index.js +1 -1
  15. package/dist/{collaboration-CmT6Ygiv.js → collaboration-Bbr45lyk.js} +3 -3
  16. package/dist/{core-BT-0QZT-.js → core-BU1I2KvV.js} +13 -7
  17. package/dist/core.d.ts +6 -6
  18. package/dist/core.js +5 -5
  19. package/dist/errors-Mzq10WZq.js +583 -0
  20. package/dist/{file-download-BXgu9BNh.js → file-download-CKOxcATB.js} +1 -1
  21. package/dist/{index-DDIymnCZ.d.ts → index-DKsOu5sq.d.ts} +5 -5
  22. package/dist/index.d.ts +9 -9
  23. package/dist/index.js +10 -10
  24. package/dist/intelligence/index.js +9 -5
  25. package/dist/interactive-control.d.ts +1 -1
  26. package/dist/interactive-control.js +1 -1
  27. package/dist/{interactive-controller-DXGWBdYK.d.ts → interactive-controller-YyZEsoB0.d.ts} +3 -3
  28. package/dist/{interactive-controller-C876Pjaj.js → interactive-controller-jr3_74Pq.js} +90 -57
  29. package/dist/lib/prepared-evidence.js +1 -1
  30. package/dist/lib/prepared-process.js +1 -1
  31. package/dist/{lines-Br3ygqhP.d.ts → lines-CCHDUfQg.d.ts} +1 -1
  32. package/dist/{lines-DxHJhxCe.js → lines-DrG0WOW6.js} +1 -1
  33. package/dist/lines.d.ts +1 -1
  34. package/dist/lines.js +1 -1
  35. package/dist/{mcp-local-Cqf4Lpp0.js → mcp-local-Dler9R_s.js} +3 -10
  36. package/dist/{prepared-evidence-CP1MmeCQ.js → prepared-evidence-4prvV0YK.js} +1 -1
  37. package/dist/{prepared-process-BWVz93cT.js → prepared-process-BSpZXDDw.js} +1 -1
  38. package/dist/{preview-DUxqnKSk.d.ts → preview-I1z42VGY.d.ts} +3 -3
  39. package/dist/{public-templates-DQiblzzK.d.ts → public-templates-Cw6gmWJD.d.ts} +2 -2
  40. package/dist/public-templates.d.ts +1 -1
  41. package/dist/public-templates.js +7 -4
  42. package/dist/{raw-evidence-archive-CgbWa4es.js → raw-evidence-archive-BD37zHN5.js} +2 -2
  43. package/dist/runtime.d.ts +5 -5
  44. package/dist/runtime.js +9 -7
  45. package/dist/{sandbox-B_Xbc9wR.js → sandbox-Dtb-_btd.js} +317 -221
  46. package/dist/select-seat-command.d.ts +1 -1
  47. package/dist/select-seat-command.js +5 -2
  48. package/dist/session-gateway/index.js +1 -1
  49. package/dist/tangle/index.d.ts +1 -1
  50. package/dist/tangle/index.js +1 -1
  51. package/dist/{tangle-Sg9ORVAA.js → tangle-fs17QlcY.js} +2 -2
  52. package/dist/{terminal-stream-types-1YKRrkZB.d.ts → terminal-stream-types-BqNv5EuG.d.ts} +280 -305
  53. package/dist/{types-B-UsXSi6.d.ts → types-CiuGb4lZ.d.ts} +4 -2
  54. package/package.json +6 -6
  55. package/dist/errors-CaX0a5Ry.js +0 -636
  56. /package/dist/{abort-signal-PgWPMn_e.js → abort-signal-Cu4F2VVz.js} +0 -0
  57. /package/dist/{file-transfer-DTHgLccV.js → file-transfer-Cr9Ossea.js} +0 -0
  58. /package/dist/{retry-after-header-Bt-XvU-x.js → retry-after-header-DUdCC0KJ.js} +0 -0
@@ -1,21 +1,21 @@
1
- import { A as normalizeRuntimeBackendConfig, C as encodeTextForWire, D as applyRequestedModel, F as withoutRuntimeSecrets, I as createAgentRunOutcomeTracker, L as deriveAgentResultOutcome, M as requestedSecretProfilePublicDigest, O as assertCurrentBackendType, S as encodePromptForWire, T as canUseNodeHttp2, W as normalizeEffectiveBackend, _ as isTraceId, a as assertScopedTokenActive, b as resolveDispatchRunIdentity, c as SandboxRuntimeApi, d as appendSessionIdQuery, f as callHeaders, g as TRACE_ID_HEADER, h as isRetryableCredentialRefusal, i as terminalUpgradeHeadersSupported, j as requestedPublicProfileDigest, k as mergeRuntimeBackendConfig, l as normalizeSessionInfo, m as assertFileWritePreconditions, n as InteractiveSessionController, p as sessionHeaders, r as TerminalStream, s as requestScopedToken, u as sessionMessageRequestBody, v as mintTraceId, w as runtimeFilesystemPath, x as validateAcceptedDispatchRunRef, y as resolveTraceId } from "./interactive-controller-C876Pjaj.js";
1
+ import { A as normalizeRuntimeBackendConfig, C as encodeTextForWire, D as applyRequestedModel, F as withoutRuntimeSecrets, I as createAgentRunOutcomeTracker, L as deriveAgentResultOutcome, M as requestedSecretProfilePublicDigest, O as assertCurrentBackendType, S as encodePromptForWire, T as canUseNodeHttp2, W as normalizeEffectiveBackend, _ as isTraceId, a as assertScopedTokenActive, b as resolveDispatchRunIdentity, c as SandboxRuntimeApi, d as appendSessionIdQuery, f as callHeaders, g as TRACE_ID_HEADER, h as isRetryableCredentialRefusal, i as terminalUpgradeHeadersSupported, j as requestedPublicProfileDigest, k as mergeRuntimeBackendConfig, l as normalizeSessionInfo, m as assertFileWritePreconditions, n as InteractiveSessionController, p as sessionHeaders, r as TerminalStream, s as requestScopedToken, u as sessionMessageRequestBody, v as mintTraceId, w as runtimeFilesystemPath, x as validateAcceptedDispatchRunRef, y as resolveTraceId } from "./interactive-controller-jr3_74Pq.js";
2
2
  import { C as boundedIdentifierSchema, E as boundedStringSchema, g as sha256DigestSchema$1, o as canonicalCandidateDigest$1, s as canonicalCandidateJson$1, u as isCanonicalJsonValue$1 } from "./harness-DMaNgn0S.js";
3
3
  import { t as sha256 } from "./sha2-vu4U-x2L.js";
4
- import { A as agentInteractiveSessionStatusMatchesRef, B as PlanContinuationSchema, C as AgentInteractiveSessionStopAcknowledgementSchema, D as agentInteractiveSessionControlClaimMatchesRef, E as agentInteractiveSessionControlClaimIsNewer, F as AgentRunCancellationAcknowledgementSchema, G as InteractionResponseSchema, H as InteractionBindingSchema, I as AgentRunCancellationRequestSchema, L as agentRunCancellationAcknowledgementMatchesRequest, M as agentInteractiveDimensionSchema, N as sameAgentExactRun, O as agentInteractiveSessionPromptAcknowledgementMatchesCommand, P as AgentExactRunControlRefSchema, S as AgentInteractiveSessionStatusSchema, T as agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, U as InteractionRequestSchema, V as InteractionAcknowledgementSchema, W as InteractionResponseCommandSchema, _ as AgentInteractiveSessionControlClaimRequestSchema, b as AgentInteractiveSessionPromptCommandSchema, d as interactiveSessionControlClaimResponseSchema, f as interactiveSessionControlReleaseResponseSchema, g as AgentInteractiveSessionControlClaimAcknowledgementSchema, h as AgentInteractiveSessionAttachSchema, j as agentInteractiveSessionStopAcknowledgementMatchesCommand, l as createInteractiveControlHolderId, m as interactiveSessionStatusResponseSchema, p as interactiveSessionControlValidationResponseSchema, v as AgentInteractiveSessionControlClaimSchema, w as AgentInteractiveSessionStopCommandSchema, x as AgentInteractiveSessionRefSchema, y as AgentInteractiveSessionPromptAcknowledgementSchema } from "./browser-interactive-control-controller-DHIS8edi.js";
4
+ import { A as agentInteractiveSessionStatusMatchesRef, B as PlanContinuationSchema, C as AgentInteractiveSessionStopAcknowledgementSchema, D as agentInteractiveSessionControlClaimMatchesRef, E as agentInteractiveSessionControlClaimIsNewer, F as AgentRunCancellationAcknowledgementSchema, G as InteractionResponseSchema, H as InteractionBindingSchema, I as AgentRunCancellationRequestSchema, L as agentRunCancellationAcknowledgementMatchesRequest, M as agentInteractiveDimensionSchema, N as sameAgentExactRun, O as agentInteractiveSessionPromptAcknowledgementMatchesCommand, P as AgentExactRunControlRefSchema, S as AgentInteractiveSessionStatusSchema, T as agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, U as InteractionRequestSchema, V as InteractionAcknowledgementSchema, W as InteractionResponseCommandSchema, _ as AgentInteractiveSessionControlClaimRequestSchema, b as AgentInteractiveSessionPromptCommandSchema, d as interactiveSessionControlClaimResponseSchema, f as interactiveSessionControlReleaseResponseSchema, g as AgentInteractiveSessionControlClaimAcknowledgementSchema, h as AgentInteractiveSessionAttachSchema, j as agentInteractiveSessionStopAcknowledgementMatchesCommand, l as createInteractiveControlHolderId, m as interactiveSessionStatusResponseSchema, p as interactiveSessionControlValidationResponseSchema, v as AgentInteractiveSessionControlClaimSchema, w as AgentInteractiveSessionStopCommandSchema, x as AgentInteractiveSessionRefSchema, y as AgentInteractiveSessionPromptAcknowledgementSchema } from "./browser-interactive-control-controller-BYbNLahH.js";
5
5
  import { a as ProxySecretReceiptSchema, o as canonicalAgentProfileValue, r as agentProfileSchema } from "./profile-schema-C1KpT-wS.js";
6
- import { a as SANDBOX_PROXY_REQUEST_MAX_BYTES, c as PROFILE_FILE_MOUNT_OUTSIDE_ROOTS_CODE, d as isProfileFileMountOutsideRoots, f as profileFileMountOutsideRootsMessage, l as SANDBOX_AGENT_HOME, o as FILE_OPERATION_LIMITS, u as SANDBOX_FILE_API_ABSOLUTE_ROOTS } from "./file-transfer-DTHgLccV.js";
7
- import { C as StateError, E as ValidationError, S as ServerError, T as TimeoutError, a as AuthError, c as CompliancePlacementError, f as GpuProviderNotConfiguredError, g as NotFoundError, h as NetworkError, i as readResponseJson, l as EdgeNotReadyError, m as NON_RETRYABLE_CREATE_QUOTA_REASONS, n as parseErrorResponse, r as parseResponseError, s as CapabilityError, t as TerminalStreamError, v as ProfileFileMountPathError, w as StreamInterruptedError, x as SandboxError, y as QuotaError } from "./errors-CaX0a5Ry.js";
8
- import { i as delayUntilAborted, n as awaitWithAbort, r as combineAbortSignals, t as abortableSleep } from "./abort-signal-PgWPMn_e.js";
6
+ import { C as ServerError, D as ValidationError, E as TimeoutError, S as SandboxError, T as StreamInterruptedError, _ as NotFoundError, a as readResponseJson, d as EdgeNotReadyError, g as NetworkError, i as parseResponseError, l as CapabilityError, n as isTransientWrite, o as retryWhen, r as parseErrorResponse, s as AuthError, t as TerminalStreamError, w as StateError, y as ProfileFileMountPathError } from "./errors-Mzq10WZq.js";
7
+ import { i as delayUntilAborted, n as awaitWithAbort, r as combineAbortSignals, t as abortableSleep } from "./abort-signal-Cu4F2VVz.js";
8
+ import { a as SANDBOX_PROXY_REQUEST_MAX_BYTES, c as PROFILE_FILE_MOUNT_OUTSIDE_ROOTS_CODE, d as isProfileFileMountOutsideRoots, f as profileFileMountOutsideRootsMessage, l as SANDBOX_AGENT_HOME, o as FILE_OPERATION_LIMITS, u as SANDBOX_FILE_API_ABSOLUTE_ROOTS } from "./file-transfer-Cr9Ossea.js";
9
9
  import { t as rewrapResponse } from "./response-rewrap-Cjoxh2wZ.js";
10
10
  import { n as fetchWithKeepAlive, t as emitTiming } from "./keep-alive-fetch-C2lFwrMA.js";
11
11
  import { t as SIDECAR_PROXY_ERROR_HEADER } from "./sidecar-proxy-error-DTJbOAWL.js";
12
12
  import { t as parseSSEStream } from "./sse-parser-B4aH89Nq.js";
13
- import { s as uploadChunked } from "./chunked-upload-vAE2hVcP.js";
14
- import { t as runPreparedProcess } from "./prepared-process-BWVz93cT.js";
13
+ import { s as uploadChunked } from "./chunked-upload-D5ytV_s6.js";
14
+ import { t as runPreparedProcess } from "./prepared-process-BSpZXDDw.js";
15
15
  import { a as isBackendType, r as cliAuthReferenceSchema } from "./cli-auth-bundle-C6DtK7GX-BbbiAn-Z.js";
16
16
  import "./cli-auth-bundle-CMJWI99l.js";
17
- import { n as SandboxLines } from "./lines-DxHJhxCe.js";
18
- import { t as downloadFile } from "./file-download-BXgu9BNh.js";
17
+ import { n as SandboxLines } from "./lines-DrG0WOW6.js";
18
+ import { t as downloadFile } from "./file-download-CKOxcATB.js";
19
19
  import { z } from "zod";
20
20
  import { createHash } from "node:crypto";
21
21
  import { constants } from "node:fs";
@@ -259,16 +259,6 @@ const TerminalReplayWindowSchema = z.strictObject({
259
259
  const DEFAULT_CREATE_TIMEOUT_MS = 12e4;
260
260
  const DEFAULT_GPU_CREATE_TIMEOUT_MS = 900 * 1e3;
261
261
  const CREATE_RETRY_MAX_DELAY_MS = 4e3;
262
- const RETRYABLE_CREATE_STATUS_CODES = new Set([
263
- 408,
264
- 425,
265
- 429,
266
- 500,
267
- 502,
268
- 503,
269
- 504,
270
- 524
271
- ]);
272
262
  /**
273
263
  * 503 classes that mean "the cell cannot place a create right now, ask
274
264
  * again", not "this create failed". A full fleet answers `CAPACITY_EXHAUSTED`
@@ -342,15 +332,14 @@ function extendableDeadline(atMs) {
342
332
  };
343
333
  }
344
334
  function isDeployWindowCreateError(cause) {
345
- return cause instanceof SandboxError && cause.status === 503 && DEPLOY_WINDOW_RETRY_CODES.has(cause.code);
335
+ return cause instanceof SandboxError && cause.status === 503 && DEPLOY_WINDOW_RETRY_CODES.has(cause.wireCode);
346
336
  }
347
337
  /** A no-room refusal allocated nothing, so a create giving up on one reports this typed 503. */
348
- const isCapacityShortageCreateError = (cause) => isDeployWindowCreateError(cause) && (cause.code === "CAPACITY_EXHAUSTED" || cause.code === "HOST_PRESSURE");
338
+ const isCapacityShortageCreateError = (cause) => isDeployWindowCreateError(cause) && (cause.wireCode === "CAPACITY_EXHAUSTED" || cause.wireCode === "HOST_PRESSURE");
349
339
  /**
350
340
  * The plan rate limiter's 429 (`RATE_LIMIT_EXCEEDED`, or the platform's own
351
- * limiter): `quotaType` is the limiter's default `rate_limit`, never one of
352
- * the create quotas, which name their reason. Every paced re-POST above is a
353
- * Worker management request that limiter counts (the free plan allows 60 a
341
+ * limiter); a quota 429 is final in the catalog. Every paced re-POST above is
342
+ * a Worker management request that limiter counts (the free plan allows 60 a
354
343
  * minute, and one create retrying every 2 s is 30 of them), so in a full
355
344
  * fleet two concurrent creates meet it. Answered right after a capacity
356
345
  * refusal on the same key, it is part of that pacing, not a new failure: it
@@ -358,18 +347,25 @@ const isCapacityShortageCreateError = (cause) => isDeployWindowCreateError(cause
358
347
  * the attempt budget.
359
348
  */
360
349
  function isRateLimitCreateError(cause) {
361
- return cause instanceof QuotaError && cause.status === 429 && cause.quotaType === "rate_limit";
350
+ return retryWhen(cause) && cause.status === 429;
362
351
  }
352
+ /**
353
+ * Create retries what the catalog marks retryable (a 524 is a `TIMEOUT`, so a
354
+ * key that a proxy cut off is joined), except a 409, which create never
355
+ * retried, and a customer-floor hold: the cell keeps that room for customers
356
+ * and a re-POST meets the same hold.
357
+ */
363
358
  function isRetryableCreateError(cause) {
364
- if (cause instanceof NetworkError) return true;
365
- if (cause instanceof GpuProviderNotConfiguredError) return false;
366
- if (cause instanceof CompliancePlacementError) return false;
367
- if (cause instanceof SandboxError && cause.capacityHold) return false;
368
- if (cause instanceof QuotaError && NON_RETRYABLE_CREATE_QUOTA_REASONS.has(cause.quotaType.toUpperCase())) return false;
369
- return cause instanceof SandboxError && cause.status !== void 0 && RETRYABLE_CREATE_STATUS_CODES.has(cause.status);
359
+ return retryWhen(cause) && cause.status !== 409 && !cause.capacityHold;
370
360
  }
361
+ /**
362
+ * Longest wait on an `IDEMPOTENT_CREATE_PROBE_FAILED` `Retry-After`: the
363
+ * probe answers again within seconds, and an upstream 11.8 s hint ended a
364
+ * create on 10-26 instead of re-probing.
365
+ */
366
+ const PROBE_FAILED_MAX_DELAY_MS = 5e3;
371
367
  function createRetryDelayMs(cause, failedAttempt) {
372
- if (cause instanceof SandboxError && cause.retryAfterMs !== void 0) return cause.retryAfterMs;
368
+ if (cause instanceof SandboxError && cause.retryAfterMs !== void 0) return cause.wireCode === "IDEMPOTENT_CREATE_PROBE_FAILED" ? Math.min(cause.retryAfterMs, PROBE_FAILED_MAX_DELAY_MS) : cause.retryAfterMs;
373
369
  return Math.min(250 * 2 ** Math.max(0, failedAttempt - 1), CREATE_RETRY_MAX_DELAY_MS);
374
370
  }
375
371
  function generateIdempotencyKey() {
@@ -466,7 +462,7 @@ function normalizeEgressPolicyFields(data) {
466
462
  function normalizeProxySecretReceipt(raw, sandboxId) {
467
463
  if (raw === void 0) return void 0;
468
464
  const receipt = ProxySecretReceiptSchema.parse(raw);
469
- if (receipt.sandboxId !== sandboxId) throw new ServerError("Proxy secret receipt names another sandbox", 502);
465
+ if (receipt.sandboxId !== sandboxId) throw new ServerError("Proxy secret receipt names another sandbox", { status: 502 });
470
466
  return receipt;
471
467
  }
472
468
  //#endregion
@@ -1089,7 +1085,7 @@ var SandboxInfoCapabilities = class {
1089
1085
  /** Read and apply a lifecycle answer, which carries the complete sandbox state. */
1090
1086
  async readLifecycleResponse(response) {
1091
1087
  const data = await readResponseJson(response);
1092
- if (!this.applyLifecycleResponse(data)) throw new ServerError("Sandbox API lifecycle answer did not carry this sandbox's state", 502);
1088
+ if (!this.applyLifecycleResponse(data)) throw new ServerError("Sandbox API lifecycle answer did not carry this sandbox's state", { status: 502 });
1093
1089
  return data;
1094
1090
  }
1095
1091
  applyLifecycleResponse(data) {
@@ -1127,11 +1123,17 @@ var SandboxInfoCapabilities = class {
1127
1123
  if (this.status !== "running" || this.filesystemIncarnationReadiness !== "ready") return "not-running";
1128
1124
  }
1129
1125
  assertRunnable() {
1130
- if (this.status !== "running") throw new StateError(`Sandbox is not running (status: ${this.status})`, this.status, "running");
1126
+ if (this.status !== "running") throw new StateError(`Sandbox is not running (status: ${this.status})`, {
1127
+ currentState: this.status,
1128
+ requiredState: "running"
1129
+ });
1131
1130
  this.assertFilesystemIncarnationReady();
1132
1131
  }
1133
1132
  assertFilesystemIncarnationReady() {
1134
- if (this.filesystemIncarnationReadiness !== "ready") throw new StateError("Sandbox filesystem incarnation is not ready", this.status, "running with a ready filesystem incarnation");
1133
+ if (this.filesystemIncarnationReadiness !== "ready") throw new StateError("Sandbox filesystem incarnation is not ready", {
1134
+ currentState: this.status,
1135
+ requiredState: "running with a ready filesystem incarnation"
1136
+ });
1135
1137
  }
1136
1138
  /** Authenticated runtime request relative to this sandbox; preserves the runtime error
1137
1139
  * and request context. */
@@ -1188,7 +1190,8 @@ var SandboxInfoCapabilities = class {
1188
1190
  } catch (err) {
1189
1191
  options?.signal?.throwIfAborted();
1190
1192
  if (err instanceof StateError) throw err;
1191
- throw new NetworkError(`Failed to connect to sandbox: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : void 0, {
1193
+ throw new NetworkError(`Failed to connect to sandbox: ${err instanceof Error ? err.message : String(err)}`, {
1194
+ cause: err instanceof Error ? err : void 0,
1192
1195
  endpoint: path,
1193
1196
  origin: "runtime"
1194
1197
  });
@@ -3424,15 +3427,6 @@ const PROFILE_FILE_MOUNT_RETRY_MAX_MS = 2e3;
3424
3427
  * platform restart, which the caller is better told about.
3425
3428
  */
3426
3429
  const PROFILE_FILE_MOUNT_WRITE_RETRY_BUDGET_MS = 1e4;
3427
- /**
3428
- * Answers that decided nothing about the write: the gateway or proxy in front
3429
- * of the sandbox runtime answered for it, so the write may never have run.
3430
- */
3431
- const UNDECIDED_WRITE_STATUSES = new Set([
3432
- 502,
3433
- 503,
3434
- 504
3435
- ]);
3436
3430
  const waitForProfileFileMount = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3437
3431
  var ProfileFileMountExecTimeoutError = class extends Error {
3438
3432
  constructor(timeoutMs) {
@@ -3561,9 +3555,12 @@ function isRetryableProfileFileMaterializeFailure(err) {
3561
3555
  for (let link = err; link && typeof link === "object";) {
3562
3556
  if (seen.has(link)) break;
3563
3557
  seen.add(link);
3564
- if (link instanceof ProfileFileMountExecTimeoutError || link instanceof NetworkError || link instanceof TimeoutError) return true;
3558
+ if (link instanceof ProfileFileMountExecTimeoutError) return true;
3565
3559
  const status = errorStatus(link);
3566
- if (status !== void 0) {
3560
+ if (link instanceof SandboxError) {
3561
+ if (link.retryable) return true;
3562
+ decided = true;
3563
+ } else if (status !== void 0) {
3567
3564
  if (status >= 500 || UNSETTLED_HTTP_STATUSES.has(status)) return true;
3568
3565
  if (status >= 400) decided = true;
3569
3566
  }
@@ -3583,12 +3580,6 @@ function isRetryableProfileFileMaterializeFailure(err) {
3583
3580
  }
3584
3581
  return !decided;
3585
3582
  }
3586
- function isUndecidedWriteFailure(err) {
3587
- if (err instanceof NetworkError) return true;
3588
- if (!err || typeof err !== "object") return false;
3589
- const status = errorStatus(err);
3590
- return status !== void 0 && UNDECIDED_WRITE_STATUSES.has(status);
3591
- }
3592
3583
  /**
3593
3584
  * Run one file API batch write, sending it again after an undecided answer.
3594
3585
  *
@@ -3603,7 +3594,7 @@ async function writeBatchRidingOutUndecided(write, maxRetries) {
3603
3594
  await write();
3604
3595
  return;
3605
3596
  } catch (err) {
3606
- if (!isUndecidedWriteFailure(err) || attempt >= maxRetries) throw err;
3597
+ if (!(retryWhen(err) && (err instanceof NetworkError || err.status >= 502 && !(err instanceof TimeoutError))) || attempt >= maxRetries) throw err;
3607
3598
  const waitMs = retryAfterMs(err) ?? Math.min(250 * 2 ** attempt, 2e3);
3608
3599
  if (Date.now() - startedAt + waitMs >= PROFILE_FILE_MOUNT_WRITE_RETRY_BUDGET_MS) throw err;
3609
3600
  await waitForProfileFileMount(waitMs);
@@ -3660,14 +3651,21 @@ function validateDeferredProfileFileMounts(files, options = {}) {
3660
3651
  validateProfileFilePath(mount.path);
3661
3652
  if (isProfileFileMountOutsideRoots(mount.path)) {
3662
3653
  const message = `materializeProfileFileMounts: ${profileFileMountOutsideRootsMessage(mount.path)}`;
3663
- if (options.failOnError !== false) throw new ProfileFileMountPathError(mount.path, message, PROFILE_FILE_MOUNT_OUTSIDE_ROOTS_CODE);
3654
+ if (options.failOnError !== false) throw new ProfileFileMountPathError(message, {
3655
+ path: mount.path,
3656
+ code: PROFILE_FILE_MOUNT_OUTSIDE_ROOTS_CODE
3657
+ });
3664
3658
  console.warn(`[sandbox.profile] dropped profile file mount (resources.failOnError is false): ${message}`);
3665
3659
  continue;
3666
3660
  }
3667
3661
  const path = (mount.path.startsWith("~/") ? `${PROFILE_AGENT_HOME}/${mount.path.slice(2)}` : mount.path).replace(/\/+/g, "/");
3668
3662
  const same = paths.get(path);
3669
3663
  if (same === void 0) kept.push(mount);
3670
- else if (inlineContent(same) !== inlineContent(mount) || isExecutableProfileFile(same) !== isExecutableProfileFile(mount)) throw new ProfileFileMountPathError(mount.path, `materializeProfileFileMounts: ${same.path} and ${mount.path} name one file with different content or mode`, "PROFILE_FILE_CONFLICT", void 0, 409);
3664
+ else if (inlineContent(same) !== inlineContent(mount) || isExecutableProfileFile(same) !== isExecutableProfileFile(mount)) throw new ProfileFileMountPathError(`materializeProfileFileMounts: ${same.path} and ${mount.path} name one file with different content or mode`, {
3665
+ path: mount.path,
3666
+ code: "PROFILE_FILE_CONFLICT",
3667
+ status: 409
3668
+ });
3671
3669
  paths.set(path, mount);
3672
3670
  }
3673
3671
  return kept;
@@ -4057,7 +4055,11 @@ async function materializeAbsentProfileFiles(box, files, options) {
4057
4055
  const conflict = /^PROFILE_FILE_CONFLICT (.+)$/m.exec(stderr)?.[1];
4058
4056
  if (conflict !== void 0) {
4059
4057
  const paths = JSON.parse(conflict);
4060
- throw new ProfileFileMountPathError(paths[0], `Profile file ${paths.join(" and ")} conflicts (changed in the sandbox and the profile, or one target with two contents or modes); refusing to replace it`, "PROFILE_FILE_CONFLICT", void 0, 409);
4058
+ throw new ProfileFileMountPathError(`Profile file ${paths.join(" and ")} conflicts (changed in the sandbox and the profile, or one target with two contents or modes); refusing to replace it`, {
4059
+ path: paths[0],
4060
+ code: "PROFILE_FILE_CONFLICT",
4061
+ status: 409
4062
+ });
4061
4063
  }
4062
4064
  throw new ProfileFileMaterializeError(`materializeProfileFileMounts: ${stderr}`, {
4063
4065
  exitCode: applied.exitCode,
@@ -4133,7 +4135,10 @@ var ProfileFileDelivery = class {
4133
4135
  if (incarnation === void 0 || this.delivered?.incarnation !== incarnation || this.delivered.fingerprint !== bundle) {
4134
4136
  this.delivered = void 0;
4135
4137
  delivery = await this.deliverProfileFiles(box, deferredFiles, bundle, existingFiles);
4136
- if (box.filesystemIncarnationId !== incarnation) throw new StateError("Filesystem incarnation changed during profile file delivery", box.filesystemIncarnationId ?? "unknown", incarnation ?? "unknown");
4138
+ if (box.filesystemIncarnationId !== incarnation) throw new StateError("Filesystem incarnation changed during profile file delivery", {
4139
+ currentState: box.filesystemIncarnationId ?? "unknown",
4140
+ requiredState: incarnation ?? "unknown"
4141
+ });
4137
4142
  if (incarnation !== void 0) this.delivered = {
4138
4143
  incarnation,
4139
4144
  fingerprint: bundle
@@ -4244,8 +4249,7 @@ const DEFAULT_WAIT_TIMEOUT_MS = 10 * 6e4;
4244
4249
  var SandboxOperationFailedError = class extends SandboxError {
4245
4250
  operation;
4246
4251
  constructor(operation) {
4247
- super(operation.error?.message ?? `Sandbox ${operation.kind} operation ${operation.id} failed`, operation.error?.code ?? "OPERATION_FAILED");
4248
- this.name = "SandboxOperationFailedError";
4252
+ super(operation.error?.message ?? `Sandbox ${operation.kind} operation ${operation.id} failed`, { code: operation.error?.code ?? "OPERATION_FAILED" });
4249
4253
  this.operation = operation;
4250
4254
  }
4251
4255
  };
@@ -4273,7 +4277,10 @@ function parseSnapshot(value) {
4273
4277
  };
4274
4278
  }
4275
4279
  function contractViolation(message) {
4276
- return new SandboxError(message, "UPSTREAM_CONTRACT_VIOLATION", 502);
4280
+ return new SandboxError(message, {
4281
+ code: "UPSTREAM_CONTRACT_VIOLATION",
4282
+ status: 502
4283
+ });
4277
4284
  }
4278
4285
  /**
4279
4286
  * Parse the API's operation body; throws on a body that is not one. With
@@ -4393,7 +4400,7 @@ var SandboxOperation = class SandboxOperation {
4393
4400
  let delayMs = 0;
4394
4401
  let info;
4395
4402
  while (!info || !isTerminalOperation(info)) {
4396
- if (Date.now() - startedAt + delayMs > timeoutMs) throw new TimeoutError(timeoutMs, `Timed out waiting for ${this.#info.kind} operation ${this.#info.id} (last state ${this.#info.state})`);
4403
+ if (Date.now() - startedAt + delayMs > timeoutMs) throw new TimeoutError(`Timed out waiting for ${this.#info.kind} operation ${this.#info.id} (last state ${this.#info.state})`, { timeoutMs });
4397
4404
  signal?.throwIfAborted();
4398
4405
  if (delayMs > 0) await delayUntilAborted(delayMs, signal);
4399
4406
  const next = Math.min(Math.max(delayMs * 2, FIRST_POLL_MS), MAX_POLL_MS);
@@ -4401,8 +4408,7 @@ var SandboxOperation = class SandboxOperation {
4401
4408
  info = await this.refresh({ signal });
4402
4409
  delayMs = next;
4403
4410
  } catch (error) {
4404
- if (!(error instanceof SandboxError)) throw error;
4405
- if (error.status !== 429 && error.status !== 503) throw error;
4411
+ if (!retryWhen(error) || error instanceof NetworkError || error.status !== 429 && error.status !== 503) throw error;
4406
4412
  delayMs = Math.max(error.retryAfterMs ?? 0, next);
4407
4413
  }
4408
4414
  }
@@ -4730,7 +4736,8 @@ var SandboxBackendCapabilities = class extends SandboxGitCapabilities {
4730
4736
  async backendControlData(path) {
4731
4737
  await this.ensureRunning();
4732
4738
  const payload = await readResponseJson(await this.runtimeFetch(path, { method: "GET" }));
4733
- if (!payload || typeof payload !== "object" || !("data" in payload)) throw new ServerError("Backend control response missing data", 502, {
4739
+ if (!payload || typeof payload !== "object" || !("data" in payload)) throw new ServerError("Backend control response missing data", {
4740
+ status: 502,
4734
4741
  endpoint: path,
4735
4742
  origin: "runtime"
4736
4743
  });
@@ -4791,7 +4798,8 @@ var SandboxBackendCapabilities = class extends SandboxGitCapabilities {
4791
4798
  await this.ensureRunning();
4792
4799
  const search = new URLSearchParams({ path });
4793
4800
  const payload = await readResponseJson(await this.runtimeFetch(`/config/artifacts/${encodeURIComponent(sessionId)}/download?${search.toString()}`, { method: "GET" }));
4794
- if (!payload || typeof payload.base64 !== "string") throw new ServerError("Backend artifact download response missing base64", 502, {
4801
+ if (!payload || typeof payload.base64 !== "string") throw new ServerError("Backend artifact download response missing base64", {
4802
+ status: 502,
4795
4803
  endpoint: `/config/artifacts/${encodeURIComponent(sessionId)}/download`,
4796
4804
  origin: "runtime"
4797
4805
  });
@@ -5157,12 +5165,14 @@ var SandboxPreviewCapabilities = class extends SandboxGpuCapabilities {
5157
5165
  const startTime = Date.now();
5158
5166
  let lastProbeCode;
5159
5167
  while (true) {
5160
- if (options?.signal?.aborted) throw new TimeoutError(0, "Aborted", {
5168
+ if (options?.signal?.aborted) throw new TimeoutError("Aborted", {
5169
+ timeoutMs: 0,
5161
5170
  origin: "runtime",
5162
5171
  endpoint
5163
5172
  });
5164
5173
  const remainingBeforeCheckMs = timeoutMs - (Date.now() - startTime);
5165
- if (remainingBeforeCheckMs < 0) throw new TimeoutError(timeoutMs, `Timed out waiting for preview link ${previewId} to become ready${lastProbeCode ? ` (${lastProbeCode})` : ""}`, {
5174
+ if (remainingBeforeCheckMs < 0) throw new TimeoutError(`Timed out waiting for preview link ${previewId} to become ready${lastProbeCode ? ` (${lastProbeCode})` : ""}`, {
5175
+ timeoutMs,
5166
5176
  origin: "runtime",
5167
5177
  endpoint
5168
5178
  });
@@ -5171,35 +5181,43 @@ var SandboxPreviewCapabilities = class extends SandboxGpuCapabilities {
5171
5181
  try {
5172
5182
  previewLink = await this.previewLinkGet(previewId, requestSignal);
5173
5183
  } catch (error) {
5174
- if (options?.signal?.aborted) throw new TimeoutError(0, "Aborted", {
5184
+ if (options?.signal?.aborted) throw new TimeoutError("Aborted", {
5185
+ timeoutMs: 0,
5175
5186
  origin: "runtime",
5176
5187
  endpoint
5177
5188
  });
5178
- if (timeoutMs > 0 && Date.now() - startTime >= timeoutMs) throw new TimeoutError(timeoutMs, `Timed out waiting for preview link ${previewId} to become ready${lastProbeCode ? ` (${lastProbeCode})` : ""}`, {
5189
+ if (timeoutMs > 0 && Date.now() - startTime >= timeoutMs) throw new TimeoutError(`Timed out waiting for preview link ${previewId} to become ready${lastProbeCode ? ` (${lastProbeCode})` : ""}`, {
5190
+ timeoutMs,
5179
5191
  origin: "runtime",
5180
5192
  endpoint
5181
5193
  });
5182
5194
  throw error;
5183
5195
  }
5184
5196
  lastProbeCode = previewLink.lastProbe?.code;
5185
- if (options?.signal?.aborted) throw new TimeoutError(0, "Aborted", {
5197
+ if (options?.signal?.aborted) throw new TimeoutError("Aborted", {
5198
+ timeoutMs: 0,
5186
5199
  origin: "runtime",
5187
5200
  endpoint
5188
5201
  });
5189
5202
  if (previewLink.status === "ready") return previewLink;
5190
- if (previewLink.status === "error" || previewLink.status === "disabled") throw new StateError(`Preview link cannot become ready (status: ${previewLink.status})`, previewLink.status, "ready", {
5203
+ if (previewLink.status === "error" || previewLink.status === "disabled") throw new StateError(`Preview link cannot become ready (status: ${previewLink.status})`, {
5204
+ currentState: previewLink.status,
5205
+ requiredState: "ready",
5191
5206
  origin: "runtime",
5192
- endpoint
5193
- }, lastProbeCode ?? "PREVIEW_LINK_UNAVAILABLE");
5207
+ endpoint,
5208
+ code: lastProbeCode ?? "PREVIEW_LINK_UNAVAILABLE"
5209
+ });
5194
5210
  const remainingAfterCheckMs = timeoutMs - (Date.now() - startTime);
5195
- if (remainingAfterCheckMs <= 0) throw new TimeoutError(timeoutMs, `Timed out waiting for preview link ${previewId} to become ready${lastProbeCode ? ` (${lastProbeCode})` : ""}`, {
5211
+ if (remainingAfterCheckMs <= 0) throw new TimeoutError(`Timed out waiting for preview link ${previewId} to become ready${lastProbeCode ? ` (${lastProbeCode})` : ""}`, {
5212
+ timeoutMs,
5196
5213
  origin: "runtime",
5197
5214
  endpoint
5198
5215
  });
5199
5216
  try {
5200
5217
  await delayUntilAborted(Math.min(pollIntervalMs, remainingAfterCheckMs), options?.signal);
5201
5218
  } catch {
5202
- throw new TimeoutError(0, "Aborted", {
5219
+ throw new TimeoutError("Aborted", {
5220
+ timeoutMs: 0,
5203
5221
  origin: "runtime",
5204
5222
  endpoint
5205
5223
  });
@@ -5365,8 +5383,8 @@ var SandboxLifecycleEventsCapabilities = class extends SandboxPreviewCapabilitie
5365
5383
  const timeoutSignal = AbortSignal.timeout(timeoutMs);
5366
5384
  const signal = options?.signal ? combineAbortSignals([options.signal, timeoutSignal]) : timeoutSignal;
5367
5385
  const rethrowWaitError = (error) => {
5368
- if (timeoutSignal.aborted) throw new TimeoutError(timeoutMs, `Timed out waiting for sandbox to reach ${statuses.join(" or ")}`);
5369
- if (options?.signal?.aborted) throw new TimeoutError(0, "Aborted");
5386
+ if (timeoutSignal.aborted) throw new TimeoutError(`Timed out waiting for sandbox to reach ${statuses.join(" or ")}`, { timeoutMs });
5387
+ if (options?.signal?.aborted) throw new TimeoutError("Aborted", { timeoutMs: 0 });
5370
5388
  throw error;
5371
5389
  };
5372
5390
  if (options?.onProgress && (this.status === "provisioning" || this.status === "pending")) try {
@@ -5380,8 +5398,8 @@ var SandboxLifecycleEventsCapabilities = class extends SandboxPreviewCapabilitie
5380
5398
  if (signal.aborted) rethrowWaitError(signal.reason);
5381
5399
  await this.refreshFor("poll", signal).catch(rethrowWaitError);
5382
5400
  if (this.hasReachedWaitTarget(statuses)) return;
5383
- if (this.status === "failed") throw new StateError(this.error ?? "Sandbox failed", this.status);
5384
- if (Date.now() - startTime > timeoutMs) throw new TimeoutError(timeoutMs, `Timed out waiting for sandbox to reach ${statuses.join(" or ")}`);
5401
+ if (this.status === "failed") throw new StateError(this.error ?? "Sandbox failed", { currentState: this.status });
5402
+ if (Date.now() - startTime > timeoutMs) throw new TimeoutError(`Timed out waiting for sandbox to reach ${statuses.join(" or ")}`, { timeoutMs });
5385
5403
  await delayUntilAborted(pollIntervalMs, signal).catch(rethrowWaitError);
5386
5404
  }
5387
5405
  }
@@ -5395,7 +5413,7 @@ var SandboxLifecycleEventsCapabilities = class extends SandboxPreviewCapabilitie
5395
5413
  if (signal) {
5396
5414
  if (signal.aborted) {
5397
5415
  clearTimeout(timeout);
5398
- throw new TimeoutError(0, "Aborted");
5416
+ throw new TimeoutError("Aborted", { timeoutMs: 0 });
5399
5417
  }
5400
5418
  signal.addEventListener("abort", () => abortController.abort(), { once: true });
5401
5419
  }
@@ -5420,17 +5438,17 @@ var SandboxLifecycleEventsCapabilities = class extends SandboxPreviewCapabilitie
5420
5438
  });
5421
5439
  } else if (event.type === "provision_failed") {
5422
5440
  await this.refresh(abortController.signal);
5423
- throw new StateError(event.data.error ?? "Provisioning failed", this.status);
5441
+ throw new StateError(event.data.error ?? "Provisioning failed", { currentState: this.status });
5424
5442
  } else if (event.type === "provision_complete" || event.type === "status_change") {
5425
5443
  await this.refreshFor("poll", abortController.signal);
5426
5444
  if (this.hasReachedWaitTarget(statuses)) return true;
5427
- if (this.status === "failed") throw new StateError(this.error ?? "Sandbox failed", this.status);
5445
+ if (this.status === "failed") throw new StateError(this.error ?? "Sandbox failed", { currentState: this.status });
5428
5446
  }
5429
5447
  await this.refreshFor("poll", abortController.signal);
5430
5448
  if (this.hasReachedWaitTarget(statuses)) return true;
5431
- if (this.status === "failed") throw new StateError(this.error ?? "Sandbox failed", this.status);
5449
+ if (this.status === "failed") throw new StateError(this.error ?? "Sandbox failed", { currentState: this.status });
5432
5450
  if (statuses.includes("running") && this.status === "running") return false;
5433
- throw new TimeoutError(timeoutMs, `SSE stream ended before sandbox reached ${statuses.join(" or ")}`);
5451
+ throw new TimeoutError(`SSE stream ended before sandbox reached ${statuses.join(" or ")}`, { timeoutMs });
5434
5452
  } finally {
5435
5453
  clearTimeout(timeout);
5436
5454
  abortController.abort();
@@ -5450,7 +5468,9 @@ var SandboxLifecycleEventsCapabilities = class extends SandboxPreviewCapabilitie
5450
5468
  */
5451
5469
  consumerConnectionReady() {
5452
5470
  const connection = this.connection;
5453
- if (connection?.edgeStatus === "failed") throw new EdgeNotReadyError(connection.edgeError || `Sandbox ${this.id} public edge failed to attach`, "failed", {
5471
+ if (connection?.edgeStatus === "failed") throw new EdgeNotReadyError(connection.edgeError || `Sandbox ${this.id} public edge failed to attach`, {
5472
+ edgeStatus: "failed",
5473
+ status: 502,
5454
5474
  origin: "sandbox-api",
5455
5475
  endpoint: `/v1/sandboxes/${this.id}`
5456
5476
  });
@@ -5532,7 +5552,10 @@ var SandboxLifecycleCapabilities = class extends SandboxLifecycleEventsCapabilit
5532
5552
  if (diagnostics) local.info.startupDiagnostics = diagnostics;
5533
5553
  }
5534
5554
  async delete(options) {
5535
- if (options?.wait === false && options.until) throw new SandboxError("delete({ wait: false }) cannot also wait until removed", "INVALID_OPTIONS", 400);
5555
+ if (options?.wait === false && options.until) throw new SandboxError("delete({ wait: false }) cannot also wait until removed", {
5556
+ code: "INVALID_OPTIONS",
5557
+ status: 400
5558
+ });
5536
5559
  options?.signal?.throwIfAborted();
5537
5560
  const path = `/v1/sandboxes/${this.id}?wait=false${options?.until === "removed" ? "&until=removed" : ""}`;
5538
5561
  let sawLifecycleConflict = false;
@@ -5590,17 +5613,12 @@ var SandboxLifecycleCapabilities = class extends SandboxLifecycleEventsCapabilit
5590
5613
  }
5591
5614
  };
5592
5615
  /**
5593
- * The platform's typed refusal when one sandbox already has a lifecycle
5594
- * operation in flight: HTTP 409 from `withSandboxLifecycleClaim`
5595
- * (products/sandbox/api/src/routes/sandbox-lifecycle-claim.ts).
5596
- */
5597
- const LIFECYCLE_CONFLICT_CODE = "SANDBOX_LIFECYCLE_IN_PROGRESS";
5598
- /**
5599
5616
  * How long a lifecycle call re-attempts a refusal that only asks it to wait.
5600
5617
  * `resume`, `stop` and `delete` share one lease per sandbox, `lifecycle-<id>`,
5601
5618
  * held past a response while its deferred cleanup runs (the workflow smoke
5602
- * hand-rolls the same retry), so a second call in that window is refused 409;
5603
- * 2 of 2 provider-seam runs (agent-sdk#280) lost a completed turn to it. A
5619
+ * hand-rolls the same retry), so a second call in that window is refused 409
5620
+ * `SANDBOX_LIFECYCLE_IN_PROGRESS` by `withSandboxLifecycleClaim`; 2 of 2
5621
+ * provider-seam runs (agent-sdk#280) lost a completed turn to it. A
5604
5622
  * lease-store or storage outage answers 503 (us1 2026-11-01: 16/16 child
5605
5623
  * deletes failed through a Platform deploy that had removed every child). The
5606
5624
  * ceiling (~11 s) is short: a longer conflict is a real concurrent operation.
@@ -5611,7 +5629,7 @@ const LIFECYCLE_CONFLICT_MAX_DELAY_MS = 4e3;
5611
5629
  /** A lease-store or storage outage the API answers 503 before or after its effect: a retry is safe. */
5612
5630
  const LIFECYCLE_OUTAGE_CODES = new Set(["SANDBOX_LIFECYCLE_COORDINATION_UNAVAILABLE", "STORAGE_UNAVAILABLE"]);
5613
5631
  function isLifecycleConflict(cause) {
5614
- return cause instanceof SandboxError && (cause.status === 409 && cause.code === LIFECYCLE_CONFLICT_CODE || cause.status === 503 && LIFECYCLE_OUTAGE_CODES.has(cause.code));
5632
+ return cause instanceof SandboxError && (cause.status === 409 && cause.wireCode === "SANDBOX_LIFECYCLE_IN_PROGRESS" || cause.status === 503 && LIFECYCLE_OUTAGE_CODES.has(cause.wireCode));
5615
5633
  }
5616
5634
  function lifecycleConflictDelayMs(cause, failedAttempt) {
5617
5635
  if (cause instanceof SandboxError && cause.retryAfterMs !== void 0) return cause.retryAfterMs;
@@ -5661,7 +5679,7 @@ function usableTimeoutMs(timeoutMs) {
5661
5679
  function usableExecutionTtlMs(ttlMs) {
5662
5680
  if (ttlMs === void 0) return void 0;
5663
5681
  const got = timerMsViolation(ttlMs);
5664
- if (got !== void 0) throw new ValidationError(`ttlMs must be an integer between 1 and ${MAX_TIMER_MS}ms; got ${got}`, { ttlMs: "Must be a positive integer of milliseconds" });
5682
+ if (got !== void 0) throw new ValidationError(`ttlMs must be an integer between 1 and ${MAX_TIMER_MS}ms; got ${got}`, { fields: { ttlMs: "Must be a positive integer of milliseconds" } });
5665
5683
  return ttlMs;
5666
5684
  }
5667
5685
  /**
@@ -6582,7 +6600,7 @@ function assertActiveInteractiveControlClaim(control) {
6582
6600
  if (!Number.isFinite(expiresAt) || expiresAt <= Date.now()) throw new Error("Interactive control claim is stale");
6583
6601
  }
6584
6602
  function assertInteractiveRefBelongsToSandbox(ref, sandboxId) {
6585
- if (ref.run.environmentId !== sandboxId) throw new ValidationError("Interactive session reference does not belong to this sandbox", { "ref.run.environmentId": `Expected ${sandboxId}` });
6603
+ if (ref.run.environmentId !== sandboxId) throw new ValidationError("Interactive session reference does not belong to this sandbox", { fields: { "ref.run.environmentId": `Expected ${sandboxId}` } });
6586
6604
  }
6587
6605
  //#endregion
6588
6606
  //#region src/sandbox-ledger.ts
@@ -6624,10 +6642,12 @@ function meterTurn(box, fetch, id) {
6624
6642
  //#endregion
6625
6643
  //#region src/capabilities.ts
6626
6644
  function invalidCapabilities(message) {
6627
- throw new ServerError(`Capability discovery returned ${message}`, 502, {
6645
+ throw new ServerError(`Capability discovery returned ${message}`, {
6646
+ status: 502,
6628
6647
  origin: "runtime",
6629
- endpoint: "/capabilities"
6630
- }, "INVALID_CAPABILITY_DOCUMENT");
6648
+ endpoint: "/capabilities",
6649
+ code: "INVALID_CAPABILITY_DOCUMENT"
6650
+ });
6631
6651
  }
6632
6652
  function readFlagGroup(record, group, keys) {
6633
6653
  const value = record[group];
@@ -6770,7 +6790,8 @@ var SandboxRuntimeOperations = class extends SandboxLifecycleCapabilities {
6770
6790
  try {
6771
6791
  data = JSON.parse(body);
6772
6792
  } catch (error) {
6773
- if (response.ok) throw new NetworkError("Detailed health returned a non-JSON response", error instanceof Error ? error : void 0, {
6793
+ if (response.ok) throw new NetworkError("Detailed health returned a non-JSON response", {
6794
+ cause: error instanceof Error ? error : void 0,
6774
6795
  endpoint: "/health/detailed",
6775
6796
  origin: "runtime"
6776
6797
  });
@@ -6795,9 +6816,9 @@ var SandboxRuntimeOperations = class extends SandboxLifecycleCapabilities {
6795
6816
  if (!response.ok) throw parseErrorResponse(response.status, await response.text());
6796
6817
  const value = await readResponseJson(response);
6797
6818
  const pending = value && typeof value === "object" && "proxySecretReceipt" in value ? ProxySecretReceiptSchema.safeParse(value.proxySecretReceipt) : void 0;
6798
- if (!value || typeof value !== "object" || (pending ? !pending.success || pending.data.status !== "proxy-installed" || pending.data.sandboxId !== this.id || !pending.data.bindings.length || pending.data.bindings.some((binding) => binding.secretRef.key !== cliAuth.secretEnv) || "installed" in value : !("installed" in value) || value.installed !== true) || !("harness" in value) || value.harness !== grant.harness || !("cliAuth" in value)) throw new StateError("Native credential grant receipt is invalid", "unconfirmed");
6819
+ if (!value || typeof value !== "object" || (pending ? !pending.success || pending.data.status !== "proxy-installed" || pending.data.sandboxId !== this.id || !pending.data.bindings.length || pending.data.bindings.some((binding) => binding.secretRef.key !== cliAuth.secretEnv) || "installed" in value : !("installed" in value) || value.installed !== true) || !("harness" in value) || value.harness !== grant.harness || !("cliAuth" in value)) throw new StateError("Native credential grant receipt is invalid", { currentState: "unconfirmed" });
6799
6820
  const confirmed = cliAuthReferenceSchema.safeParse(value.cliAuth);
6800
- if (!confirmed.success || confirmed.data.account !== cliAuth.account || confirmed.data.secretEnv !== cliAuth.secretEnv || confirmed.data.format !== cliAuth.format) throw new StateError("Native credential grant receipt names another reference", "unconfirmed");
6821
+ if (!confirmed.success || confirmed.data.account !== cliAuth.account || confirmed.data.secretEnv !== cliAuth.secretEnv || confirmed.data.format !== cliAuth.format) throw new StateError("Native credential grant receipt names another reference", { currentState: "unconfirmed" });
6801
6822
  }
6802
6823
  /** Deployed capabilities; newer schemas return null, malformed known schemas or transport failures throw. */
6803
6824
  async capabilities() {
@@ -6856,7 +6877,7 @@ var SandboxCodeOperations = class extends SandboxRuntimeOperations {
6856
6877
  blocking: true
6857
6878
  })
6858
6879
  }, timeoutMs + 15e3))).data;
6859
- if (!result || typeof result.exitCode !== "number" || typeof result.stdout !== "string" || typeof result.stderr !== "string") throw new ServerError("Sandbox process response was malformed", 502);
6880
+ if (!result || typeof result.exitCode !== "number" || typeof result.stdout !== "string" || typeof result.stderr !== "string") throw new ServerError("Sandbox process response was malformed", { status: 502 });
6860
6881
  return {
6861
6882
  exitCode: result.exitCode,
6862
6883
  stdout: result.stdout,
@@ -7039,7 +7060,7 @@ var SandboxFileOperations = class extends SandboxExecCapabilities {
7039
7060
  ifAbsent: options?.ifAbsent
7040
7061
  })
7041
7062
  }));
7042
- if (!data.data) throw new ServerError("Invalid file write response: missing data", 502);
7063
+ if (!data.data) throw new ServerError("Invalid file write response: missing data", { status: 502 });
7043
7064
  this.assertWritePreconditions(data.data, {
7044
7065
  expectedHash: options?.ifHash,
7045
7066
  ifAbsent: options?.ifAbsent
@@ -7063,12 +7084,14 @@ var SandboxFileOperations = class extends SandboxExecCapabilities {
7063
7084
  payload = JSON.parse(await response.text());
7064
7085
  } catch (error) {
7065
7086
  if (!(error instanceof SyntaxError)) throw error;
7066
- throw new ServerError("Runtime returned invalid JSON for file read", 502, {
7087
+ throw new ServerError("Runtime returned invalid JSON for file read", {
7088
+ status: 502,
7067
7089
  origin: "runtime",
7068
7090
  endpoint: "/files/read"
7069
7091
  });
7070
7092
  }
7071
- if (typeof payload !== "object" || payload === null || !("success" in payload) || payload.success !== true || !("data" in payload) || typeof payload.data !== "object" || payload.data === null || !("content" in payload.data) || typeof payload.data.content !== "string" || !("encoding" in payload.data) || payload.data.encoding !== "utf8") throw new ServerError("Runtime returned a malformed text file response", 502, {
7093
+ if (typeof payload !== "object" || payload === null || !("success" in payload) || payload.success !== true || !("data" in payload) || typeof payload.data !== "object" || payload.data === null || !("content" in payload.data) || typeof payload.data.content !== "string" || !("encoding" in payload.data) || payload.data.encoding !== "utf8") throw new ServerError("Runtime returned a malformed text file response", {
7094
+ status: 502,
7072
7095
  origin: "runtime",
7073
7096
  endpoint: "/files/read"
7074
7097
  });
@@ -7094,12 +7117,12 @@ var SandboxFileWriteCapabilities = class extends SandboxFileOperations {
7094
7117
  }, response.headers);
7095
7118
  }
7096
7119
  const payload = await response.json().catch(() => null);
7097
- if (!payload?.data?.files || typeof payload.data.files !== "object") throw new ServerError("Invalid file batch write response: missing data.files", 502);
7120
+ if (!payload?.data?.files || typeof payload.data.files !== "object") throw new ServerError("Invalid file batch write response: missing data.files", { status: 502 });
7098
7121
  for (const file of files) {
7099
7122
  const result = payload.data.files[file.path];
7100
- if (!result || typeof result !== "object") throw new ServerError(`Invalid file batch write response: missing result for ${file.path}`, 502);
7123
+ if (!result || typeof result !== "object") throw new ServerError(`Invalid file batch write response: missing result for ${file.path}`, { status: 502 });
7101
7124
  if (result.success === false) {
7102
- if (typeof result.status !== "number" || typeof result.error !== "string" && (typeof result.error !== "object" || result.error === null)) throw new ServerError(`Invalid file batch write failure for ${file.path}`, 502);
7125
+ if (typeof result.status !== "number" || typeof result.error !== "string" && (typeof result.error !== "object" || result.error === null)) throw new ServerError(`Invalid file batch write failure for ${file.path}`, { status: 502 });
7103
7126
  throw parseErrorResponse(result.status, JSON.stringify({
7104
7127
  success: false,
7105
7128
  error: result.error
@@ -7108,7 +7131,7 @@ var SandboxFileWriteCapabilities = class extends SandboxFileOperations {
7108
7131
  path: "/files/write-batch"
7109
7132
  }, response.headers);
7110
7133
  }
7111
- if (result.success !== true || typeof result.path !== "string" || typeof result.hash !== "string" || typeof result.size !== "number" || typeof result.mtime !== "number" || result.preconditionsApplied !== void 0 && (!Array.isArray(result.preconditionsApplied) || !result.preconditionsApplied.every((value) => value === "ifHash" || value === "ifAbsent"))) throw new ServerError(`Invalid file batch write result for ${file.path}`, 502);
7134
+ if (result.success !== true || typeof result.path !== "string" || typeof result.hash !== "string" || typeof result.size !== "number" || typeof result.mtime !== "number" || result.preconditionsApplied !== void 0 && (!Array.isArray(result.preconditionsApplied) || !result.preconditionsApplied.every((value) => value === "ifHash" || value === "ifAbsent"))) throw new ServerError(`Invalid file batch write result for ${file.path}`, { status: 502 });
7112
7135
  this.assertWritePreconditions({
7113
7136
  path: result.path,
7114
7137
  hash: result.hash,
@@ -7135,7 +7158,7 @@ var SandboxFileWriteCapabilities = class extends SandboxFileOperations {
7135
7158
  });
7136
7159
  break;
7137
7160
  } catch (err) {
7138
- if (isTransientWriteError(err) && attempt < maxRetries) {
7161
+ if (isTransientWrite(err) && attempt < maxRetries) {
7139
7162
  const backoff = Math.min(WRITE_MANY_RETRY_BASE_MS * 2 ** attempt, WRITE_MANY_RETRY_MAX_MS);
7140
7163
  await delay((err instanceof SandboxError ? err.retryAfterMs : void 0) ?? backoff);
7141
7164
  continue;
@@ -7240,12 +7263,6 @@ function hasDuplicateWriteManyPaths(files) {
7240
7263
  return new Set(files.map((file) => file.path)).size !== files.length;
7241
7264
  }
7242
7265
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7243
- /** Transient file-write failures worth retrying: rate-limit (quota), 5xx,
7244
- * transport (network), and request timeouts. A non-transient error (bad path,
7245
- * auth, validation) fails loud immediately. */
7246
- function isTransientWriteError(err) {
7247
- return err instanceof QuotaError || err instanceof ServerError || err instanceof NetworkError || err instanceof TimeoutError;
7248
- }
7249
7266
  //#endregion
7250
7267
  //#region src/sandbox-profile.ts
7251
7268
  function isProfileNotCachedError(err) {
@@ -7487,7 +7504,8 @@ var SandboxProfileCapabilities = class extends SandboxFileWriteCapabilities {
7487
7504
  const receipt = await this.postProfileRevision(backend.profile, endpoint, body);
7488
7505
  const digest = /^sha256:[a-f0-9]{64}$/;
7489
7506
  const conflicts = readPublicProfileConflicts(receipt.conflicts);
7490
- if (typeof receipt.workspacePlanDigest !== "string" || !digest.test(receipt.workspacePlanDigest) || typeof receipt.materializedDigest !== "string" || !digest.test(receipt.materializedDigest) || typeof receipt.launchDigest !== "string" || !/^[a-f0-9]{64}$/.test(receipt.launchDigest) || conflicts === void 0) throw new ServerError("Public profile preparation returned an invalid receipt", 502, {
7507
+ if (typeof receipt.workspacePlanDigest !== "string" || !digest.test(receipt.workspacePlanDigest) || typeof receipt.materializedDigest !== "string" || !digest.test(receipt.materializedDigest) || typeof receipt.launchDigest !== "string" || !/^[a-f0-9]{64}$/.test(receipt.launchDigest) || conflicts === void 0) throw new ServerError("Public profile preparation returned an invalid receipt", {
7508
+ status: 502,
7491
7509
  origin: "runtime",
7492
7510
  endpoint
7493
7511
  });
@@ -7519,7 +7537,8 @@ var SandboxProfileCapabilities = class extends SandboxFileWriteCapabilities {
7519
7537
  secret: true
7520
7538
  });
7521
7539
  const receipt = await this.postProfileRevision(backend.profile, endpoint, body);
7522
- if (typeof receipt.workspacePlanDigest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(receipt.workspacePlanDigest) || typeof receipt.executorReceipt !== "string" || !/^hmac-sha256:[a-f0-9]{64}$/.test(receipt.executorReceipt) || !Array.isArray(receipt.conflicts) || !receipt.conflicts.every((conflict) => typeof conflict === "object" && conflict !== null && typeof conflict.relPath === "string" && typeof conflict.copyRelPath === "string" && (conflict.reason === "existing" || conflict.reason === "symlink"))) throw new ServerError("Secret profile preparation returned an invalid receipt", 502, {
7540
+ if (typeof receipt.workspacePlanDigest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(receipt.workspacePlanDigest) || typeof receipt.executorReceipt !== "string" || !/^hmac-sha256:[a-f0-9]{64}$/.test(receipt.executorReceipt) || !Array.isArray(receipt.conflicts) || !receipt.conflicts.every((conflict) => typeof conflict === "object" && conflict !== null && typeof conflict.relPath === "string" && typeof conflict.copyRelPath === "string" && (conflict.reason === "existing" || conflict.reason === "symlink"))) throw new ServerError("Secret profile preparation returned an invalid receipt", {
7541
+ status: 502,
7523
7542
  origin: "runtime",
7524
7543
  endpoint
7525
7544
  });
@@ -7700,7 +7719,8 @@ const InteractionListEnvelopeSchema = z.object({
7700
7719
  data: z.object({ interactions: z.array(InteractionRequestSchema) })
7701
7720
  });
7702
7721
  function invalidRuntimeResponse(message, response, endpoint) {
7703
- return new ServerError(message, 502, {
7722
+ return new ServerError(message, {
7723
+ status: 502,
7704
7724
  origin: "runtime",
7705
7725
  endpoint,
7706
7726
  sidecarVersion: response.headers.get("x-sidecar-version") ?? void 0,
@@ -7748,7 +7768,8 @@ async function readInteractionResult(response, endpoint, sessionId, submitted) {
7748
7768
  }
7749
7769
  /** Convert a command result into the shared retry-safe acknowledgement. */
7750
7770
  function interactionAcknowledgement(command, result) {
7751
- if ("interactionId" in result && (result.binding === void 0 || !bindingsEqual(result.binding, command.binding))) throw new ServerError("Sidecar did not return the exact interaction binding for this command", 502, {
7771
+ if ("interactionId" in result && (result.binding === void 0 || !bindingsEqual(result.binding, command.binding))) throw new ServerError("Sidecar did not return the exact interaction binding for this command", {
7772
+ status: 502,
7752
7773
  origin: "runtime",
7753
7774
  endpoint: "/agents/sessions/:id/interactions"
7754
7775
  });
@@ -7776,7 +7797,7 @@ function commandHttpFailure(command, error) {
7776
7797
  const message = error.message;
7777
7798
  switch (error.status) {
7778
7799
  case 400: return { acknowledgement: commandAcknowledgement(command, "invalid_response", { message }) };
7779
- case 404: return { acknowledgement: commandAcknowledgement(command, error.code === "SESSION_NOT_FOUND" ? "unknown_run" : "unknown_interaction", { message }) };
7800
+ case 404: return { acknowledgement: commandAcknowledgement(command, error.wireCode === "SESSION_NOT_FOUND" ? "unknown_run" : "unknown_interaction", { message }) };
7780
7801
  case 408:
7781
7802
  case 429: return { acknowledgement: commandAcknowledgement(command, "transport_failure", {
7782
7803
  message,
@@ -7824,7 +7845,7 @@ async function listSandboxInteractions(transport, sessionId, options) {
7824
7845
  /** Submit a plain response and preserve the server's durable result. */
7825
7846
  async function submitSandboxInteractionResponse(transport, sessionId, submitted, options) {
7826
7847
  const parsed = InteractionResponseSchema.safeParse(submitted);
7827
- if (!parsed.success) throw new ValidationError("Invalid interaction response", { response: parsed.error.message });
7848
+ if (!parsed.success) throw new ValidationError("Invalid interaction response", { fields: { response: parsed.error.message } });
7828
7849
  await prepareTransport(transport, options?.signal);
7829
7850
  const endpoint = interactionEndpoint(sessionId);
7830
7851
  return readInteractionResult(await transport.fetch(endpoint, {
@@ -7837,9 +7858,9 @@ async function submitSandboxInteractionResponse(transport, sessionId, submitted,
7837
7858
  /** Submit one digest-bound command and return the shared acknowledgement. */
7838
7859
  async function submitSandboxInteractionCommand(transport, sessionId, command, options) {
7839
7860
  const parsed = InteractionResponseCommandSchema.safeParse(command);
7840
- if (!parsed.success) throw new ValidationError("Invalid interaction response command", { commandDigest: parsed.error.message });
7841
- if (parsed.data.binding.sessionId !== sessionId) throw new ValidationError("Interaction response command does not belong to this session", { "binding.sessionId": `Expected ${sessionId}` });
7842
- if (parsed.data.binding.environmentId !== transport.environmentId) throw new ValidationError("Interaction response command does not belong to this sandbox", { "binding.environmentId": `Expected ${transport.environmentId}` });
7861
+ if (!parsed.success) throw new ValidationError("Invalid interaction response command", { fields: { commandDigest: parsed.error.message } });
7862
+ if (parsed.data.binding.sessionId !== sessionId) throw new ValidationError("Interaction response command does not belong to this session", { fields: { "binding.sessionId": `Expected ${sessionId}` } });
7863
+ if (parsed.data.binding.environmentId !== transport.environmentId) throw new ValidationError("Interaction response command does not belong to this sandbox", { fields: { "binding.environmentId": `Expected ${transport.environmentId}` } });
7843
7864
  try {
7844
7865
  await prepareTransport(transport, options?.signal);
7845
7866
  } catch (error) {
@@ -7932,7 +7953,8 @@ var SandboxSessionAdmissionCapabilities = class extends SandboxProfileCapabiliti
7932
7953
  });
7933
7954
  if (!response.ok) throw await parseResponseError(response);
7934
7955
  const info = normalizeSessionInfo(await response.json());
7935
- if (!info) throw new ServerError("Session fork response missing session id", 502, {
7956
+ if (!info) throw new ServerError("Session fork response missing session id", {
7957
+ status: 502,
7936
7958
  origin: "runtime",
7937
7959
  endpoint: `/agents/sessions/${encodeURIComponent(id)}/forks`
7938
7960
  });
@@ -7955,7 +7977,7 @@ var SandboxSessionAdmissionCapabilities = class extends SandboxProfileCapabiliti
7955
7977
  }
7956
7978
  /** @internal — invoked by SandboxSession.interrupt(). */
7957
7979
  async _interrupt(id, options) {
7958
- if (options?.executionId !== void 0 && !options.executionId) throw new ValidationError("executionId must not be empty", { executionId: "Expected a non-empty runtime execution id" });
7980
+ if (options?.executionId !== void 0 && !options.executionId) throw new ValidationError("executionId must not be empty", { fields: { executionId: "Expected a non-empty runtime execution id" } });
7959
7981
  await this.ensureRunning();
7960
7982
  const response = options?.executionId ? await this.runtimeFetch("/agents/run/cancel", {
7961
7983
  method: "POST",
@@ -8000,9 +8022,9 @@ var SandboxSessionAdmissionCapabilities = class extends SandboxProfileCapabiliti
8000
8022
  async _cancelRun(id, request, options) {
8001
8023
  options?.signal?.throwIfAborted();
8002
8024
  const parsedRequest = AgentRunCancellationRequestSchema.safeParse(request);
8003
- if (!parsedRequest.success) throw new ValidationError("Invalid run cancellation request", { requestDigest: parsedRequest.error.message });
8004
- if (parsedRequest.data.run.sessionId !== id) throw new ValidationError("Cancellation request does not belong to this session", { "run.sessionId": `Expected ${id}` });
8005
- if (parsedRequest.data.run.environmentId !== this.id) throw new ValidationError("Cancellation request does not belong to this sandbox", { "run.environmentId": `Expected ${this.id}` });
8025
+ if (!parsedRequest.success) throw new ValidationError("Invalid run cancellation request", { fields: { requestDigest: parsedRequest.error.message } });
8026
+ if (parsedRequest.data.run.sessionId !== id) throw new ValidationError("Cancellation request does not belong to this session", { fields: { "run.sessionId": `Expected ${id}` } });
8027
+ if (parsedRequest.data.run.environmentId !== this.id) throw new ValidationError("Cancellation request does not belong to this sandbox", { fields: { "run.environmentId": `Expected ${this.id}` } });
8006
8028
  await this.ensureRunning();
8007
8029
  options?.signal?.throwIfAborted();
8008
8030
  const response = await this.runtimeFetch("/agents/run/cancel", {
@@ -8017,17 +8039,20 @@ var SandboxSessionAdmissionCapabilities = class extends SandboxProfileCapabiliti
8017
8039
  try {
8018
8040
  raw = JSON.parse(body);
8019
8041
  } catch {
8020
- throw new ServerError("Sidecar returned an invalid cancellation acknowledgement", response.status, {
8042
+ throw new ServerError("Sidecar returned an invalid cancellation acknowledgement", {
8043
+ status: response.status,
8021
8044
  origin: "runtime",
8022
8045
  endpoint: "/agents/run/cancel"
8023
8046
  });
8024
8047
  }
8025
8048
  const acknowledgement = AgentRunCancellationAcknowledgementSchema.safeParse(raw);
8026
- if (!acknowledgement.success) throw new ServerError("Sidecar returned an invalid cancellation acknowledgement", response.status, {
8049
+ if (!acknowledgement.success) throw new ServerError("Sidecar returned an invalid cancellation acknowledgement", {
8050
+ status: response.status,
8027
8051
  origin: "runtime",
8028
8052
  endpoint: "/agents/run/cancel"
8029
8053
  });
8030
- if (!agentRunCancellationAcknowledgementMatchesRequest(parsedRequest.data, acknowledgement.data)) throw new ServerError("Sidecar returned a cancellation acknowledgement for another request", response.status, {
8054
+ if (!agentRunCancellationAcknowledgementMatchesRequest(parsedRequest.data, acknowledgement.data)) throw new ServerError("Sidecar returned a cancellation acknowledgement for another request", {
8055
+ status: response.status,
8031
8056
  origin: "runtime",
8032
8057
  endpoint: "/agents/run/cancel"
8033
8058
  });
@@ -8049,7 +8074,8 @@ var SandboxSessionAdmissionCapabilities = class extends SandboxProfileCapabiliti
8049
8074
  const response = await state(this).client.fetch(path);
8050
8075
  if (response.status === 404) return null;
8051
8076
  const decoded = await readResponseJson(response);
8052
- if (!decoded.plan || typeof decoded.plan.sourceTurnId !== "string" || !decoded.plan.sourceTurnId.trim()) throw new ServerError("Durable plan response is missing plan or original sourceTurnId", 502, {
8077
+ if (!decoded.plan || typeof decoded.plan.sourceTurnId !== "string" || !decoded.plan.sourceTurnId.trim()) throw new ServerError("Durable plan response is missing plan or original sourceTurnId", {
8078
+ status: 502,
8053
8079
  endpoint: path,
8054
8080
  origin: "control-plane"
8055
8081
  });
@@ -8073,11 +8099,13 @@ var SandboxSessionAdmissionCapabilities = class extends SandboxProfileCapabiliti
8073
8099
  "started",
8074
8100
  "completed",
8075
8101
  "failed"
8076
- ].includes(String(followUpState)) || typeof decoded.idempotent !== "boolean") throw new ServerError("Plan decision response is invalid", 502, {
8102
+ ].includes(String(followUpState)) || typeof decoded.idempotent !== "boolean") throw new ServerError("Plan decision response is invalid", {
8103
+ status: 502,
8077
8104
  endpoint: path,
8078
8105
  origin: "control-plane"
8079
8106
  });
8080
- if (options.followUp && decoded.followUp.mode !== "caller") throw new ServerError("Server did not acknowledge caller-owned plan follow-up", 502, {
8107
+ if (options.followUp && decoded.followUp.mode !== "caller") throw new ServerError("Server did not acknowledge caller-owned plan follow-up", {
8108
+ status: 502,
8081
8109
  endpoint: path,
8082
8110
  origin: "control-plane"
8083
8111
  });
@@ -8085,7 +8113,8 @@ var SandboxSessionAdmissionCapabilities = class extends SandboxProfileCapabiliti
8085
8113
  if (decoded.followUp.resume !== void 0) {
8086
8114
  const candidate = decoded.followUp.resume;
8087
8115
  const continuation = PlanContinuationSchema.safeParse(candidate?.continuation);
8088
- if (!continuation.success || typeof candidate.sourceTurnId !== "string" || !candidate.sourceTurnId || typeof candidate.credential !== "string" || !candidate.credential || typeof candidate.callbackUrl !== "string" || !/^https?:\/\//.test(candidate.callbackUrl) || typeof candidate.expiresAt !== "string" || !Number.isFinite(Date.parse(candidate.expiresAt))) throw new ServerError("Caller plan admission response is invalid", 502, {
8116
+ if (!continuation.success || typeof candidate.sourceTurnId !== "string" || !candidate.sourceTurnId || typeof candidate.credential !== "string" || !candidate.credential || typeof candidate.callbackUrl !== "string" || !/^https?:\/\//.test(candidate.callbackUrl) || typeof candidate.expiresAt !== "string" || !Number.isFinite(Date.parse(candidate.expiresAt))) throw new ServerError("Caller plan admission response is invalid", {
8117
+ status: 502,
8089
8118
  endpoint: path,
8090
8119
  origin: "control-plane"
8091
8120
  });
@@ -8118,10 +8147,10 @@ function validatePromptDispatchOptions(sandboxId, options) {
8118
8147
  const validId = (id) => typeof id === "string" && /^[A-Za-z0-9._:-]{1,256}$/u.test(id);
8119
8148
  if (!options.sessionId || options.lastEventId !== void 0 || resume === null || typeof resume !== "object" || Object.keys(resume).sort().join(",") !== "harness,nativeSessionId,sourceCheckpointId" || !["claude-code", "codex"].includes(resume.harness) || !validId(resume.nativeSessionId) || !validId(resume.sourceCheckpointId)) throw new ValidationError("Native resume requires an exact harness, native session, source checkpoint, and new session dispatch");
8120
8149
  }
8121
- if (options?.lastEventId && !options.executionId) throw new ValidationError("lastEventId requires executionId so the SDK can replay the correct execution", { executionId: "Required when lastEventId is set" });
8150
+ if (options?.lastEventId && !options.executionId) throw new ValidationError("lastEventId requires executionId so the SDK can replay the correct execution", { fields: { executionId: "Required when lastEventId is set" } });
8122
8151
  const runControlRef = options?.runControlRef ? AgentExactRunControlRefSchema.safeParse(options.runControlRef) : void 0;
8123
- if (runControlRef && !runControlRef.success) throw new ValidationError("Invalid runControlRef", { runControlRef: runControlRef.error.message });
8124
- if (runControlRef?.success && (runControlRef.data.environmentId !== sandboxId || runControlRef.data.sessionId !== options?.sessionId || runControlRef.data.executionId !== options?.executionId)) throw new ValidationError("runControlRef does not belong to this sandbox dispatch", { runControlRef: "environmentId, sessionId, and executionId must match the dispatch" });
8152
+ if (runControlRef && !runControlRef.success) throw new ValidationError("Invalid runControlRef", { fields: { runControlRef: runControlRef.error.message } });
8153
+ if (runControlRef?.success && (runControlRef.data.environmentId !== sandboxId || runControlRef.data.sessionId !== options?.sessionId || runControlRef.data.executionId !== options?.executionId)) throw new ValidationError("runControlRef does not belong to this sandbox dispatch", { fields: { runControlRef: "environmentId, sessionId, and executionId must match the dispatch" } });
8125
8154
  return runControlRef?.success ? runControlRef.data : void 0;
8126
8155
  }
8127
8156
  var SandboxPromptTransportCapabilities = class extends SandboxSessionAdmissionCapabilities {
@@ -8141,7 +8170,8 @@ var SandboxPromptTransportCapabilities = class extends SandboxSessionAdmissionCa
8141
8170
  const streamSignal = timeoutSignal ? options?.signal ? combineAbortSignals([options.signal, timeoutSignal]) : timeoutSignal : options?.signal;
8142
8171
  const throwIfTimedOut = () => {
8143
8172
  if (!timeoutSignal?.aborted || !timeoutMs) return;
8144
- throw new TimeoutError(timeoutMs, `Prompt stream timed out after ${timeoutMs}ms`, {
8173
+ throw new TimeoutError(`Prompt stream timed out after ${timeoutMs}ms`, {
8174
+ timeoutMs,
8145
8175
  endpoint: "/agents/run/stream",
8146
8176
  origin: "runtime"
8147
8177
  });
@@ -8303,15 +8333,16 @@ var SandboxPromptTransportCapabilities = class extends SandboxSessionAdmissionCa
8303
8333
  });
8304
8334
  const resumeExecutionId = state.executionId;
8305
8335
  const interrupted = (reason, detail, cause) => {
8306
- return new StreamInterruptedError({
8307
- message: `Prompt stream for execution ${resumeExecutionId} ended before a terminal event and could not be rejoined (${detail}); the execution's outcome is unknown${state.lastReplayStatus !== void 0 ? `; last replay status ${state.lastReplayStatus}` : ""}${state.lastExecutionStatus ? `; last known execution status ${state.lastExecutionStatus}` : ""}`,
8336
+ return new StreamInterruptedError(`Prompt stream for execution ${resumeExecutionId} ended before a terminal event and could not be rejoined (${detail}); the execution's outcome is unknown${state.lastReplayStatus !== void 0 ? `; last replay status ${state.lastReplayStatus}` : ""}${state.lastExecutionStatus ? `; last known execution status ${state.lastExecutionStatus}` : ""}`, {
8337
+ origin: "runtime",
8338
+ endpoint: `/agents/run/${resumeExecutionId}/events`,
8308
8339
  executionId: resumeExecutionId,
8309
- ...state.sessionId ? { sessionId: state.sessionId } : {},
8310
- ...state.lastEventId ? { lastEventId: state.lastEventId } : {},
8340
+ sessionId: state.sessionId,
8341
+ lastEventId: state.lastEventId,
8311
8342
  reason,
8312
- ...state.lastReplayStatus !== void 0 ? { lastReplayStatus: state.lastReplayStatus } : {},
8313
- ...state.lastExecutionStatus ? { lastExecutionStatus: state.lastExecutionStatus } : {},
8314
- ...cause !== void 0 ? { cause } : {}
8343
+ lastReplayStatus: state.lastReplayStatus,
8344
+ lastExecutionStatus: state.lastExecutionStatus,
8345
+ cause
8315
8346
  });
8316
8347
  };
8317
8348
  let outageStartedAt = Date.now();
@@ -8399,7 +8430,9 @@ function fromStreamErrorEvent(data) {
8399
8430
  const code = typeof data?.code === "string" && data.code.length > 0 ? data.code : void 0;
8400
8431
  if (status === void 0 && code === void 0) return new ServerError(message);
8401
8432
  const origin = data?.origin;
8402
- const error = new SandboxError(message, code ?? "SERVER_ERROR", status, {
8433
+ const error = new SandboxError(message, {
8434
+ code: code ?? "SERVER_ERROR",
8435
+ status,
8403
8436
  ...origin === "sidecar" || origin === "sandbox-api" || origin === "control-plane" || origin === "runtime" || origin === "unknown" ? { origin } : {},
8404
8437
  ...typeof data?.endpoint === "string" ? { endpoint: data.endpoint } : {},
8405
8438
  ...typeof data?.retryAfterMs === "number" && Number.isFinite(data.retryAfterMs) && data.retryAfterMs >= 0 ? { retryAfterMs: data.retryAfterMs } : {}
@@ -8430,7 +8463,7 @@ function toStreamErrorEvent(err) {
8430
8463
  type: "error",
8431
8464
  data: {
8432
8465
  message: err.message,
8433
- code: err.code,
8466
+ code: err.wireCode,
8434
8467
  name: err.name,
8435
8468
  ...err.status !== void 0 ? { status: err.status } : {},
8436
8469
  ...err.origin ? { origin: err.origin } : {},
@@ -8613,12 +8646,14 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8613
8646
  if (!response.ok) throw await parseResponseError(response);
8614
8647
  const endpoint = `/agents/sessions/${encodeURIComponent(id)}/interactive`;
8615
8648
  const parsed = interactiveSessionStartResponseSchema.safeParse(await response.json());
8616
- if (!parsed.success) throw new ServerError("Interactive session response has an invalid exact identity", 502, {
8649
+ if (!parsed.success) throw new ServerError("Interactive session response has an invalid exact identity", {
8650
+ status: 502,
8617
8651
  endpoint,
8618
8652
  origin: "runtime"
8619
8653
  });
8620
8654
  const result = parsed.data.data;
8621
- if (!agentInteractiveSessionRefMatchesStart(exactStart, result.ref) || !agentInteractiveSessionControlClaimMatchesRef(result.ref, result.control)) throw new ServerError("Interactive session response has an invalid exact identity", 502, {
8655
+ if (!agentInteractiveSessionRefMatchesStart(exactStart, result.ref) || !agentInteractiveSessionControlClaimMatchesRef(result.ref, result.control)) throw new ServerError("Interactive session response has an invalid exact identity", {
8656
+ status: 502,
8622
8657
  endpoint,
8623
8658
  origin: "runtime"
8624
8659
  });
@@ -8631,7 +8666,9 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8631
8666
  if (exactCommand.ref.run.sessionId !== id) throw new ValidationError("Interactive prompt command does not belong to the session");
8632
8667
  await this.ensureRunning(options?.signal);
8633
8668
  const status = await this._interactiveStatus(id, exactCommand.ref.incarnationId, options);
8634
- if (!status) throw new NotFoundError("Interactive session", id, {
8669
+ if (!status) throw new NotFoundError(`Interactive session not found: ${id}`, {
8670
+ resourceType: "Interactive session",
8671
+ resourceId: id,
8635
8672
  origin: "runtime",
8636
8673
  endpoint: `/agents/sessions/${encodeURIComponent(id)}/interactive`
8637
8674
  });
@@ -8643,12 +8680,14 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8643
8680
  ...options?.signal === void 0 ? {} : { signal: options.signal }
8644
8681
  });
8645
8682
  const parsed = interactiveSessionPromptResponseSchema.safeParse(await readResponseJson(response));
8646
- if (!parsed.success) throw new ServerError("Interactive prompt acknowledgement is invalid", 502, {
8683
+ if (!parsed.success) throw new ServerError("Interactive prompt acknowledgement is invalid", {
8684
+ status: 502,
8647
8685
  endpoint,
8648
8686
  origin: "runtime"
8649
8687
  });
8650
8688
  const acknowledgement = parsed.data.data;
8651
- if (!agentInteractiveSessionPromptAcknowledgementMatchesCommand(exactCommand, acknowledgement)) throw new ServerError("Interactive prompt acknowledgement does not match the command", 502, {
8689
+ if (!agentInteractiveSessionPromptAcknowledgementMatchesCommand(exactCommand, acknowledgement)) throw new ServerError("Interactive prompt acknowledgement does not match the command", {
8690
+ status: 502,
8652
8691
  endpoint,
8653
8692
  origin: "runtime"
8654
8693
  });
@@ -8669,12 +8708,14 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8669
8708
  ...options?.signal === void 0 ? {} : { signal: options.signal }
8670
8709
  });
8671
8710
  const parsed = interactiveSessionControlClaimResponseSchema.safeParse(await readResponseJson(response));
8672
- if (!parsed.success) throw new ServerError("Interactive control claim acknowledgement is invalid", 502, {
8711
+ if (!parsed.success) throw new ServerError("Interactive control claim acknowledgement is invalid", {
8712
+ status: 502,
8673
8713
  endpoint,
8674
8714
  origin: "runtime"
8675
8715
  });
8676
8716
  const acknowledgement = parsed.data.data;
8677
- if (!agentInteractiveSessionControlClaimAcknowledgementMatchesRequest(exactRequest, acknowledgement)) throw new ServerError("Interactive control claim acknowledgement does not match the request", 502, {
8717
+ if (!agentInteractiveSessionControlClaimAcknowledgementMatchesRequest(exactRequest, acknowledgement)) throw new ServerError("Interactive control claim acknowledgement does not match the request", {
8718
+ status: 502,
8678
8719
  endpoint,
8679
8720
  origin: "runtime"
8680
8721
  });
@@ -8703,7 +8744,8 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8703
8744
  body: JSON.stringify(claim),
8704
8745
  ...options?.signal === void 0 ? {} : { signal: options.signal }
8705
8746
  });
8706
- if (!interactiveSessionControlReleaseResponseSchema.safeParse(await readResponseJson(response)).success) throw new ServerError("Interactive control release response is invalid", 502, {
8747
+ if (!interactiveSessionControlReleaseResponseSchema.safeParse(await readResponseJson(response)).success) throw new ServerError("Interactive control release response is invalid", {
8748
+ status: 502,
8707
8749
  endpoint,
8708
8750
  origin: "runtime"
8709
8751
  });
@@ -8720,7 +8762,8 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8720
8762
  body: JSON.stringify(claim),
8721
8763
  ...options?.signal === void 0 ? {} : { signal: options.signal }
8722
8764
  });
8723
- if (!interactiveSessionControlValidationResponseSchema.safeParse(await readResponseJson(response)).success) throw new ServerError("Interactive control validation response is invalid", 502, {
8765
+ if (!interactiveSessionControlValidationResponseSchema.safeParse(await readResponseJson(response)).success) throw new ServerError("Interactive control validation response is invalid", {
8766
+ status: 502,
8724
8767
  endpoint,
8725
8768
  origin: "runtime"
8726
8769
  });
@@ -8736,12 +8779,14 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8736
8779
  });
8737
8780
  if (response.status === 404) return null;
8738
8781
  const parsed = interactiveSessionStatusResponseSchema.safeParse(await readResponseJson(response));
8739
- if (!parsed.success) throw new ServerError("Interactive status response has an invalid exact identity", 502, {
8782
+ if (!parsed.success) throw new ServerError("Interactive status response has an invalid exact identity", {
8783
+ status: 502,
8740
8784
  endpoint,
8741
8785
  origin: "runtime"
8742
8786
  });
8743
8787
  const status = parsed.data.data.status;
8744
- if (status.ref.run.sessionId !== id || status.ref.incarnationId !== incarnationId) throw new ServerError("Interactive status response has an invalid exact identity", 502, {
8788
+ if (status.ref.run.sessionId !== id || status.ref.incarnationId !== incarnationId) throw new ServerError("Interactive status response has an invalid exact identity", {
8789
+ status: 502,
8745
8790
  endpoint,
8746
8791
  origin: "runtime"
8747
8792
  });
@@ -8782,12 +8827,14 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8782
8827
  ...options?.signal === void 0 ? {} : { signal: options.signal }
8783
8828
  });
8784
8829
  const parsed = interactiveSessionStopResponseSchema.safeParse(await readResponseJson(response));
8785
- if (!parsed.success) throw new ServerError("Interactive stop acknowledgement is invalid", 502, {
8830
+ if (!parsed.success) throw new ServerError("Interactive stop acknowledgement is invalid", {
8831
+ status: 502,
8786
8832
  endpoint,
8787
8833
  origin: "runtime"
8788
8834
  });
8789
8835
  const acknowledgement = parsed.data.data;
8790
- if (!agentInteractiveSessionStopAcknowledgementMatchesCommand(exactCommand, acknowledgement)) throw new ServerError("Interactive stop acknowledgement does not match the command", 502, {
8836
+ if (!agentInteractiveSessionStopAcknowledgementMatchesCommand(exactCommand, acknowledgement)) throw new ServerError("Interactive stop acknowledgement does not match the command", {
8837
+ status: 502,
8791
8838
  endpoint,
8792
8839
  origin: "runtime"
8793
8840
  });
@@ -8807,12 +8854,14 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8807
8854
  ...options?.signal === void 0 ? {} : { signal: options.signal }
8808
8855
  });
8809
8856
  const parsed = interactiveSessionStopResponseSchema.safeParse(await readResponseJson(response));
8810
- if (!parsed.success) throw new ServerError("Interactive lifecycle stop acknowledgement is invalid", 502, {
8857
+ if (!parsed.success) throw new ServerError("Interactive lifecycle stop acknowledgement is invalid", {
8858
+ status: 502,
8811
8859
  endpoint,
8812
8860
  origin: "runtime"
8813
8861
  });
8814
8862
  const acknowledgement = parsed.data.data;
8815
- if (canonicalCandidateDigest$1(acknowledgement.ref) !== canonicalCandidateDigest$1(exactRef)) throw new ServerError("Interactive lifecycle stop acknowledgement does not match the exact ref", 502, {
8863
+ if (canonicalCandidateDigest$1(acknowledgement.ref) !== canonicalCandidateDigest$1(exactRef)) throw new ServerError("Interactive lifecycle stop acknowledgement does not match the exact ref", {
8864
+ status: 502,
8816
8865
  endpoint,
8817
8866
  origin: "runtime"
8818
8867
  });
@@ -8824,7 +8873,7 @@ var SandboxInteractiveCapabilities = class extends SandboxPromptCapabilities {
8824
8873
  var SandboxSessionEvidenceCapabilities = class extends SandboxInteractiveCapabilities {
8825
8874
  /** @internal — invoked before the sandbox is deleted. */
8826
8875
  async _sessionExportRawEvidence(id, destination, options) {
8827
- const { exportRawEvidenceDirectory } = await import("./raw-evidence-archive-CgbWa4es.js");
8876
+ const { exportRawEvidenceDirectory } = await import("./raw-evidence-archive-BD37zHN5.js");
8828
8877
  await this.ensureRunning();
8829
8878
  await this.refresh();
8830
8879
  return exportRawEvidenceDirectory((signal, archiveId, cancel) => this.runtimeFetch(`/agents/sessions/${encodeURIComponent(id)}/raw-evidence/archive?${new URLSearchParams([
@@ -8855,7 +8904,7 @@ var SandboxSessionEvidenceCapabilities = class extends SandboxInteractiveCapabil
8855
8904
  * and the byte and file bounds are verified before the directory appears.
8856
8905
  */
8857
8906
  async exportRawEvidence(destination, options) {
8858
- const { exportRawEvidenceDirectory } = await import("./raw-evidence-archive-CgbWa4es.js");
8907
+ const { exportRawEvidenceDirectory } = await import("./raw-evidence-archive-BD37zHN5.js");
8859
8908
  await this.ensureRunning();
8860
8909
  await this.refresh();
8861
8910
  return exportRawEvidenceDirectory((signal, archiveId, cancel) => this.runtimeFetch(`/agents/raw-evidence/archive?${new URLSearchParams({
@@ -8967,19 +9016,24 @@ var SandboxSessionEvidenceCapabilities = class extends SandboxInteractiveCapabil
8967
9016
  }
8968
9017
  /** @internal — invoked by SandboxSession.result(). */
8969
9018
  async _sessionResult(id, options, knownSession) {
8970
- if (options?.executionId !== void 0 && !options.executionId) throw new ValidationError("executionId must not be empty", { executionId: "Expected a non-empty runtime execution id" });
9019
+ if (options?.executionId !== void 0 && !options.executionId) throw new ValidationError("executionId must not be empty", { fields: { executionId: "Expected a non-empty runtime execution id" } });
8971
9020
  const startTime = Date.now();
8972
9021
  let executionId = options?.executionId;
8973
9022
  if (!executionId) {
8974
9023
  const session = knownSession ?? await this._sessionStatus(id);
8975
- if (!session) throw new NotFoundError("Session", id, {
9024
+ if (!session) throw new NotFoundError(`Session not found: ${id}`, {
9025
+ resourceType: "Session",
9026
+ resourceId: id,
8976
9027
  origin: "runtime",
8977
9028
  endpoint: `/agents/sessions/${encodeURIComponent(id)}`
8978
9029
  });
8979
- if (!session.latestExecutionId) throw new StateError(`Session ${id} has no execution result to await`, session.status, "session with an admitted execution", {
9030
+ if (!session.latestExecutionId) throw new StateError(`Session ${id} has no execution result to await`, {
9031
+ currentState: session.status,
9032
+ requiredState: "session with an admitted execution",
8980
9033
  origin: "runtime",
8981
- endpoint: `/agents/sessions/${encodeURIComponent(id)}`
8982
- }, "SESSION_EXECUTION_MISSING");
9034
+ endpoint: `/agents/sessions/${encodeURIComponent(id)}`,
9035
+ code: "SESSION_EXECUTION_MISSING"
9036
+ });
8983
9037
  executionId = session.latestExecutionId;
8984
9038
  }
8985
9039
  let resultExecutionId = executionId;
@@ -9091,10 +9145,12 @@ function readModelCalls(value) {
9091
9145
  //#endregion
9092
9146
  //#region src/completed-turn.ts
9093
9147
  function invalidCompletedTurn(message) {
9094
- throw new ServerError(`Completed-turn lookup returned ${message}`, 502, {
9148
+ throw new ServerError(`Completed-turn lookup returned ${message}`, {
9149
+ status: 502,
9095
9150
  origin: "runtime",
9096
- endpoint: "/messages/turns"
9097
- }, "INVALID_COMPLETED_TURN");
9151
+ endpoint: "/messages/turns",
9152
+ code: "INVALID_COMPLETED_TURN"
9153
+ });
9098
9154
  }
9099
9155
  function parseCompletedTurnResult(value, expected) {
9100
9156
  if (value === null || typeof value !== "object" || Array.isArray(value)) invalidCompletedTurn("a non-object record");
@@ -9538,7 +9594,8 @@ var SandboxSessionCapabilities = class extends SandboxSessionEvidenceCapabilitie
9538
9594
  ctrl.abort();
9539
9595
  }
9540
9596
  if (!admissionObserved || !resolvedSessionId || !resolvedExecutionId) throw dispatchError ?? new ServerError("dispatchPrompt did not receive an execution admission from the sandbox");
9541
- if (!resolvedRunControlRef) throw new ServerError("Sandbox admission did not return the exact run reference", 502, {
9597
+ if (!resolvedRunControlRef) throw new ServerError("Sandbox admission did not return the exact run reference", {
9598
+ status: 502,
9542
9599
  origin: "runtime",
9543
9600
  endpoint: "/agents/run/stream"
9544
9601
  });
@@ -9722,7 +9779,11 @@ var SandboxTurnCapabilities = class extends SandboxSessionCapabilities {
9722
9779
  let checked = firstCheck;
9723
9780
  if (!info) {
9724
9781
  if (firstCheck.status === "fulfilled") await firstCheck.value.body?.cancel().catch(() => void 0);
9725
- if (cached) throw new StateError("Retained result has no verifiable conversation admission", "unverified", "verified admission", void 0, "MESSAGE_ADMISSION_UNVERIFIED");
9782
+ if (cached) throw new StateError("Retained result has no verifiable conversation admission", {
9783
+ currentState: "unverified",
9784
+ requiredState: "verified admission",
9785
+ code: "MESSAGE_ADMISSION_UNVERIFIED"
9786
+ });
9726
9787
  if (opts.allowDispatch === false) return { state: "not_admitted" };
9727
9788
  await this.createSession({
9728
9789
  sessionId: opts.sessionId,
@@ -9740,7 +9801,11 @@ var SandboxTurnCapabilities = class extends SandboxSessionCapabilities {
9740
9801
  if (body.requestVerified !== true || !Object.hasOwn(body, "receipt")) throw new Error("Runtime did not verify the durable message admission request");
9741
9802
  let executionId;
9742
9803
  if (body.receipt === null) {
9743
- if (cached) throw new StateError("Retained result has no matching request evidence", "unverified", "verified admission", void 0, "MESSAGE_ADMISSION_UNVERIFIED");
9804
+ if (cached) throw new StateError("Retained result has no matching request evidence", {
9805
+ currentState: "unverified",
9806
+ requiredState: "verified admission",
9807
+ code: "MESSAGE_ADMISSION_UNVERIFIED"
9808
+ });
9744
9809
  if (opts.allowDispatch === false) return { state: "not_admitted" };
9745
9810
  if (isSessionInFlight(info)) return { state: "running" };
9746
9811
  const receipt = await this.session(opts.sessionId).sendMessage(request, {
@@ -9816,7 +9881,7 @@ const SNAPSHOT_DELETE_RETAINED_RETRY_MS = 2e3;
9816
9881
  const HELD_REASONS = new Set(["resume_generation_unconfirmed", "snapshot_delete_in_flight"]);
9817
9882
  /** A hold the platform says to wait out, named by the body's typed `reason`. */
9818
9883
  function isRetainedHold(cause, reason) {
9819
- return cause.status === 409 && cause.code === "RESUME_SNAPSHOT_RETAINED" && typeof reason === "string" && HELD_REASONS.has(reason);
9884
+ return cause.status === 409 && cause.wireCode === "RESUME_SNAPSHOT_RETAINED" && typeof reason === "string" && HELD_REASONS.has(reason);
9820
9885
  }
9821
9886
  function interpretWorkspaceOperationLookup(body, kind) {
9822
9887
  const outcome = body?.outcome;
@@ -9881,7 +9946,7 @@ var SandboxSnapshotCapabilities = class extends SandboxTurnCapabilities {
9881
9946
  }, { timeoutMs: SNAPSHOT_CREATE_REQUEST_TIMEOUT_MS });
9882
9947
  const data = await readResponseJson(response);
9883
9948
  const snapshotId = data.snapshotId ?? data.id;
9884
- if (typeof snapshotId !== "string" || snapshotId.length === 0) throw new ServerError(`Snapshot create returned 200 but body had no snapshot ID: ${JSON.stringify(data).slice(0, 200)}`, response.status);
9949
+ if (typeof snapshotId !== "string" || snapshotId.length === 0) throw new ServerError(`Snapshot create returned 200 but body had no snapshot ID: ${JSON.stringify(data).slice(0, 200)}`, { status: response.status });
9885
9950
  const reportedOutcome = data.idempotency?.outcome;
9886
9951
  const reportedDigest = data.idempotency?.requestDigest;
9887
9952
  const idempotency = (reportedOutcome === "created" || reportedOutcome === "replayed") && typeof reportedDigest === "string" ? {
@@ -9918,7 +9983,7 @@ var SandboxSnapshotCapabilities = class extends SandboxTurnCapabilities {
9918
9983
  sandboxId: this.id
9919
9984
  }), state(this).client);
9920
9985
  const snapshotId = body.snapshotId ?? body.id;
9921
- if (typeof snapshotId !== "string" || snapshotId.length === 0) throw new ServerError(`Snapshot create returned ${response.status} but body had no snapshot ID: ${JSON.stringify(body).slice(0, 200)}`, response.status);
9986
+ if (typeof snapshotId !== "string" || snapshotId.length === 0) throw new ServerError(`Snapshot create returned ${response.status} but body had no snapshot ID: ${JSON.stringify(body).slice(0, 200)}`, { status: response.status });
9922
9987
  return SandboxOperation.completed("snapshot", this.id, { snapshot: {
9923
9988
  snapshotId,
9924
9989
  createdAt: new Date(typeof body.createdAt === "string" ? body.createdAt : Date.now()),
@@ -10083,7 +10148,7 @@ var SandboxSnapshotCapabilities = class extends SandboxTurnCapabilities {
10083
10148
  polledAt = Date.now();
10084
10149
  status = await readResponseJson(await state(this).client.fetch(`/v1/sandboxes/${this.id}/snapshots/jobs/${encodeURIComponent(accepted.jobId)}?waitMs=${SNAPSHOT_RESTORE_HOLD_MS}`));
10085
10150
  }
10086
- throw new TimeoutError(SNAPSHOT_RESTORE_TIMEOUT_MS);
10151
+ throw new TimeoutError(`Request timed out after ${SNAPSHOT_RESTORE_TIMEOUT_MS}ms`, { timeoutMs: SNAPSHOT_RESTORE_TIMEOUT_MS });
10087
10152
  }
10088
10153
  async waitForSnapshotVisible(snapshotId, fallback) {
10089
10154
  const deadline = Date.now() + SNAPSHOT_VISIBILITY_TIMEOUT_MS;
@@ -10110,7 +10175,7 @@ var SandboxSnapshotCapabilities = class extends SandboxTurnCapabilities {
10110
10175
  sizeBytes: fallback.sizeBytes,
10111
10176
  tags: fallback.tags ?? []
10112
10177
  };
10113
- throw lastError instanceof Error ? lastError : new TimeoutError(SNAPSHOT_VISIBILITY_TIMEOUT_MS);
10178
+ throw lastError instanceof Error ? lastError : new TimeoutError(`Request timed out after ${SNAPSHOT_VISIBILITY_TIMEOUT_MS}ms`, { timeoutMs: SNAPSHOT_VISIBILITY_TIMEOUT_MS });
10114
10179
  }
10115
10180
  /**
10116
10181
  * Restore from the latest snapshot in customer-provided storage.
@@ -10224,7 +10289,7 @@ var SandboxBranchCapabilities = class extends SandboxSnapshotCapabilities {
10224
10289
  })
10225
10290
  });
10226
10291
  const data = await readResponseJson(response);
10227
- if (typeof data.rolloutId !== "string" || data.rolloutId.length === 0) throw new ServerError(`Rollout create returned ${response.status} but body had no rolloutId: ${JSON.stringify(data).slice(0, 200)}`, response.status);
10292
+ if (typeof data.rolloutId !== "string" || data.rolloutId.length === 0) throw new ServerError(`Rollout create returned ${response.status} but body had no rolloutId: ${JSON.stringify(data).slice(0, 200)}`, { status: response.status });
10228
10293
  return data;
10229
10294
  }
10230
10295
  /**
@@ -10250,10 +10315,10 @@ var SandboxBranchCapabilities = class extends SandboxSnapshotCapabilities {
10250
10315
  const pollIntervalMs = options?.pollIntervalMs ?? 2e3;
10251
10316
  const startTime = Date.now();
10252
10317
  while (true) {
10253
- if (options?.signal?.aborted) throw new TimeoutError(0, "Aborted");
10318
+ if (options?.signal?.aborted) throw new TimeoutError("Aborted", { timeoutMs: 0 });
10254
10319
  const record = await this.getRollout(rolloutId);
10255
10320
  if (record.status !== "running") return record;
10256
- if (Date.now() - startTime > timeoutMs) throw new TimeoutError(timeoutMs, `Timed out waiting for rollout ${rolloutId} to settle`);
10321
+ if (Date.now() - startTime > timeoutMs) throw new TimeoutError(`Timed out waiting for rollout ${rolloutId} to settle`, { timeoutMs });
10257
10322
  await this.sleep(pollIntervalMs);
10258
10323
  }
10259
10324
  }
@@ -10286,7 +10351,11 @@ async function fetchTeeSurface(client, sandboxId, surface, init) {
10286
10351
  const response = await client.fetch(path, init);
10287
10352
  if (response.ok) return response;
10288
10353
  const body = await response.text();
10289
- if (response.status === 404 && isRouterNotFound(body)) throw new CapabilityError(`TEE ${surface} is not served by this deployment. The /tee paths are answered by a Tangle confidential operator that intercepts them before the sandbox API; a sandbox reached through the public API has no such route. Point the client at the operator, or create the sandbox with driver.type "tangle" on a deployment that fronts it.`, "TEE_UNSUPPORTED", 404, void 0, "tee");
10354
+ if (response.status === 404 && isRouterNotFound(body)) throw new CapabilityError(`TEE ${surface} is not served by this deployment. The /tee paths are answered by a Tangle confidential operator that intercepts them before the sandbox API; a sandbox reached through the public API has no such route. Point the client at the operator, or create the sandbox with driver.type "tangle" on a deployment that fronts it.`, {
10355
+ code: "TEE_UNSUPPORTED",
10356
+ status: 404,
10357
+ capability: "tee"
10358
+ });
10290
10359
  throw parseErrorResponse(response.status, body, void 0, response.headers);
10291
10360
  }
10292
10361
  //#endregion
@@ -10424,7 +10493,10 @@ var SandboxAccessCapabilities = class extends SandboxBranchCapabilities {
10424
10493
  */
10425
10494
  async ssh() {
10426
10495
  await this.ensureRunning();
10427
- if (!this.connection?.ssh) throw new StateError("SSH is not enabled for this sandbox", this.status, "running");
10496
+ if (!this.connection?.ssh) throw new StateError("SSH is not enabled for this sandbox", {
10497
+ currentState: this.status,
10498
+ requiredState: "running"
10499
+ });
10428
10500
  return this.connection.ssh;
10429
10501
  }
10430
10502
  async sshCommand() {
@@ -10735,14 +10807,14 @@ var SandboxEgressOperations = class {
10735
10807
  const response = await this.host.fetch(`/v1/sandboxes/${encodeURIComponent(this.host.id())}/egress/denials${query}`);
10736
10808
  if (!response.ok) throw await parseResponseError(response);
10737
10809
  const body = await readEgressJson(response, "Egress denials response was malformed: body is not valid JSON");
10738
- if (typeof body !== "object" || body === null || Array.isArray(body)) throw new ServerError("Egress denials response was malformed: body is not an object", 502);
10810
+ if (typeof body !== "object" || body === null || Array.isArray(body)) throw new ServerError("Egress denials response was malformed: body is not an object", { status: 502 });
10739
10811
  const raw = body.denials;
10740
10812
  if (raw === void 0 || raw === null) return [];
10741
- if (!Array.isArray(raw)) throw new ServerError("Egress denials response was malformed: denials is not a list", 502);
10813
+ if (!Array.isArray(raw)) throw new ServerError("Egress denials response was malformed: denials is not a list", { status: 502 });
10742
10814
  const denials = [];
10743
10815
  for (const [index, entry] of raw.entries()) {
10744
10816
  const row = entry;
10745
- if (typeof row !== "object" || row === null || typeof row.host !== "string" || typeof row.rejectedBy !== "string" || typeof row.count !== "number" || !Number.isInteger(row.count) || row.count < 0 || row.lastAt !== void 0 && row.lastAt !== null && typeof row.lastAt !== "string") throw new ServerError(`Egress denials response was malformed: entry ${index} is not a denial`, 502);
10817
+ if (typeof row !== "object" || row === null || typeof row.host !== "string" || typeof row.rejectedBy !== "string" || typeof row.count !== "number" || !Number.isInteger(row.count) || row.count < 0 || row.lastAt !== void 0 && row.lastAt !== null && typeof row.lastAt !== "string") throw new ServerError(`Egress denials response was malformed: entry ${index} is not a denial`, { status: 502 });
10746
10818
  denials.push(row.lastAt === void 0 || row.lastAt === null ? {
10747
10819
  host: row.host,
10748
10820
  rejectedBy: row.rejectedBy,
@@ -10772,7 +10844,7 @@ var SandboxEgressOperations = class {
10772
10844
  const row = typeof usage === "object" && usage !== null && !Array.isArray(usage) ? usage : void 0;
10773
10845
  const count = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
10774
10846
  const usd = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
10775
- if (!row || typeof row.sandboxId !== "string" || typeof row.month !== "string" || row.plan !== "free" && row.plan !== "pro" && row.plan !== "enterprise" || !count(row.bytes) || !usd(row.chargeUsd) || !usd(row.usdPerGb) || !count(row.accountBytes) || !count(row.accountIncludedBytes) || !count(row.accountOverageBytes)) throw new ServerError("Egress usage response was malformed: usage is not a month record", 502);
10847
+ if (!row || typeof row.sandboxId !== "string" || typeof row.month !== "string" || row.plan !== "free" && row.plan !== "pro" && row.plan !== "enterprise" || !count(row.bytes) || !usd(row.chargeUsd) || !usd(row.usdPerGb) || !count(row.accountBytes) || !count(row.accountIncludedBytes) || !count(row.accountOverageBytes)) throw new ServerError("Egress usage response was malformed: usage is not a month record", { status: 502 });
10776
10848
  return {
10777
10849
  sandboxId: row.sandboxId,
10778
10850
  month: row.month,
@@ -10803,11 +10875,11 @@ var SandboxEgressOperations = class {
10803
10875
  const response = await this.host.fetch(`/v1/sandboxes/${encodeURIComponent(this.host.id())}/egress/activity${query}`);
10804
10876
  if (!response.ok) throw await parseResponseError(response);
10805
10877
  const body = await readEgressJson(response, "Egress activity response was malformed: body is not valid JSON");
10806
- if (typeof body !== "object" || body === null || Array.isArray(body)) throw new ServerError("Egress activity response was malformed: body is not an object", 502);
10878
+ if (typeof body !== "object" || body === null || Array.isArray(body)) throw new ServerError("Egress activity response was malformed: body is not an object", { status: 502 });
10807
10879
  const raw = body.activity;
10808
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new ServerError("Egress activity response was malformed: activity is not a record", 502);
10880
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new ServerError("Egress activity response was malformed: activity is not a record", { status: 502 });
10809
10881
  const record = raw;
10810
- if (typeof record.complete !== "boolean" || typeof record.requestsObserved !== "number" || !Number.isInteger(record.requestsObserved) || record.requestsObserved < 0 || typeof record.unparsedLines !== "number" || !Number.isInteger(record.unparsedLines) || record.unparsedLines < 0 || !Array.isArray(record.destinations) || !Array.isArray(record.incompleteReasons) || !record.incompleteReasons.every((one) => typeof one === "string") || record.complete !== (record.incompleteReasons.length === 0)) throw new ServerError("Egress activity response was malformed: activity is not an activity record", 502);
10882
+ if (typeof record.complete !== "boolean" || typeof record.requestsObserved !== "number" || !Number.isInteger(record.requestsObserved) || record.requestsObserved < 0 || typeof record.unparsedLines !== "number" || !Number.isInteger(record.unparsedLines) || record.unparsedLines < 0 || !Array.isArray(record.destinations) || !Array.isArray(record.incompleteReasons) || !record.incompleteReasons.every((one) => typeof one === "string") || record.complete !== (record.incompleteReasons.length === 0)) throw new ServerError("Egress activity response was malformed: activity is not an activity record", { status: 502 });
10811
10883
  const destinations = [];
10812
10884
  for (const [index, entry] of record.destinations.entries()) {
10813
10885
  const row = entry;
@@ -10818,7 +10890,7 @@ var SandboxEgressOperations = class {
10818
10890
  ].every((field) => {
10819
10891
  const value = row[field];
10820
10892
  return value === void 0 || value === null || typeof value === "string";
10821
- })) throw new ServerError(`Egress activity response was malformed: destination ${index} is not a destination`, 502);
10893
+ })) throw new ServerError(`Egress activity response was malformed: destination ${index} is not a destination`, { status: 502 });
10822
10894
  destinations.push({
10823
10895
  host: row.host,
10824
10896
  action: row.action,
@@ -10842,7 +10914,7 @@ async function readEgressJson(response, message) {
10842
10914
  try {
10843
10915
  return await response.json();
10844
10916
  } catch (cause) {
10845
- const error = new ServerError(message, 502);
10917
+ const error = new ServerError(message, { status: 502 });
10846
10918
  error.cause = cause;
10847
10919
  throw error;
10848
10920
  }
@@ -10962,7 +11034,7 @@ var SandboxFilesystemOperations = class extends DeclaredFilesystemOperations {
10962
11034
  totalBytes: size,
10963
11035
  percentage: 0
10964
11036
  });
10965
- const { uploadChunkedFromFile } = await import("./chunked-upload-file-HLSriv3V.js");
11037
+ const { uploadChunkedFromFile } = await import("./chunked-upload-file-DL1-AqRp.js");
10966
11038
  await uploadChunkedFromFile({ fetch: (path, init) => this.host.runtimeFetch(path, init) }, remotePath, localPath, {
10967
11039
  mode: options?.permissions,
10968
11040
  onProgress: options?.onProgress ? (progress) => {
@@ -11087,7 +11159,7 @@ const REFUSED_DIAL_TTL_MS = 5 * 6e4;
11087
11159
  * the scoped-token dial that follows tells them apart.
11088
11160
  */
11089
11161
  function isUpgradeRefusal(error) {
11090
- return error instanceof TerminalStreamError && error.beforeOpen;
11162
+ return error instanceof TerminalStreamError && error.beforeOpen === true;
11091
11163
  }
11092
11164
  /** Transport failures before `ready`; a protocol error frame is the terminal's own answer. */
11093
11165
  const EDGE_DIAL_FAILURES = new Set([
@@ -11100,7 +11172,7 @@ const EDGE_DIAL_FAILURES = new Set([
11100
11172
  * dropped, closed before `ready` or timed out.
11101
11173
  */
11102
11174
  function isEdgeDialFailure(error) {
11103
- return error instanceof TerminalStreamError && (error.beforeOpen || EDGE_DIAL_FAILURES.has(error.code));
11175
+ return error instanceof TerminalStreamError && (error.beforeOpen || EDGE_DIAL_FAILURES.has(error.wireCode));
11104
11176
  }
11105
11177
  /**
11106
11178
  * Hold the caller's `onClose` until the stream is ready. A dial that is
@@ -11239,7 +11311,10 @@ var SandboxInteractiveTerminalOperations = class {
11239
11311
  * (`/v1/sandboxes/{id}/runtime`) that `new URL(absolutePath, base)` would drop.
11240
11312
  */
11241
11313
  resolveTerminalStreamUrl(sidecarProxyUrl, streamPath) {
11242
- if (!streamPath.startsWith("/")) throw new ServerError(`Terminal stream path must be sandbox-relative (got "${streamPath}")`, 502, { origin: "runtime" });
11314
+ if (!streamPath.startsWith("/")) throw new ServerError(`Terminal stream path must be sandbox-relative (got "${streamPath}")`, {
11315
+ status: 502,
11316
+ origin: "runtime"
11317
+ });
11243
11318
  return `${sidecarProxyUrl.replace(/\/+$/, "")}${streamPath}`;
11244
11319
  }
11245
11320
  /** @internal — invoked by InteractiveSessionHandle.attach(). */
@@ -11287,14 +11362,19 @@ var SandboxInteractiveTerminalOperations = class {
11287
11362
  if (exactRef.run.sessionId !== id) throw new ValidationError("Interactive attach ref does not belong to the session");
11288
11363
  assertInteractiveRefBelongsToSandbox(exactRef, this.host.id);
11289
11364
  const status = await this.host.interactiveStatus(id, exactRef.incarnationId, options);
11290
- if (!status) throw new NotFoundError("Interactive session", id, {
11365
+ if (!status) throw new NotFoundError(`Interactive session not found: ${id}`, {
11366
+ resourceType: "Interactive session",
11367
+ resourceId: id,
11291
11368
  origin: "runtime",
11292
11369
  endpoint: `/agents/sessions/${encodeURIComponent(id)}/interactive`
11293
11370
  });
11294
- if (status.state !== "running") throw new StateError(`Interactive session ${id} has exited; there is no live PTY to attach`, status.state, "running", {
11371
+ if (status.state !== "running") throw new StateError(`Interactive session ${id} has exited; there is no live PTY to attach`, {
11372
+ currentState: status.state,
11373
+ requiredState: "running",
11295
11374
  origin: "runtime",
11296
- endpoint: `/agents/sessions/${encodeURIComponent(id)}/interactive`
11297
- }, "INTERACTIVE_SESSION_EXITED");
11375
+ endpoint: `/agents/sessions/${encodeURIComponent(id)}/interactive`,
11376
+ code: "INTERACTIVE_SESSION_EXITED"
11377
+ });
11298
11378
  if (canonicalCandidateDigest$1(status.ref) !== canonicalCandidateDigest$1(exactRef)) throw new ValidationError("Interactive attach ref does not match the current session");
11299
11379
  return exactRef;
11300
11380
  }
@@ -11533,7 +11613,7 @@ async function readBoundedResponseText(response, signal) {
11533
11613
  const declaredBytes = Number(response.headers.get("content-length"));
11534
11614
  if (Number.isFinite(declaredBytes) && declaredBytes > MAX_WORKSPACE_IMAGE_RESPONSE_BYTES) {
11535
11615
  response.body?.cancel();
11536
- throw new ServerError("Sandbox API returned an oversized workspace image response", 502);
11616
+ throw new ServerError("Sandbox API returned an oversized workspace image response", { status: 502 });
11537
11617
  }
11538
11618
  if (!response.body) return "";
11539
11619
  const reader = response.body.getReader();
@@ -11551,7 +11631,7 @@ async function readBoundedResponseText(response, signal) {
11551
11631
  const { done, value } = await Promise.race([reader.read(), aborted]);
11552
11632
  if (done) break;
11553
11633
  totalBytes += value.byteLength;
11554
- if (totalBytes > MAX_WORKSPACE_IMAGE_RESPONSE_BYTES) throw new ServerError("Sandbox API returned an oversized workspace image response", 502);
11634
+ if (totalBytes > MAX_WORKSPACE_IMAGE_RESPONSE_BYTES) throw new ServerError("Sandbox API returned an oversized workspace image response", { status: 502 });
11555
11635
  chunks.push(value);
11556
11636
  }
11557
11637
  } catch (error) {
@@ -11590,7 +11670,8 @@ var WorkspaceImages = class {
11590
11670
  await awaitWithSignal(this.ensureRunning(), signal);
11591
11671
  } catch (error) {
11592
11672
  throwIfAborted(options.signal);
11593
- if (timeoutSignal.aborted || Date.now() >= deadline) throw new TimeoutError(timeoutMs, `Workspace image publication timed out after ${timeoutMs}ms`, {
11673
+ if (timeoutSignal.aborted || Date.now() >= deadline) throw new TimeoutError(`Workspace image publication timed out after ${timeoutMs}ms`, {
11674
+ timeoutMs,
11594
11675
  origin: "sandbox-api",
11595
11676
  endpoint: path
11596
11677
  });
@@ -11598,7 +11679,11 @@ var WorkspaceImages = class {
11598
11679
  }
11599
11680
  throwIfAborted(options.signal);
11600
11681
  const filesystemIncarnationId = this.filesystemIncarnationId();
11601
- if (!filesystemIncarnationId) throw new StateError("Sandbox filesystem incarnation is not ready", "running", "running with a ready filesystem incarnation", void 0, "FILESYSTEM_INCARNATION_NOT_READY");
11682
+ if (!filesystemIncarnationId) throw new StateError("Sandbox filesystem incarnation is not ready", {
11683
+ currentState: "running",
11684
+ requiredState: "running with a ready filesystem incarnation",
11685
+ code: "FILESYSTEM_INCARNATION_NOT_READY"
11686
+ });
11602
11687
  const idempotencyKey = options.idempotencyKey ?? createIdempotencyKey();
11603
11688
  const body = JSON.stringify({
11604
11689
  ...input,
@@ -11606,7 +11691,8 @@ var WorkspaceImages = class {
11606
11691
  });
11607
11692
  for (let attempt = 1; attempt <= WORKSPACE_IMAGE_REQUEST_ATTEMPTS; attempt++) {
11608
11693
  const remainingMs = deadline - Date.now();
11609
- if (remainingMs <= 0) throw new TimeoutError(timeoutMs, `Workspace image publication timed out after ${timeoutMs}ms`, {
11694
+ if (remainingMs <= 0) throw new TimeoutError(`Workspace image publication timed out after ${timeoutMs}ms`, {
11695
+ timeoutMs,
11610
11696
  origin: "sandbox-api",
11611
11697
  endpoint: path
11612
11698
  });
@@ -11625,13 +11711,15 @@ var WorkspaceImages = class {
11625
11711
  responseText = await readBoundedResponseText(response, signal);
11626
11712
  } catch (error) {
11627
11713
  throwIfAborted(options.signal);
11628
- if (timeoutSignal.aborted || Date.now() >= deadline) throw new TimeoutError(timeoutMs, `Workspace image publication timed out after ${timeoutMs}ms`, {
11714
+ if (timeoutSignal.aborted || Date.now() >= deadline) throw new TimeoutError(`Workspace image publication timed out after ${timeoutMs}ms`, {
11715
+ timeoutMs,
11629
11716
  origin: "sandbox-api",
11630
11717
  endpoint: path
11631
11718
  });
11632
11719
  if (error instanceof ServerError) throw error;
11633
11720
  if (attempt < WORKSPACE_IMAGE_REQUEST_ATTEMPTS && Date.now() < deadline) continue;
11634
- throw new NetworkError("Failed to read the workspace image publication response", error instanceof Error ? error : new Error(String(error)), {
11721
+ throw new NetworkError("Failed to read the workspace image publication response", {
11722
+ cause: error instanceof Error ? error : new Error(String(error)),
11635
11723
  origin: "sandbox-api",
11636
11724
  endpoint: path
11637
11725
  });
@@ -11641,7 +11729,7 @@ var WorkspaceImages = class {
11641
11729
  method: "POST",
11642
11730
  path
11643
11731
  }, response.headers);
11644
- if (error.code === "IMAGE_PUBLISH_OUTCOME_UNKNOWN" && attempt < WORKSPACE_IMAGE_REQUEST_ATTEMPTS && Date.now() < deadline) continue;
11732
+ if (error.wireCode === "IMAGE_PUBLISH_OUTCOME_UNKNOWN" && attempt < WORKSPACE_IMAGE_REQUEST_ATTEMPTS && Date.now() < deadline) continue;
11645
11733
  throw error;
11646
11734
  }
11647
11735
  const parsed = parseWorkspaceImagePublishResultForRepository((() => {
@@ -11651,13 +11739,15 @@ var WorkspaceImages = class {
11651
11739
  return;
11652
11740
  }
11653
11741
  })(), input.repository);
11654
- if (!parsed) throw new ServerError("Sandbox API returned an invalid workspace image result", 502, {
11742
+ if (!parsed) throw new ServerError("Sandbox API returned an invalid workspace image result", {
11743
+ status: 502,
11655
11744
  origin: "sandbox-api",
11656
11745
  endpoint: path
11657
11746
  });
11658
11747
  return parsed;
11659
11748
  }
11660
- throw new ServerError("Sandbox API did not return a workspace image result", 502, {
11749
+ throw new ServerError("Sandbox API did not return a workspace image result", {
11750
+ status: 502,
11661
11751
  origin: "sandbox-api",
11662
11752
  endpoint: path
11663
11753
  });
@@ -11820,7 +11910,10 @@ var SandboxInstance = class SandboxInstance extends SandboxEgressCapabilities {
11820
11910
  */
11821
11911
  direct() {
11822
11912
  const data = state(this);
11823
- if (!this.connection?.hostUrl && !this.connection?.execHost && !this.connection?.runtimeUrl) throw new StateError("Sandbox has no direct runtime URL", this.status, "running");
11913
+ if (!this.connection?.hostUrl && !this.connection?.execHost && !this.connection?.runtimeUrl) throw new StateError("Sandbox has no direct runtime URL", {
11914
+ currentState: this.status,
11915
+ requiredState: "running"
11916
+ });
11824
11917
  let directInstance;
11825
11918
  directInstance = new SandboxInstance(new DirectRuntimeHttpClient(data.client, this.id, () => directInstance.connection, async () => {
11826
11919
  await directInstance.refreshFor("bearer-refused");
@@ -11831,7 +11924,10 @@ var SandboxInstance = class SandboxInstance extends SandboxEgressCapabilities {
11831
11924
  try {
11832
11925
  await directInstance.refreshFor("runtime-refused");
11833
11926
  } catch (error) {
11834
- if (error instanceof NotFoundError) throw new StateError("Sandbox is not running (status: deleted)", "deleted", "running");
11927
+ if (error instanceof NotFoundError) throw new StateError("Sandbox is not running (status: deleted)", {
11928
+ currentState: "deleted",
11929
+ requiredState: "running"
11930
+ });
11835
11931
  return;
11836
11932
  }
11837
11933
  directInstance.assertRunnable();