@tangle-network/sandbox 0.60.25 → 0.60.26-develop.20261008100338.fdb71c8

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 (34) hide show
  1. package/README.md +28 -0
  2. package/dist/agent/index.d.ts +4 -4
  3. package/dist/agent/index.js +4 -4
  4. package/dist/agent/preview.d.ts +1 -1
  5. package/dist/{agent-run-outcome-BMRvIstg.d.ts → agent-run-outcome-D5VVd5Ei.d.ts} +4 -2
  6. package/dist/auth/index.js +1 -1
  7. package/dist/{cli-auth-bundle-xnHi1LpC.js → cli-auth-bundle-CZfgymgf.js} +3 -3
  8. package/dist/{client-JaupThcm.js → client-B4ehn1iw.js} +5 -5
  9. package/dist/{client-BFOltIeq.d.ts → client-DqA0N91W.d.ts} +4 -4
  10. package/dist/collaboration/index.js +1 -1
  11. package/dist/{collaboration-CFe2H--1.js → collaboration-D15xoinI.js} +1 -1
  12. package/dist/core.d.ts +5 -5
  13. package/dist/core.js +3 -3
  14. package/dist/{errors-DS32ViPj.d.ts → errors-BXMXbVFO.d.ts} +32 -1
  15. package/dist/{errors-C1c3Q6Bj.js → errors-DMxVFCS6.js} +34 -1
  16. package/dist/{index-DaQYTQXD.d.ts → index-Dv77g3s5.d.ts} +2 -2
  17. package/dist/index.d.ts +18 -8
  18. package/dist/index.js +8 -7
  19. package/dist/intelligence/index.js +1 -1
  20. package/dist/{interactive-controller-DtX6fHC6.js → interactive-controller-4Fo9aDih.js} +100 -7
  21. package/dist/{lines-CJK_ysel.d.ts → lines-d9AEcbCd.d.ts} +22 -6
  22. package/dist/lines.d.ts +1 -1
  23. package/dist/lines.js +8 -5
  24. package/dist/{local-cli-auth-Ch35WOLn.js → local-cli-auth-CwrrtpaB.js} +1 -1
  25. package/dist/{preview-BM4uaIvf.d.ts → preview-CCAwjkRr.d.ts} +3 -3
  26. package/dist/runtime.d.ts +4 -4
  27. package/dist/runtime.js +3 -3
  28. package/dist/{sandbox-CmYUc66b.js → sandbox-C42UAlFT.js} +226 -59
  29. package/dist/{sandbox-C-MO0nYW.d.ts → sandbox-CSFajXr_.d.ts} +7 -6
  30. package/dist/tangle/index.d.ts +1 -1
  31. package/dist/tangle/index.js +1 -1
  32. package/dist/{tangle-t-VT4qL1.js → tangle-9TwNLIs5.js} +2 -2
  33. package/dist/{types-DwHQuPFG.d.ts → types-Di0cLhOV.d.ts} +30 -8
  34. package/package.json +3 -3
@@ -1,9 +1,9 @@
1
1
  import { r as backendTypeSchema } from "./backend-types-C7b_Gpa0.js";
2
- import { C as SANDBOX_PROXY_REQUEST_MAX_BYTES, D as parseSSEStream, E as encodeTextForWire, I as withoutRuntimeSecrets, L as createAgentRunOutcomeTracker, M as normalizeRuntimeBackendConfig, N as requestedPublicProfileDigest, O as applyRequestedModel, P as requestedSecretProfilePublicDigest, R as deriveAgentResultOutcome, S as validateAcceptedDispatchRunRef, T as encodePromptForWire, _ as resolveTraceId, b as uploadChunked, c as requestScopedToken, d as normalizeSessionInfo, f as sessionMessageRequestBody, g as mintTraceId, h as isTraceId, j as mergeRuntimeBackendConfig, k as assertCurrentBackendType, l as SandboxRuntimeApi, m as TRACE_ID_HEADER, n as InteractiveSessionController, o as assertScopedTokenActive, p as waitForRetryAfter, r as TerminalStream, u as isRetryableCredentialRefusal, v as appendSessionIdQuery, x as resolveDispatchRunIdentity, y as sessionHeaders } from "./interactive-controller-DtX6fHC6.js";
3
- import { _ as ValidationError, b as readResponseJson, c as NetworkError, d as QuotaError, g as TimeoutError, h as StateError, l as NotFoundError, m as ServerError, n as CapabilityError, p as SandboxError, r as EdgeNotReadyError, t as AuthError, v as parseErrorResponse, y as parseResponseError } from "./errors-C1c3Q6Bj.js";
2
+ import { C as SANDBOX_PROXY_REQUEST_MAX_BYTES, D as parseSSEStream, E as encodeTextForWire, I as withoutRuntimeSecrets, L as createAgentRunOutcomeTracker, M as normalizeRuntimeBackendConfig, N as requestedPublicProfileDigest, O as applyRequestedModel, P as requestedSecretProfilePublicDigest, R as deriveAgentResultOutcome, S as validateAcceptedDispatchRunRef, T as encodePromptForWire, _ as resolveTraceId, b as uploadChunked, c as requestScopedToken, d as normalizeSessionInfo, f as sessionMessageRequestBody, g as mintTraceId, h as isTraceId, j as mergeRuntimeBackendConfig, k as assertCurrentBackendType, l as SandboxRuntimeApi, m as TRACE_ID_HEADER, n as InteractiveSessionController, o as assertScopedTokenActive, p as waitForRetryAfter, r as TerminalStream, u as isRetryableCredentialRefusal, v as appendSessionIdQuery, x as resolveDispatchRunIdentity, y as sessionHeaders } from "./interactive-controller-4Fo9aDih.js";
3
+ import { _ as TimeoutError, b as parseResponseError, c as NetworkError, d as QuotaError, g as StreamInterruptedError, h as StateError, l as NotFoundError, m as ServerError, n as CapabilityError, p as SandboxError, r as EdgeNotReadyError, t as AuthError, v as ValidationError, x as readResponseJson, y as parseErrorResponse } from "./errors-DMxVFCS6.js";
4
4
  import { d as awaitWithAbort, f as combineAbortSignals, g as interactiveSessionStatusResponseSchema, h as interactiveSessionControlValidationResponseSchema, l as createInteractiveControlHolderId, m as interactiveSessionControlReleaseResponseSchema, p as interactiveSessionControlClaimResponseSchema } from "./browser-interactive-control-controller-BJf0P_J4.js";
5
5
  import { SandboxLines } from "./lines.js";
6
- import { r as cliAuthReferenceSchema } from "./cli-auth-bundle-xnHi1LpC.js";
6
+ import { r as cliAuthReferenceSchema } from "./cli-auth-bundle-CZfgymgf.js";
7
7
  import { AgentExactRunControlRefSchema, AgentInteractiveSessionAttachSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimRequestSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionPromptCommandSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStartSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentInteractiveSessionStopCommandSchema, AgentRunCancellationAcknowledgementSchema, AgentRunCancellationRequestSchema, InteractionAcknowledgementSchema, InteractionBindingSchema, InteractionRequestSchema, InteractionResponseCommandSchema, InteractionResponseSchema, TerminalInputSchema, TerminalOutputEventSchema, TerminalReplayWindowSchema, TerminalResizeSchema, TerminalSessionRefSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimIsNewer, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionPromptRequestDigest, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionStatusMatchesRef, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentProfileSchema, agentRunCancellationAcknowledgementMatchesRequest, canonicalCandidateDigest, canonicalCandidateJson, exactAgentInteractiveSessionStart, sha256DigestSchema, terminalSessionUsable } from "@tangle-network/agent-interface";
8
8
  import { z } from "zod";
9
9
  import { AgentInteractiveSessionControlClaimSchema as AgentInteractiveSessionControlClaimSchema$1, AgentInteractiveSessionPromptAcknowledgementSchema as AgentInteractiveSessionPromptAcknowledgementSchema$1, AgentInteractiveSessionRefSchema as AgentInteractiveSessionRefSchema$1, AgentInteractiveSessionStatusSchema, AgentInteractiveSessionStopAcknowledgementSchema as AgentInteractiveSessionStopAcknowledgementSchema$1 } from "@tangle-network/agent-interface/environment-interactive-control";
@@ -1836,6 +1836,99 @@ function collectAgentFinalMessageText(events) {
1836
1836
  return composed.trim().length > 0 ? composed : void 0;
1837
1837
  }
1838
1838
  //#endregion
1839
+ //#region src/lib/stream-resume.ts
1840
+ /**
1841
+ * How a prompt stream rejoins its execution after the connection drops.
1842
+ *
1843
+ * A dropped stream is a transport fact, never a statement about the run. The
1844
+ * platform restarts its control path (host agents, orchestrator, Worker)
1845
+ * several times a day while executions keep running inside their sandboxes
1846
+ * and keep appending to their durable event log, so the SDK rejoins the log
1847
+ * for as long as the caller allows and the sandbox exists.
1848
+ */
1849
+ /** Default reconnect window: how long an execution may stay unreachable. */
1850
+ const DEFAULT_RECONNECT_WINDOW_MS = 360 * 60 * 1e3;
1851
+ /** The first retry waits this long; each consecutive failure doubles it. */
1852
+ const RECONNECT_BASE_DELAY_MS = 1e3;
1853
+ /** No single wait between attempts exceeds this. */
1854
+ const RECONNECT_MAX_DELAY_MS = 3e4;
1855
+ /** The caller's window, or the default; 0 disables reconnection. */
1856
+ function resolveReconnectWindowMs(value) {
1857
+ if (value === void 0) return DEFAULT_RECONNECT_WINDOW_MS;
1858
+ if (!Number.isFinite(value) || value < 0) throw new RangeError("reconnectWindowMs must be a non-negative number");
1859
+ return value;
1860
+ }
1861
+ /**
1862
+ * Capped exponential backoff with ±20% jitter, so the clients a host-agent
1863
+ * restart disconnects together do not return together.
1864
+ */
1865
+ function reconnectDelayMs(consecutiveFailures, random = Math.random) {
1866
+ const exponent = Math.max(0, consecutiveFailures - 1);
1867
+ const base = Math.min(RECONNECT_MAX_DELAY_MS, RECONNECT_BASE_DELAY_MS * 2 ** Math.min(exponent, 16));
1868
+ return Math.round(base * (.8 + .4 * random()));
1869
+ }
1870
+ /** Sandbox states from which no execution can continue. */
1871
+ function isFinalSandboxStatus(status) {
1872
+ return status === "stopped" || status === "failed" || status === "expired" || status === "deleted";
1873
+ }
1874
+ /**
1875
+ * Drops events the caller already received. The runtime numbers buffered
1876
+ * events with one increasing integer per sandbox, so numeric ids compare by
1877
+ * value; any other id is remembered exactly.
1878
+ */
1879
+ var DeliveredEvents = class {
1880
+ highestNumeric;
1881
+ opaque = /* @__PURE__ */ new Set();
1882
+ constructor(lastEventId) {
1883
+ if (lastEventId !== void 0) this.record(lastEventId);
1884
+ }
1885
+ isDuplicate(eventId) {
1886
+ if (eventId === void 0 || eventId === "") return false;
1887
+ const numeric = numericEventId(eventId);
1888
+ if (numeric !== void 0) return this.highestNumeric !== void 0 && numeric <= this.highestNumeric;
1889
+ return this.opaque.has(eventId);
1890
+ }
1891
+ record(eventId) {
1892
+ if (eventId === void 0 || eventId === "") return;
1893
+ const numeric = numericEventId(eventId);
1894
+ if (numeric !== void 0) {
1895
+ if (this.highestNumeric === void 0 || numeric > this.highestNumeric) this.highestNumeric = numeric;
1896
+ return;
1897
+ }
1898
+ this.opaque.add(eventId);
1899
+ }
1900
+ };
1901
+ /**
1902
+ * The runtime ends each replay connection with a `stream.terminal`
1903
+ * announcement that reuses the last delivered event id as its position, so
1904
+ * it is never a duplicate of an agent event.
1905
+ */
1906
+ function isDuplicateDelivery(delivered, event) {
1907
+ return event.type !== "stream.terminal" && delivered.isDuplicate(event.id);
1908
+ }
1909
+ function numericEventId(eventId) {
1910
+ if (!/^\d{1,15}$/u.test(eventId)) return void 0;
1911
+ return Number(eventId);
1912
+ }
1913
+ /** Resolve after `ms`, or as soon as the signal aborts; the caller checks it. */
1914
+ function waitForReconnect(ms, signal) {
1915
+ return new Promise((resolve) => {
1916
+ if (signal?.aborted) {
1917
+ resolve();
1918
+ return;
1919
+ }
1920
+ const timer = setTimeout(() => {
1921
+ signal?.removeEventListener("abort", onAbort);
1922
+ resolve();
1923
+ }, ms);
1924
+ const onAbort = () => {
1925
+ clearTimeout(timer);
1926
+ resolve();
1927
+ };
1928
+ signal?.addEventListener("abort", onAbort, { once: true });
1929
+ });
1930
+ }
1931
+ //#endregion
1839
1932
  //#region src/profile-file-delivery.ts
1840
1933
  /** Successful immutable mount delivery is scoped to one filesystem incarnation. */
1841
1934
  var ProfileFileDelivery = class {
@@ -3561,6 +3654,23 @@ function fromStreamErrorEvent(data) {
3561
3654
  * through so consumers can inspect the failure without re-parsing the message.
3562
3655
  */
3563
3656
  function toStreamErrorEvent(err) {
3657
+ if (err instanceof StreamInterruptedError) return {
3658
+ type: "error",
3659
+ data: {
3660
+ message: err.message,
3661
+ code: err.code,
3662
+ name: err.name,
3663
+ origin: err.origin,
3664
+ endpoint: err.endpoint,
3665
+ outcome: "unknown",
3666
+ reason: err.reason,
3667
+ executionId: err.executionId,
3668
+ ...err.sessionId ? { sessionId: err.sessionId } : {},
3669
+ ...err.lastEventId ? { lastEventId: err.lastEventId } : {},
3670
+ ...err.lastReplayStatus !== void 0 ? { lastReplayStatus: err.lastReplayStatus } : {},
3671
+ ...err.lastExecutionStatus ? { lastExecutionStatus: err.lastExecutionStatus } : {}
3672
+ }
3673
+ };
3564
3674
  if (err instanceof SandboxError) return {
3565
3675
  type: "error",
3566
3676
  data: {
@@ -4631,6 +4741,7 @@ var SandboxInstance = class SandboxInstance {
4631
4741
  let sessionId = options?.sessionId;
4632
4742
  let executionId = options?.lastEventId ? options.executionId : void 0;
4633
4743
  let profileResendAttempted = false;
4744
+ let streamInterrupted = false;
4634
4745
  try {
4635
4746
  for (;;) {
4636
4747
  let yieldedThisAttempt = false;
@@ -4665,9 +4776,21 @@ var SandboxInstance = class SandboxInstance {
4665
4776
  executionId,
4666
4777
  error: err instanceof Error ? err.message : String(err)
4667
4778
  });
4779
+ if (err instanceof StreamInterruptedError) {
4780
+ streamInterrupted = true;
4781
+ yield toStreamErrorEvent(err);
4782
+ return;
4783
+ }
4668
4784
  yield toStreamErrorEvent(err);
4669
4785
  } finally {
4670
- if (!receivedTerminal && !isCallerAbort()) {
4786
+ if (!receivedTerminal && !streamInterrupted && options.detach !== true && executionId !== void 0 && sessionId !== void 0) {
4787
+ this.logStreamCheckpoint("consumer_cancel", {
4788
+ sessionId,
4789
+ executionId
4790
+ });
4791
+ this._interrupt(sessionId, { executionId }).catch(() => void 0);
4792
+ }
4793
+ if (!receivedTerminal && !streamInterrupted && !isCallerAbort()) {
4671
4794
  this.logStreamCheckpoint("synthetic_terminal", {
4672
4795
  sessionId,
4673
4796
  executionId
@@ -4684,12 +4807,18 @@ var SandboxInstance = class SandboxInstance {
4684
4807
  }
4685
4808
  }
4686
4809
  /**
4687
- * Inner prompt stream: opens the SSE connection and reconnects on silent
4688
- * drops. May throw (pre-stream HTTP error, timeout, reconnect exhausted);
4689
- * the public `streamPrompt` wrapper converts those throws into a terminal
4690
- * `error` + `done` so callers never see a thrown generator.
4810
+ * Inner prompt stream: opens the SSE connection and rejoins the execution's
4811
+ * event log on silent drops. May throw (pre-stream HTTP error, timeout, or
4812
+ * `StreamInterruptedError` when it cannot rejoin); the public
4813
+ * `streamPrompt` wrapper converts those throws into in-band events so
4814
+ * callers never see a thrown generator.
4691
4815
  */
4692
4816
  async *streamPromptInner(message, options, internal) {
4817
+ if (options?.nativeResume !== void 0) {
4818
+ const resume = options.nativeResume;
4819
+ const validId = (id) => typeof id === "string" && /^[A-Za-z0-9._:-]{1,256}$/u.test(id);
4820
+ 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");
4821
+ }
4693
4822
  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" });
4694
4823
  const runControlRef = options?.runControlRef ? AgentExactRunControlRefSchema.safeParse(options.runControlRef) : void 0;
4695
4824
  if (runControlRef && !runControlRef.success) throw new ValidationError("Invalid runControlRef", { runControlRef: runControlRef.error.message });
@@ -4733,15 +4862,8 @@ var SandboxInstance = class SandboxInstance {
4733
4862
  let executionId = options?.executionId;
4734
4863
  let sessionId = options?.sessionId;
4735
4864
  let receivedTerminal = false;
4736
- const RECONNECT_BACKOFF_MS = [
4737
- 2e3,
4738
- 4e3,
4739
- 8e3,
4740
- 16e3,
4741
- 3e4,
4742
- 3e4
4743
- ];
4744
- const MAX_RECONNECT_ATTEMPTS = RECONNECT_BACKOFF_MS.length;
4865
+ const reconnectWindowMs = resolveReconnectWindowMs(options?.reconnectWindowMs);
4866
+ const delivered = new DeliveredEvents(lastEventId);
4745
4867
  let lastReplayStatus;
4746
4868
  let lastExecutionStatus;
4747
4869
  let firstSseEventSeen = false;
@@ -4771,6 +4893,7 @@ var SandboxInstance = class SandboxInstance {
4771
4893
  body: JSON.stringify({
4772
4894
  id: "default",
4773
4895
  ...options?.sessionId ? { sessionId: options.sessionId } : {},
4896
+ ...options?.nativeResume ? { nativeResume: options.nativeResume } : {},
4774
4897
  ...runControlRef?.success ? { runControlRef: runControlRef.data } : {},
4775
4898
  parts: encodePromptForWire(message),
4776
4899
  turnId: options?.turnId,
@@ -4819,31 +4942,40 @@ var SandboxInstance = class SandboxInstance {
4819
4942
  status: response.status,
4820
4943
  ok: false
4821
4944
  });
4822
- } else for await (const event of this.parseSSEStream(response, streamSignal)) {
4823
- if (event.type === "history.replay.start" || event.type === "history.replay.end") continue;
4824
- if (!firstSseEventSeen) {
4825
- firstSseEventSeen = true;
4826
- logStreamCheckpoint("first_sse_event", {
4827
- eventType: event.type,
4828
- eventId: event.id
4829
- });
4830
- }
4831
- if (event.id) lastEventId = event.id;
4832
- if (event.type === "execution.started" && event.data?.executionId) {
4833
- executionId = event.data.executionId;
4834
- const eventSessionId = event.data?.sessionId;
4835
- if (sessionId === void 0 && typeof eventSessionId === "string" && eventSessionId.length > 0) sessionId = eventSessionId;
4836
- }
4837
- if (event.type === "done" || event.type === "error") {
4838
- receivedTerminal = true;
4839
- logStreamCheckpoint("terminal_event", {
4840
- eventType: event.type,
4841
- eventId: event.id,
4842
- sessionId,
4843
- executionId
4844
- });
4945
+ } else try {
4946
+ for await (const event of this.parseSSEStream(response, streamSignal)) {
4947
+ if (event.type === "history.replay.start" || event.type === "history.replay.end") continue;
4948
+ if (!firstSseEventSeen) {
4949
+ firstSseEventSeen = true;
4950
+ logStreamCheckpoint("first_sse_event", {
4951
+ eventType: event.type,
4952
+ eventId: event.id
4953
+ });
4954
+ }
4955
+ if (isDuplicateDelivery(delivered, event)) continue;
4956
+ delivered.record(event.id);
4957
+ if (event.id) lastEventId = event.id;
4958
+ if (event.type === "execution.started" && event.data?.executionId) {
4959
+ executionId = event.data.executionId;
4960
+ const eventSessionId = event.data?.sessionId;
4961
+ if (sessionId === void 0 && typeof eventSessionId === "string" && eventSessionId.length > 0) sessionId = eventSessionId;
4962
+ }
4963
+ if (event.type === "done" || event.type === "error") {
4964
+ receivedTerminal = true;
4965
+ logStreamCheckpoint("terminal_event", {
4966
+ eventType: event.type,
4967
+ eventId: event.id,
4968
+ sessionId,
4969
+ executionId
4970
+ });
4971
+ }
4972
+ yield event;
4845
4973
  }
4846
- yield event;
4974
+ } catch (readError) {
4975
+ throwIfTimedOut();
4976
+ if (receivedTerminal || options?.signal?.aborted || streamSignal?.aborted) return;
4977
+ logStreamCheckpoint("stream_read_failed", { error: readError instanceof Error ? readError.message : String(readError) });
4978
+ console.warn(`[sandbox-sdk] Stream connection broke: ${readError instanceof Error ? readError.message : String(readError)}`);
4847
4979
  }
4848
4980
  if (receivedTerminal) return;
4849
4981
  throwIfTimedOut();
@@ -4858,22 +4990,49 @@ var SandboxInstance = class SandboxInstance {
4858
4990
  endpoint: "/agents/run/stream",
4859
4991
  origin: "runtime"
4860
4992
  });
4861
- for (let attempt = 1; attempt <= MAX_RECONNECT_ATTEMPTS; attempt++) {
4993
+ const resumeExecutionId = executionId;
4994
+ const interrupted = (reason, detail, cause) => {
4995
+ const replayStatusText = lastReplayStatus !== void 0 ? `; last replay status ${lastReplayStatus}` : "";
4996
+ const execStatusText = lastExecutionStatus ? `; last known execution status ${lastExecutionStatus}` : "";
4997
+ console.warn(`[sandbox-sdk] Stopped rejoining execution ${resumeExecutionId}: ${detail}`);
4998
+ return new StreamInterruptedError({
4999
+ message: `Prompt stream for execution ${resumeExecutionId} ended before a terminal event and could not be rejoined (${detail}); the execution's outcome is unknown${replayStatusText}${execStatusText}`,
5000
+ executionId: resumeExecutionId,
5001
+ ...sessionId ? { sessionId } : {},
5002
+ ...lastEventId ? { lastEventId } : {},
5003
+ reason,
5004
+ ...lastReplayStatus !== void 0 ? { lastReplayStatus } : {},
5005
+ ...lastExecutionStatus ? { lastExecutionStatus } : {},
5006
+ ...cause !== void 0 ? { cause } : {}
5007
+ });
5008
+ };
5009
+ let outageStartedAt = Date.now();
5010
+ let consecutiveFailures = 0;
5011
+ let notFoundSince;
5012
+ for (let attempt = 1;; attempt++) {
4862
5013
  throwIfTimedOut();
4863
5014
  if (options?.signal?.aborted || streamSignal?.aborted) return;
4864
- console.warn(`[sandbox-sdk] Stream dropped without terminal event, reconnecting (attempt ${attempt}/${MAX_RECONNECT_ATTEMPTS})`);
5015
+ const outageMs = Date.now() - outageStartedAt;
5016
+ if (outageMs >= reconnectWindowMs) throw interrupted("reconnect-window-elapsed", `unreachable for ${outageMs}ms of a ${reconnectWindowMs}ms reconnect window`);
5017
+ consecutiveFailures += 1;
5018
+ const delayMs = Math.min(reconnectDelayMs(consecutiveFailures), reconnectWindowMs - outageMs);
5019
+ console.warn(`[sandbox-sdk] Stream dropped without terminal event, reconnecting (attempt ${attempt}; unreachable ${Math.round(outageMs / 1e3)}s of ${Math.round(reconnectWindowMs / 1e3)}s)`);
4865
5020
  logStreamCheckpoint("reconnect_attempt_start", {
4866
5021
  attempt,
4867
5022
  executionId,
4868
5023
  sessionId,
4869
- lastEventId
5024
+ lastEventId,
5025
+ outageMs,
5026
+ delayMs
4870
5027
  });
4871
- await new Promise((resolve) => setTimeout(resolve, RECONNECT_BACKOFF_MS[attempt - 1]));
5028
+ await waitForReconnect(delayMs, streamSignal);
4872
5029
  throwIfTimedOut();
4873
5030
  if (options?.signal?.aborted || streamSignal?.aborted) return;
5031
+ let connectedAt;
5032
+ let deliveredThisConnection = 0;
4874
5033
  try {
4875
5034
  const queryParams = lastEventId ? `?lastEventId=${encodeURIComponent(lastEventId)}&format=sse` : "?format=sse";
4876
- const replayResponse = await this.runtimeFetch(`/agents/run/${encodeURIComponent(executionId)}/events${queryParams}`, {
5035
+ const replayResponse = await this.runtimeFetch(`/agents/run/${encodeURIComponent(resumeExecutionId)}/events${queryParams}`, {
4877
5036
  method: "GET",
4878
5037
  signal: streamSignal,
4879
5038
  headers: traceHeaders
@@ -4885,9 +5044,15 @@ var SandboxInstance = class SandboxInstance {
4885
5044
  });
4886
5045
  if (!replayResponse.ok) {
4887
5046
  lastReplayStatus = replayResponse.status;
5047
+ await replayResponse.body?.cancel().catch(() => void 0);
4888
5048
  await reconcileRuntimeRefusal(replayResponse.status);
4889
5049
  console.warn(`[sandbox-sdk] Replay endpoint returned ${replayResponse.status}, attempt ${attempt}`);
4890
- if (replayResponse.status === 404 && sessionId) try {
5050
+ if (replayResponse.status !== 404) {
5051
+ notFoundSince = void 0;
5052
+ continue;
5053
+ }
5054
+ notFoundSince ??= Date.now();
5055
+ if (sessionId) try {
4891
5056
  const info = await this._sessionStatus(sessionId);
4892
5057
  if (info) {
4893
5058
  lastExecutionStatus = info.status;
@@ -4916,8 +5081,11 @@ var SandboxInstance = class SandboxInstance {
4916
5081
  } catch (statusErr) {
4917
5082
  console.warn(`[sandbox-sdk] Session status poll failed during replay 404: ${statusErr instanceof Error ? statusErr.message : String(statusErr)}`);
4918
5083
  }
5084
+ if (Date.now() - notFoundSince >= 6e5) throw interrupted("execution-not-found", `the runtime has answered 404 for ${Date.now() - notFoundSince}ms`);
4919
5085
  continue;
4920
5086
  }
5087
+ notFoundSince = void 0;
5088
+ connectedAt = Date.now();
4921
5089
  for await (const event of this.parseSSEStream(replayResponse, streamSignal)) {
4922
5090
  if (!firstSseEventSeen) {
4923
5091
  firstSseEventSeen = true;
@@ -4928,6 +5096,9 @@ var SandboxInstance = class SandboxInstance {
4928
5096
  });
4929
5097
  }
4930
5098
  if (event.type === "history.replay.start" || event.type === "history.replay.end") continue;
5099
+ if (isDuplicateDelivery(delivered, event)) continue;
5100
+ delivered.record(event.id);
5101
+ deliveredThisConnection += 1;
4931
5102
  if (event.id) lastEventId = event.id;
4932
5103
  const eventSessionId = event.data?.sessionId;
4933
5104
  if (typeof eventSessionId === "string" && eventSessionId.length > 0) sessionId = eventSessionId;
@@ -4954,7 +5125,9 @@ var SandboxInstance = class SandboxInstance {
4954
5125
  if (options?.signal?.aborted || streamSignal?.aborted) return;
4955
5126
  } catch (err) {
4956
5127
  throwIfTimedOut();
4957
- if (err instanceof StateError) throw err;
5128
+ if (err instanceof StreamInterruptedError) throw err;
5129
+ if (options?.signal?.aborted || streamSignal?.aborted) return;
5130
+ if (err instanceof StateError && isFinalSandboxStatus(this.status)) throw interrupted("sandbox-not-running", `the sandbox is ${this.status}`, err);
4958
5131
  logStreamCheckpoint("reconnect_attempt_end", {
4959
5132
  attempt,
4960
5133
  status: "failed",
@@ -4962,15 +5135,10 @@ var SandboxInstance = class SandboxInstance {
4962
5135
  });
4963
5136
  console.warn(`[sandbox-sdk] Reconnection attempt ${attempt} failed: ${err instanceof Error ? err.message : String(err)}`);
4964
5137
  }
4965
- }
4966
- if (!receivedTerminal) {
4967
- console.warn(`[sandbox-sdk] Exhausted ${MAX_RECONNECT_ATTEMPTS} reconnection attempts without receiving terminal event`);
4968
- const replayStatusText = lastReplayStatus !== void 0 ? `; last replay status ${lastReplayStatus}` : "";
4969
- const execStatusText = lastExecutionStatus ? `; last known execution status ${lastExecutionStatus}` : "";
4970
- throw new NetworkError(`Prompt stream ended before a terminal event for execution ${executionId}${replayStatusText}${execStatusText}`, {
4971
- endpoint: `/agents/run/${executionId}/events`,
4972
- origin: "runtime"
4973
- });
5138
+ if (connectedAt !== void 0 && (deliveredThisConnection > 0 || Date.now() - connectedAt >= 3e4)) {
5139
+ outageStartedAt = Date.now();
5140
+ consecutiveFailures = 0;
5141
+ }
4974
5142
  }
4975
5143
  }
4976
5144
  /**
@@ -7900,8 +8068,7 @@ var SandboxInstance = class SandboxInstance {
7900
8068
  const expectedPublicProfileRequestDigest = requestedSecretProfilePublicDigest(backend);
7901
8069
  const wire = sessionMessageRequestBody({
7902
8070
  parts: [],
7903
- backend,
7904
- expectedPublicProfileRequestDigest
8071
+ backend
7905
8072
  });
7906
8073
  const endpoint = `/agents/sessions/${encodeURIComponent(opts.sessionId)}/public-profile-revisions/prepare`;
7907
8074
  const response = await this.runtimeFetch(endpoint, {
@@ -1,9 +1,9 @@
1
1
  import { t as CliAuthReference } from "./cli-auth-bundle-BMcIiB-I.js";
2
- import { $n as PublicProfileConflict, A as CommitTaskSessionOptions, Aa as WaitForOptions, Ai as SandboxTraceBundle, Bi as SendSessionMessageRequest, C as BranchOptions, Ci as SandboxStatus, Cn as ListMessagesOptions, Cr as SandboxCreateReceipt, D as CodeExecutionResult, E as CodeExecutionOptions, Et as FileSystem, Fa as WriteManyOptions, Fi as SearchMatch, H as CreateTaskSessionOptions, Hn as ProcessManager, Ii as SearchOptions, In as PreviewLinkManager, Ji as SessionInfo, Jn as PromptResult, Ka as RawEvidenceDirectoryExport, Kn as PromptInputPart, M as ConversationTurnOptions, Ma as WorkspaceOperationLookup, Mt as FileWriteResult, N as ConversationTurnResult, Na as WriteFileOptions, Ni as SandboxTraceOptions, O as CodeLanguage, Pa as WriteManyFile, Pn as PermissionsManager, Q as DispatchedSession, Qa as InteractionResolutionAcknowledgement, Qi as SessionMessageAdmission, Qt as ForkLookupOptions, Sa as TeePublicKeyResponse, Sn as JsonValue, Ta as TurnDriveResult, Tr as SandboxDeleteOptions, Ua as SandboxEnvRecovery, Ui as SessionEventStreamOptions, V as CreateSessionOptions, Vi as SentSessionMessage, Wa as SandboxEnvRecoveryView, Wi as SessionExecutionInfo, Xi as SessionListOptions, Xn as ProvisionResult, Xt as ForkCounts, Yi as SessionInterruptOptions, Yn as ProvisionEvent, Z as DispatchPromptOptions, Za as WorkspaceImagePublishResult$1, Zi as SessionMessage, Zt as ForkIdempotency, _n as IntelligenceReport, aa as SnapshotInfo, an as GitStatus, ba as TeeAttestationResponse, bi as SandboxShape, d as BackendConfig, dn as GpuLeaseManager, dr as Rollout, ea as SessionResultOptions, ei as SandboxFleetTraceBundle, fi as SandboxPortBinding, ga as TaskSessionInfo, gn as InstalledTool, gt as EventStreamOptions, hi as SandboxResourceUsage, hr as RolloutStartResult, in as GitDiff, it as DriverInfo, j as CompletedTurnResult, ja as WaitForRolloutOptions, jn as NetworkManager, ki as SandboxTerminals, kr as SandboxEvent, la as StartupDiagnostics, lr as RestoreSnapshotOptions, ma as TaskSessionCommitResult, na as SnapshotDeleteAcknowledgement, nn as GitCommit, nt as DriveTurnOptions, oa as SnapshotOptions, on as GpuLease, ot as DurablePlan, p as BackendManager, pa as TaskSessionChanges, pr as RolloutOptions, pt as EgressManager, qa as RawEvidenceExportOptions, qi as SessionForkOptions, qn as PromptOptions, sa as SnapshotResult, st as DurablePlanDecisionResult, tn as GitBranch, ui as SandboxInfo, ur as ResumeOptions, va as TeeAttestationOptions, vi as SandboxRuntimeCapabilities, vn as IntelligenceReportBudget, vr as SSHCommandDescriptor, vt as ExecOptions, wi as SandboxTerminalAttachOptions, wr as SandboxDeleteAcknowledgement, xn as IntelligenceReportWindow, xr as SandboxConnection, yi as SandboxRuntimeHealth, yn as IntelligenceReportCompareTo, yr as SSHCredentials, yt as ExecResult, zi as SendSessionMessageOptions } from "./types-DwHQuPFG.js";
2
+ import { $n as PublicProfileConflict, A as CommitTaskSessionOptions, Aa as WaitForOptions, Ai as SandboxTraceBundle, Bi as SendSessionMessageRequest, C as BranchOptions, Ci as SandboxStatus, Cn as ListMessagesOptions, Cr as SandboxCreateReceipt, D as CodeExecutionResult, E as CodeExecutionOptions, Et as FileSystem, Fa as WriteManyOptions, Fi as SearchMatch, H as CreateTaskSessionOptions, Hn as ProcessManager, Ii as SearchOptions, In as PreviewLinkManager, Ji as SessionInfo, Jn as PromptResult, Ka as RawEvidenceDirectoryExport, Kn as PromptInputPart, M as ConversationTurnOptions, Ma as WorkspaceOperationLookup, Mt as FileWriteResult, N as ConversationTurnResult, Na as WriteFileOptions, Ni as SandboxTraceOptions, O as CodeLanguage, Pa as WriteManyFile, Pn as PermissionsManager, Q as DispatchedSession, Qa as InteractionResolutionAcknowledgement, Qi as SessionMessageAdmission, Qt as ForkLookupOptions, Sa as TeePublicKeyResponse, Sn as JsonValue, Ta as TurnDriveResult, Tr as SandboxDeleteOptions, Ua as SandboxEnvRecovery, Ui as SessionEventStreamOptions, V as CreateSessionOptions, Vi as SentSessionMessage, Wa as SandboxEnvRecoveryView, Wi as SessionExecutionInfo, Xi as SessionListOptions, Xn as ProvisionResult, Xt as ForkCounts, Yi as SessionInterruptOptions, Yn as ProvisionEvent, Z as DispatchPromptOptions, Za as WorkspaceImagePublishResult$1, Zi as SessionMessage, Zt as ForkIdempotency, _n as IntelligenceReport, aa as SnapshotInfo, an as GitStatus, ba as TeeAttestationResponse, bi as SandboxShape, d as BackendConfig, dn as GpuLeaseManager, dr as Rollout, ea as SessionResultOptions, ei as SandboxFleetTraceBundle, fi as SandboxPortBinding, ga as TaskSessionInfo, gn as InstalledTool, gt as EventStreamOptions, hi as SandboxResourceUsage, hr as RolloutStartResult, in as GitDiff, it as DriverInfo, j as CompletedTurnResult, ja as WaitForRolloutOptions, jn as NetworkManager, ki as SandboxTerminals, kr as SandboxEvent, la as StartupDiagnostics, lr as RestoreSnapshotOptions, ma as TaskSessionCommitResult, na as SnapshotDeleteAcknowledgement, nn as GitCommit, nt as DriveTurnOptions, oa as SnapshotOptions, on as GpuLease, ot as DurablePlan, p as BackendManager, pa as TaskSessionChanges, pr as RolloutOptions, pt as EgressManager, qa as RawEvidenceExportOptions, qi as SessionForkOptions, qn as PromptOptions, sa as SnapshotResult, st as DurablePlanDecisionResult, tn as GitBranch, ui as SandboxInfo, ur as ResumeOptions, va as TeeAttestationOptions, vi as SandboxRuntimeCapabilities, vn as IntelligenceReportBudget, vr as SSHCommandDescriptor, vt as ExecOptions, wi as SandboxTerminalAttachOptions, wr as SandboxDeleteAcknowledgement, xn as IntelligenceReportWindow, xr as SandboxConnection, yi as SandboxRuntimeHealth, yn as IntelligenceReportCompareTo, yr as SSHCredentials, yt as ExecResult, zi as SendSessionMessageOptions } from "./types-Di0cLhOV.js";
3
3
  import { a as TerminalStreamReconnectAuthority, c as MintScopedTokenOptions, h as TerminalReadyInfo, l as ScopedToken, r as TerminalStreamHandlers, t as TerminalStream } from "./terminal-stream-B6bUr0hj.js";
4
4
  import { f as InteractiveAttachOptions, g as InteractiveSessionStatus, h as InteractiveRequestOptions, m as InteractiveControlClaimOptions, p as InteractiveControlClaimAcknowledgement } from "./browser-interactive-control-controller-DRCfxOQz.js";
5
5
  import { r as InteractiveAttachRequest } from "./interactive-controller-ykaThYp6.js";
6
- import { R as SandboxLines } from "./lines-CJK_ysel.js";
6
+ import { R as SandboxLines } from "./lines-d9AEcbCd.js";
7
7
  import { AgentInteractiveSessionAttach, AgentInteractiveSessionControlClaim, AgentInteractiveSessionControlClaimAcknowledgement, AgentInteractiveSessionControlClaimRequest, AgentInteractiveSessionPromptAcknowledgement, AgentInteractiveSessionPromptCommand, AgentInteractiveSessionRef, AgentInteractiveSessionStart, AgentInteractiveSessionStopAcknowledgement, AgentInteractiveSessionStopCommand, AgentInteractiveTerminalSession, AgentInteractiveTerminalSession as AgentInteractiveTerminalSession$1, AgentProfile, AgentRunCancellationAcknowledgement, AgentRunCancellationRequest, InteractionAcknowledgement, InteractionData, InteractionRequest, InteractionResponseCommand, TerminalOutputEvent, TerminalReplayWindow, agentInteractiveSessionPromptRequestDigest } from "@tangle-network/agent-interface";
8
8
  import { z } from "zod";
9
9
 
@@ -1124,10 +1124,11 @@ declare class SandboxInstance {
1124
1124
  private buildRunBackendBody;
1125
1125
  streamPrompt(message: string | PromptInputPart[], requestedOptions?: PromptOptions): AsyncGenerator<SandboxEvent>;
1126
1126
  /**
1127
- * Inner prompt stream: opens the SSE connection and reconnects on silent
1128
- * drops. May throw (pre-stream HTTP error, timeout, reconnect exhausted);
1129
- * the public `streamPrompt` wrapper converts those throws into a terminal
1130
- * `error` + `done` so callers never see a thrown generator.
1127
+ * Inner prompt stream: opens the SSE connection and rejoins the execution's
1128
+ * event log on silent drops. May throw (pre-stream HTTP error, timeout, or
1129
+ * `StreamInterruptedError` when it cannot rejoin); the public
1130
+ * `streamPrompt` wrapper converts those throws into in-band events so
1131
+ * callers never see a thrown generator.
1131
1132
  */
1132
1133
  private streamPromptInner;
1133
1134
  /**
@@ -1,2 +1,2 @@
1
- import { C as JsonResponseParamTypes, E as SandboxIdParamTypes, S as ITangleJobsAbi, T as SandboxCreateResponseParamTypes, _ as JOB_SANDBOX_DELETE, a as fetchQuote, b as TangleSandboxClientConfig, c as parseQuoteResponse, d as OperatorSession, f as OperatorSessionError, g as JOB_SANDBOX_CREATE, h as TangleSandboxClient, i as SignedQuote, l as validateQuote, m as SignMessage, n as QuoteDomain, o as inputsHashOf, p as OperatorSessionToken, r as QuoteError, s as jobQuoteDigest, t as JobQuoteDetails, u as OperatorChallenge, v as TANGLE_CHAIN_ID, w as SandboxCreateParamTypes, x as AgentSandboxBlueprintAbi, y as TANGLE_JOBS_CONTRACT } from "../index-DaQYTQXD.js";
1
+ import { C as JsonResponseParamTypes, E as SandboxIdParamTypes, S as ITangleJobsAbi, T as SandboxCreateResponseParamTypes, _ as JOB_SANDBOX_DELETE, a as fetchQuote, b as TangleSandboxClientConfig, c as parseQuoteResponse, d as OperatorSession, f as OperatorSessionError, g as JOB_SANDBOX_CREATE, h as TangleSandboxClient, i as SignedQuote, l as validateQuote, m as SignMessage, n as QuoteDomain, o as inputsHashOf, p as OperatorSessionToken, r as QuoteError, s as jobQuoteDigest, t as JobQuoteDetails, u as OperatorChallenge, v as TANGLE_CHAIN_ID, w as SandboxCreateParamTypes, x as AgentSandboxBlueprintAbi, y as TANGLE_JOBS_CONTRACT } from "../index-Dv77g3s5.js";
2
2
  export { AgentSandboxBlueprintAbi, ITangleJobsAbi, JOB_SANDBOX_CREATE, JOB_SANDBOX_DELETE, JobQuoteDetails, JsonResponseParamTypes, OperatorChallenge, OperatorSession, OperatorSessionError, OperatorSessionToken, QuoteDomain, QuoteError, SandboxCreateParamTypes, SandboxCreateResponseParamTypes, SandboxIdParamTypes, SignMessage, SignedQuote, TANGLE_CHAIN_ID, TANGLE_JOBS_CONTRACT, TangleSandboxClient, TangleSandboxClientConfig, fetchQuote, inputsHashOf, jobQuoteDigest, parseQuoteResponse, validateQuote };
@@ -1,2 +1,2 @@
1
- import { _ as SandboxCreateParamTypes, a as parseQuoteResponse, c as OperatorSession, d as JOB_SANDBOX_DELETE, f as TANGLE_CHAIN_ID, g as JsonResponseParamTypes, h as ITangleJobsAbi, i as jobQuoteDigest, l as OperatorSessionError, m as AgentSandboxBlueprintAbi, n as fetchQuote, o as validateQuote, p as TANGLE_JOBS_CONTRACT, r as inputsHashOf, s as TangleSandboxClient, t as QuoteError, u as JOB_SANDBOX_CREATE, v as SandboxCreateResponseParamTypes, y as SandboxIdParamTypes } from "../tangle-t-VT4qL1.js";
1
+ import { _ as SandboxCreateParamTypes, a as parseQuoteResponse, c as OperatorSession, d as JOB_SANDBOX_DELETE, f as TANGLE_CHAIN_ID, g as JsonResponseParamTypes, h as ITangleJobsAbi, i as jobQuoteDigest, l as OperatorSessionError, m as AgentSandboxBlueprintAbi, n as fetchQuote, o as validateQuote, p as TANGLE_JOBS_CONTRACT, r as inputsHashOf, s as TangleSandboxClient, t as QuoteError, u as JOB_SANDBOX_CREATE, v as SandboxCreateResponseParamTypes, y as SandboxIdParamTypes } from "../tangle-9TwNLIs5.js";
2
2
  export { AgentSandboxBlueprintAbi, ITangleJobsAbi, JOB_SANDBOX_CREATE, JOB_SANDBOX_DELETE, JsonResponseParamTypes, OperatorSession, OperatorSessionError, QuoteError, SandboxCreateParamTypes, SandboxCreateResponseParamTypes, SandboxIdParamTypes, TANGLE_CHAIN_ID, TANGLE_JOBS_CONTRACT, TangleSandboxClient, fetchQuote, inputsHashOf, jobQuoteDigest, parseQuoteResponse, validateQuote };
@@ -1,5 +1,5 @@
1
- import { b as readResponseJson } from "./errors-C1c3Q6Bj.js";
2
- import { n as createSandboxInstanceFromResponse } from "./sandbox-CmYUc66b.js";
1
+ import { x as readResponseJson } from "./errors-DMxVFCS6.js";
2
+ import { n as createSandboxInstanceFromResponse } from "./sandbox-C42UAlFT.js";
3
3
  import { _ as rotlBH, a as anumber, b as rotlSL, d as createXOFer, g as u32, h as toBytes$1, l as createHasher, m as swap32IfBE, n as abytes, o as aoutput, r as aexists, s as clean, t as Hash, v as rotlBL, x as split, y as rotlSH } from "./utils-ChcSLv53.js";
4
4
  //#region src/tangle/abi.ts
5
5
  /**
@@ -2991,6 +2991,12 @@ type PromptInputPart = {
2991
2991
  interface PromptOptions {
2992
2992
  /** Session ID for conversation continuity */
2993
2993
  sessionId?: string;
2994
+ /** Resume one native conversation from the verified source snapshot. */
2995
+ nativeResume?: {
2996
+ harness: "claude-code" | "codex";
2997
+ nativeSessionId: string;
2998
+ sourceCheckpointId: string;
2999
+ };
2994
3000
  /**
2995
3001
  * Per-turn model id, forwarded to the runtime as `backend.model.model`.
2996
3002
  * Accepts a provider-prefixed slug ("zai/glm-4.7", "openai/gpt-5-mini")
@@ -3091,16 +3097,32 @@ interface PromptOptions {
3091
3097
  */
3092
3098
  turnId?: string;
3093
3099
  /**
3094
- * Detach the run from this stream's lifetime. When true, dropping the
3095
- * SSE connection (closing the generator, an isolate restart, a network
3096
- * blip) does NOT cancel the run: the platform keeps executing it and
3097
- * buffers its events so a later reconnect can replay. Use for batch or
3098
- * queue workloads where a long quiet run (repo clone + test suite) must
3099
- * survive transient stream drops. Omit for interactive chat where
3100
- * closing the tab should stop burning tokens. `dispatchPrompt` always
3101
- * sets this so fire-and-detach is safe by construction.
3100
+ * Detach the run from this stream's lifetime. When true, the run never
3101
+ * ends because a reader went away: closing the generator does not cancel
3102
+ * it, and the platform keeps executing it and buffering its events so a
3103
+ * later reconnect can replay. Use for batch or queue workloads.
3104
+ *
3105
+ * Without it, ending the stream early (breaking out of the loop, aborting
3106
+ * `signal`, or letting `timeoutMs` elapse) cancels the run. A dropped
3107
+ * connection does not: the platform keeps an interactive run through a
3108
+ * disconnect grace window so this stream can rejoin it.
3109
+ * `dispatchPrompt` always sets this so fire-and-detach is safe by
3110
+ * construction.
3102
3111
  */
3103
3112
  detach?: boolean;
3113
+ /**
3114
+ * How long the SDK keeps rejoining this execution while it is unreachable,
3115
+ * in milliseconds. A dropped stream is a transport event, not an outcome:
3116
+ * the SDK reconnects with capped exponential backoff (1s doubling to 30s)
3117
+ * and resumes after the last delivered event, without duplicates. Each
3118
+ * replay connection that reaches the execution restarts the window, so a
3119
+ * long run survives any number of platform deploys. When the window
3120
+ * elapses, or the sandbox stops, the stream ends with an `error` event
3121
+ * whose `code` is `STREAM_INTERRUPTED` and `outcome` is `unknown`, and no
3122
+ * `done`: rejoin later with `executionId` + `lastEventId`.
3123
+ * Default six hours; 0 disables reconnection.
3124
+ */
3125
+ reconnectWindowMs?: number;
3104
3126
  }
3105
3127
  /**
3106
3128
  * SSE event from sandbox streaming.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox",
3
- "version": "0.60.25",
3
+ "version": "0.60.26-develop.20261008100338.fdb71c8",
4
4
  "description": "Client SDK for the Tangle Sandbox platform - build AI agent applications with dev containers",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -149,12 +149,12 @@
149
149
  "vitest": "^4.1.11",
150
150
  "ws": "^8.20.0",
151
151
  "yjs": "13.6.30",
152
- "@products/sandbox-test-utils": "0.0.0",
153
- "@repo/shared": "0.0.0",
154
152
  "@tangle-network/agent-profile-materialize": "0.22.0",
155
153
  "@tangle-network/cli-agent-registry": "0.6.2",
156
154
  "@tangle-network/runtime-contracts": "0.16.0",
155
+ "@repo/shared": "0.0.0",
157
156
  "@tangle-network/sdk": "4.0.3",
157
+ "@products/sandbox-test-utils": "0.0.0",
158
158
  "@tangle-network/sse-core": "0.0.0"
159
159
  },
160
160
  "scripts": {