@opengeni/runtime 0.13.0 → 0.13.3

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.
@@ -14,6 +14,7 @@ var MCP_MAX_TOOL_RESULT_BYTES = 1024 * 1024;
14
14
  var MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES = 256 * 1024;
15
15
  var MCP_MAX_SELECTED_SERVERS = 64;
16
16
  var MCP_MAX_CONCURRENT_SERVER_OPERATIONS = 8;
17
+ var MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS = 1e4;
17
18
  var MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = 4096;
18
19
  var MCP_MAX_AGGREGATE_TOOL_LIST_BYTES = 16 * 1024 * 1024;
19
20
  var MCP_MAX_TOOL_SEARCH_SOURCES = 64;
@@ -73,6 +74,12 @@ function assertMcpServerSelectionWithinBounds(servers) {
73
74
  }
74
75
  return servers;
75
76
  }
77
+ function mcpOuterConnectTimeoutMs(configuredTimeouts) {
78
+ return Math.max(
79
+ MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS,
80
+ ...configuredTimeouts.flatMap((timeoutMs) => timeoutMs === void 0 ? [] : [timeoutMs])
81
+ );
82
+ }
76
83
  var McpAggregateToolListBudget = class {
77
84
  constructor(label = "aggregate MCP tool list", maxEntries = MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES, maxBytes = MCP_MAX_AGGREGATE_TOOL_LIST_BYTES) {
78
85
  this.label = label;
@@ -269,6 +276,7 @@ export {
269
276
  MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES,
270
277
  MCP_MAX_SELECTED_SERVERS,
271
278
  MCP_MAX_CONCURRENT_SERVER_OPERATIONS,
279
+ MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS,
272
280
  MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES,
273
281
  MCP_MAX_AGGREGATE_TOOL_LIST_BYTES,
274
282
  MCP_MAX_TOOL_SEARCH_SOURCES,
@@ -279,6 +287,7 @@ export {
279
287
  assertMcpPayloadWithinBytes,
280
288
  assertMcpToolListWithinBounds,
281
289
  assertMcpServerSelectionWithinBounds,
290
+ mcpOuterConnectTimeoutMs,
282
291
  McpAggregateToolListBudget,
283
292
  boundedParallelMap,
284
293
  guardedMcpFetch,
@@ -289,4 +298,4 @@ export {
289
298
  isNonPublicMcpAddress,
290
299
  undiciFetch
291
300
  };
292
- //# sourceMappingURL=chunk-HAN5D27J.js.map
301
+ //# sourceMappingURL=chunk-SSB7VOLE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp-network.ts"],"sourcesContent":["import type { Settings } from \"@opengeni/config\";\nimport {\n isNonPublicAddress,\n pinnedFetch,\n resolvePinnedDestination,\n type DnsLookup,\n type FetchLike,\n} from \"@opengeni/network\";\n\nexport { undiciFetch } from \"@opengeni/network\";\n\nexport const MCP_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;\nexport const MCP_MAX_INBOUND_REQUEST_BYTES = 1024 * 1024;\nexport const MCP_MAX_TOOL_DEFINITION_BYTES = 128 * 1024;\nexport const MCP_MAX_TOOL_LIST_BYTES = 4 * 1024 * 1024;\nexport const MCP_MAX_TOOL_LIST_ENTRIES = 1_000;\nexport const MCP_MAX_TOOL_RESULT_BYTES = 1024 * 1024;\nexport const MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES = 256 * 1024;\nexport const MCP_MAX_SELECTED_SERVERS = 64;\nexport const MCP_MAX_CONCURRENT_SERVER_OPERATIONS = 8;\n// @openai/agents has a separate lifecycle fence around MCPServer.connect().\n// It defaults to 10 seconds and can otherwise preempt a larger per-server\n// transport timeout before that server finishes its own handshake.\nexport const MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS = 10_000;\nexport const MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = 4_096;\nexport const MCP_MAX_AGGREGATE_TOOL_LIST_BYTES = 16 * 1024 * 1024;\nexport const MCP_MAX_TOOL_SEARCH_SOURCES = 64;\nexport const MCP_MAX_TOOL_SEARCH_SOURCE_LABEL_LENGTH = 120;\nexport const MCP_MAX_TOOL_SEARCH_DESCRIPTION_BYTES = 16 * 1024;\n\nexport class McpPayloadTooLargeError extends Error {\n constructor(\n readonly label: string,\n readonly actualBytes: number,\n readonly maxBytes: number,\n ) {\n super(`${label} exceeds the ${maxBytes}-byte safety limit`);\n this.name = \"McpPayloadTooLargeError\";\n }\n}\n\nexport function mcpSerializedSizeBytes(value: unknown): number {\n let serialized: string;\n try {\n serialized = JSON.stringify(value) ?? \"null\";\n } catch {\n throw new Error(\"MCP payload is not JSON serializable\");\n }\n return Buffer.byteLength(serialized);\n}\n\nexport function assertMcpPayloadWithinBytes(value: unknown, maxBytes: number, label: string): void {\n const actualBytes = mcpSerializedSizeBytes(value);\n if (actualBytes > maxBytes) {\n throw new McpPayloadTooLargeError(label, actualBytes, maxBytes);\n }\n}\n\nexport function assertMcpToolListWithinBounds<T>(tools: readonly T[]): readonly T[] {\n if (tools.length > MCP_MAX_TOOL_LIST_ENTRIES) {\n throw new McpPayloadTooLargeError(\"MCP tool list\", tools.length, MCP_MAX_TOOL_LIST_ENTRIES);\n }\n for (const tool of tools) {\n const toolBytes = mcpSerializedSizeBytes(tool);\n if (toolBytes > MCP_MAX_TOOL_DEFINITION_BYTES) {\n throw new McpPayloadTooLargeError(\n \"MCP tool definition\",\n toolBytes,\n MCP_MAX_TOOL_DEFINITION_BYTES,\n );\n }\n }\n // Measure the complete JSON array, including brackets and separators. Summing\n // definitions alone under-counts by one byte per separator plus the array\n // delimiters and makes the advertised serialized-byte ceiling porous.\n const totalBytes = mcpSerializedSizeBytes(tools);\n if (totalBytes > MCP_MAX_TOOL_LIST_BYTES) {\n throw new McpPayloadTooLargeError(\"MCP tool list\", totalBytes, MCP_MAX_TOOL_LIST_BYTES);\n }\n return tools;\n}\n\nexport function assertMcpServerSelectionWithinBounds<T>(servers: readonly T[]): readonly T[] {\n if (servers.length > MCP_MAX_SELECTED_SERVERS) {\n throw new McpPayloadTooLargeError(\n \"selected MCP server count\",\n servers.length,\n MCP_MAX_SELECTED_SERVERS,\n );\n }\n return servers;\n}\n\nexport function mcpOuterConnectTimeoutMs(\n configuredTimeouts: readonly (number | undefined)[],\n): number {\n return Math.max(\n MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS,\n ...configuredTimeouts.flatMap((timeoutMs) => (timeoutMs === undefined ? [] : [timeoutMs])),\n );\n}\n\ntype McpToolListContribution = {\n entries: number;\n bytes: number;\n};\n\n/**\n * Atomic aggregate accounting shared by every exposed tools/list in one run.\n * A repeated list for the same source REPLACES its prior contribution, so\n * cache invalidation/relisting cannot ratchet the budget upward. Failed\n * replacements leave the previous accounting intact.\n */\nexport class McpAggregateToolListBudget {\n private readonly contributions = new Map<string, McpToolListContribution>();\n private totalEntries = 0;\n private totalBytes = 0;\n\n constructor(\n private readonly label = \"aggregate MCP tool list\",\n private readonly maxEntries = MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES,\n private readonly maxBytes = MCP_MAX_AGGREGATE_TOOL_LIST_BYTES,\n ) {}\n\n replace<T>(sourceId: string, tools: readonly T[]): readonly T[] {\n assertMcpToolListWithinBounds(tools);\n const contribution = {\n entries: tools.length,\n // Conservatively account each server as its complete serialized array.\n // Summing these arrays slightly over-counts the brackets relative to one\n // flattened array, which is intentional for a fail-closed hard ceiling.\n bytes: mcpSerializedSizeBytes(tools),\n };\n const previous = this.contributions.get(sourceId) ?? { entries: 0, bytes: 0 };\n const nextEntries = this.totalEntries - previous.entries + contribution.entries;\n if (nextEntries > this.maxEntries) {\n throw new McpPayloadTooLargeError(this.label, nextEntries, this.maxEntries);\n }\n const nextBytes = this.totalBytes - previous.bytes + contribution.bytes;\n if (nextBytes > this.maxBytes) {\n throw new McpPayloadTooLargeError(this.label, nextBytes, this.maxBytes);\n }\n this.contributions.set(sourceId, contribution);\n this.totalEntries = nextEntries;\n this.totalBytes = nextBytes;\n return tools;\n }\n\n remove(sourceId: string): void {\n const previous = this.contributions.get(sourceId);\n if (!previous) return;\n this.contributions.delete(sourceId);\n this.totalEntries -= previous.entries;\n this.totalBytes -= previous.bytes;\n }\n\n snapshot(): Readonly<McpToolListContribution> {\n return { entries: this.totalEntries, bytes: this.totalBytes };\n }\n}\n\n/** Stable-order parallel map with a hard in-flight ceiling and fail-stop drain. */\nexport async function boundedParallelMap<T, R>(\n values: readonly T[],\n concurrency: number,\n mapper: (value: T, index: number) => Promise<R>,\n): Promise<R[]> {\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n throw new Error(\"bounded parallel map concurrency must be a positive integer\");\n }\n if (values.length === 0) return [];\n\n const results = new Array<R>(values.length);\n const errors: Array<{ index: number; error: unknown }> = [];\n let nextIndex = 0;\n let stopped = false;\n const worker = async () => {\n while (!stopped) {\n const index = nextIndex;\n if (index >= values.length) return;\n nextIndex += 1;\n try {\n results[index] = await mapper(values[index]!, index);\n } catch (error) {\n errors.push({ index, error });\n stopped = true;\n }\n }\n };\n await Promise.all(Array.from({ length: Math.min(concurrency, values.length) }, () => worker()));\n if (errors.length > 0) {\n errors.sort((left, right) => left.index - right.index);\n throw errors[0]!.error;\n }\n return results;\n}\n\n/**\n * Guard normal MCP traffic with the same deployment policy as OAuth traffic.\n * The pinned transport resolves and policy-checks the destination after the\n * caller has composed any credential headers, then performs the final network\n * call through the vetted Agent. It forces manual redirects, so an\n * Authorization-bearing request never follows a provider-controlled Location\n * to an unvalidated host.\n *\n * This module is deliberately agent-loop-free. API code imports the explicit\n * `@opengeni/runtime/mcp-network` leaf rather than the runtime root barrel.\n */\nexport function guardedMcpFetch<TInput extends string | URL | Request>(\n settings: Pick<Settings, \"environment\" | \"integrationsAllowPrivateNetworkTargets\">,\n fetchImpl: (input: TInput, init?: RequestInit) => Promise<Response>,\n options: {\n maxResponseBytes?: number;\n dnsLookup?: DnsLookup;\n requireHttpsOutsideLocalTest?: boolean;\n } = {},\n): (input: TInput, init?: RequestInit) => Promise<Response> {\n return async (input: TInput, init?: RequestInit) => {\n const response = await pinnedFetch(input, init, settings, {\n fetchImpl: fetchImpl as FetchLike,\n ...(options.dnsLookup ? { dnsLookup: options.dnsLookup } : {}),\n label: \"MCP endpoint\",\n requireHttpsOutsideLocalTest: options.requireHttpsOutsideLocalTest ?? true,\n });\n return boundMcpResponseBody(response, options.maxResponseBytes ?? MCP_MAX_RESPONSE_BYTES);\n };\n}\n\nexport function boundMcpResponseBody(response: Response, maxBytes: number): Response {\n const declaredLength = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {\n void response.body?.cancel().catch(() => undefined);\n throw new McpPayloadTooLargeError(\"MCP response\", declaredLength, maxBytes);\n }\n if (!response.body) {\n return response;\n }\n\n const reader = response.body.getReader();\n let receivedBytes = 0;\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const chunk = await reader.read();\n if (chunk.done) {\n controller.close();\n return;\n }\n receivedBytes += chunk.value.byteLength;\n if (receivedBytes > maxBytes) {\n await reader.cancel().catch(() => undefined);\n controller.error(new McpPayloadTooLargeError(\"MCP response\", receivedBytes, maxBytes));\n return;\n }\n controller.enqueue(chunk.value);\n } catch (error) {\n controller.error(error);\n }\n },\n async cancel(reason) {\n await reader.cancel(reason).catch(() => undefined);\n },\n });\n const bounded = new Response(body, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n Object.defineProperties(bounded, {\n redirected: { value: response.redirected },\n type: { value: response.type },\n url: { value: response.url },\n });\n return bounded;\n}\n\nexport async function cancelMcpResponseBody(response: Response): Promise<void> {\n await response.body?.cancel().catch(() => undefined);\n}\n\n/** Read and rebuild an inbound MCP request before the SDK parses it. */\nexport async function boundedMcpRequest(\n request: Request,\n maxBytes = MCP_MAX_INBOUND_REQUEST_BYTES,\n): Promise<Request> {\n const declared = request.headers.get(\"content-length\");\n if (declared !== null) {\n const normalized = declared.trim();\n if (!/^\\d+$/.test(normalized)) {\n await request.body?.cancel().catch(() => undefined);\n throw new McpPayloadTooLargeError(\"MCP request\", 0, maxBytes);\n }\n const declaredBytes = Number(normalized);\n if (!Number.isSafeInteger(declaredBytes) || declaredBytes > maxBytes) {\n await request.body?.cancel().catch(() => undefined);\n throw new McpPayloadTooLargeError(\"MCP request\", declaredBytes, maxBytes);\n }\n }\n if (!request.body) {\n return request;\n }\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let receivedBytes = 0;\n try {\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n receivedBytes += result.value.byteLength;\n if (receivedBytes > maxBytes) {\n await reader.cancel().catch(() => undefined);\n throw new McpPayloadTooLargeError(\"MCP request\", receivedBytes, maxBytes);\n }\n chunks.push(result.value);\n }\n } catch (error) {\n await reader.cancel().catch(() => undefined);\n throw error;\n } finally {\n reader.releaseLock();\n }\n const body = new Uint8Array(receivedBytes);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new Request(request, { body, headers: request.headers });\n}\n\nexport async function assertMcpDestinationAllowed(\n rawUrl: string,\n settings: Pick<Settings, \"environment\" | \"integrationsAllowPrivateNetworkTargets\">,\n options: { dnsLookup?: DnsLookup } = {},\n): Promise<void> {\n await resolvePinnedDestination(rawUrl, settings, {\n ...(options.dnsLookup ? { dnsLookup: options.dnsLookup } : {}),\n label: \"MCP endpoint\",\n requireHttpsOutsideLocalTest: true,\n });\n}\n\nexport const isNonPublicMcpAddress = isNonPublicAddress;\n"],"mappings":"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","names":[]}
@@ -4,6 +4,48 @@ import { SandboxSessionLike, ExecCommandArgs, SandboxClient, Manifest, SandboxSe
4
4
  import * as modal from 'modal';
5
5
  import { ControlRequest, ControlResponse, ErrorCode, AgentError, ExecResponse, DesktopInputRequest, ExecRequest } from '@opengeni/agent-proto';
6
6
 
7
+ declare const WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION: 1;
8
+ type WorkspaceTreeFingerprint = {
9
+ algorithm: "sha256";
10
+ sha256: string;
11
+ entryCount: number;
12
+ fileCount: number;
13
+ totalFileBytes: number;
14
+ };
15
+ type WorkspaceArchiveDescriptor = {
16
+ version: typeof WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION;
17
+ revision: string;
18
+ archiveSha256: string;
19
+ archiveBytes: number;
20
+ capturedAt: string;
21
+ workspace: WorkspaceTreeFingerprint;
22
+ };
23
+ type VerifiedWorkspaceArchive = {
24
+ bytes: Uint8Array;
25
+ base64: string;
26
+ descriptor: WorkspaceArchiveDescriptor;
27
+ };
28
+ type WorkspaceArchiveIntegrityCode = "archive_metadata_missing" | "archive_metadata_invalid" | "archive_base64_invalid" | "archive_hash_mismatch" | "archive_hydration_failed" | "workspace_fingerprint_unavailable" | "workspace_changed_during_capture" | "workspace_fingerprint_mismatch";
29
+ declare class WorkspaceArchiveIntegrityError extends Error {
30
+ readonly code: WorkspaceArchiveIntegrityCode;
31
+ readonly name = "WorkspaceArchiveIntegrityError";
32
+ readonly retryable: boolean;
33
+ constructor(code: WorkspaceArchiveIntegrityCode, message: string, options?: {
34
+ retryable?: boolean;
35
+ });
36
+ }
37
+ declare function parseWorkspaceArchiveDescriptor(value: unknown): WorkspaceArchiveDescriptor | null;
38
+ declare function readVerifiedWorkspaceArchive(base64: unknown, metadata: unknown): VerifiedWorkspaceArchive | null;
39
+ /** Hashes names, kinds, modes, symlink targets and all file bytes through one
40
+ * deterministic GNU tar stream. Only the aggregate is returned; paths and file
41
+ * contents never enter logs or durable metadata. */
42
+ declare function fingerprintSandboxWorkspace(session: unknown): Promise<WorkspaceTreeFingerprint>;
43
+ /** Capture is accepted only when the complete tree is byte-identical immediately
44
+ * before and after the provider snapshot. A concurrent mutation makes the
45
+ * candidate non-durable and it is never folded onto the lease. */
46
+ declare function captureVerifiedWorkspaceArchive(session: unknown, capturedAtMs?: number): Promise<VerifiedWorkspaceArchive>;
47
+ declare function verifyRestoredWorkspace(session: unknown, descriptor: WorkspaceArchiveDescriptor): Promise<WorkspaceTreeFingerprint>;
48
+
7
49
  type RuntimeMetricsHooks = {
8
50
  onModelCall?: (input: {
9
51
  provider: string;
@@ -101,6 +143,39 @@ declare const PROVIDER_REGISTRY: Record<SandboxBackend, ProviderRegistration>;
101
143
  */
102
144
  declare function assertProviderRegistryInvariants(): void;
103
145
 
146
+ /**
147
+ * Provider sandbox failure classification.
148
+ *
149
+ * This is deliberately structural and fail-closed. DNS failures often contain
150
+ * the word "not found" (`ENOTFOUND`) while gRPC status values are also used by
151
+ * unrelated SDKs and command routers. A bare numeric status (including gRPC's
152
+ * numeric 5) is therefore not enough to retire a provider instance. Only
153
+ * authoritative, non-transient evidence may retire a provider instance and
154
+ * license lease recovery.
155
+ */
156
+ type ProviderSandboxFailureKind = "not_found" | "transient_transport" | "other";
157
+ type ProviderSandboxFailure = {
158
+ kind: ProviderSandboxFailureKind;
159
+ /** Bounded, non-secret diagnostic suitable for logs and lifecycle events. */
160
+ diagnostic: string;
161
+ };
162
+ /** Typed transport evidence always dominates nested/string NotFound text. */
163
+ declare function classifyProviderSandboxFailure(backendId: string, error: unknown): ProviderSandboxFailure;
164
+ declare function isProviderSandboxNotFoundError(backendId: string, error: unknown): boolean;
165
+ /**
166
+ * Whether a failure from an operation routed through an already-established
167
+ * sandbox proves that exact provider sandbox disappeared.
168
+ *
169
+ * Routed operations can legitimately return HTTP 404 / `NOT_FOUND` for paths,
170
+ * files, ports, processes, and other subresources. Those generic signals are
171
+ * sufficient for provider create/resume APIs, but they must never retire the
172
+ * live sandbox identity after an arbitrary operation. Only an explicit
173
+ * sandbox-scoped provider code or Modal's exact terminal sandbox grammar is
174
+ * authoritative on this path. Transient transport evidence still dominates.
175
+ */
176
+ declare function isProviderSandboxGoneDuringRoutedOperation(backendId: string, error: unknown): boolean;
177
+ declare function isProviderSandboxTransientError(backendId: string, error: unknown): boolean;
178
+
104
179
  type ModalSandboxAttribution = {
105
180
  leaseId: string;
106
181
  workspaceId: string;
@@ -156,6 +231,11 @@ interface NegotiationContext {
156
231
  liveness: "cold" | "warming" | "warm" | "draining";
157
232
  /** The lease epoch echoed on viewer heartbeats (the split-brain fence). */
158
233
  leaseEpoch: number;
234
+ /** Numeric/boolean archive completeness truth. Non-persistable targets use
235
+ * null/null/false; archive locations and provider details are never exposed. */
236
+ workspaceGeneration?: number | null;
237
+ archiveGeneration?: number | null;
238
+ archiveComplete?: boolean;
159
239
  /** The deployment desktop toggle (settings.sandboxDesktopEnabled). */
160
240
  desktopEnabled: boolean;
161
241
  /**
@@ -718,6 +798,7 @@ declare function recordingStorageKey(workspaceId: string, sessionId: string, rec
718
798
 
719
799
  declare function parseExecBannerSessionId(raw: string): number | null;
720
800
  declare function parseExecBannerExitCode(raw: string): number | null;
801
+ declare function isExecSessionLostBanner(out: string, execSessionId: number): boolean;
721
802
 
722
803
  type ChannelAExecResult = {
723
804
  output?: string;
@@ -756,6 +837,21 @@ type ChannelASession = {
756
837
  yieldTimeMs?: number;
757
838
  maxOutputTokens?: number;
758
839
  }): Promise<string>;
840
+ writeStdinForProcessMutation?(args: {
841
+ sessionId: number;
842
+ chars?: string;
843
+ yieldTimeMs?: number;
844
+ maxOutputTokens?: number;
845
+ }): Promise<string>;
846
+ writeStdinForProcessControl?(args: {
847
+ sessionId: number;
848
+ chars?: string;
849
+ yieldTimeMs?: number;
850
+ maxOutputTokens?: number;
851
+ }): Promise<string>;
852
+ cancelExecCommand?(opId: string): Promise<boolean>;
853
+ hasRetainedProcess?(providerSessionId: number): boolean;
854
+ execCommandForProcessControl?(providerSessionId: number, args: ChannelAExecArgs): Promise<string>;
759
855
  createEditor?(runAs?: string): ChannelAEditor;
760
856
  supportsPty?(): boolean;
761
857
  };
@@ -854,10 +950,9 @@ declare class SandboxChannelAService {
854
950
  detectReposDetailed(): Promise<RepositoryDiscoveryResult>;
855
951
  /** Detect repo roots within the workspace (for the Git.repos capability). */
856
952
  detectRepos(): Promise<string[]>;
857
- /** Run a bounded command, return buffered stdout/stderr + exit code inline. The
858
- * long-running tail (when the process hasn't exited within timeoutMs) keeps
859
- * running in-box; if emitStream is set the buffered output is also published as
860
- * the agent firehose so other viewers see it. */
953
+ /** Run a bounded command to physical completion and return buffered output.
954
+ * A deadline cancels the exact provider operation, proves its process group
955
+ * absent, and settles any retained-process admission before returning 124. */
861
956
  terminalExec(req: TerminalExecRequest): Promise<TerminalExecResponse>;
862
957
  /** Open an interactive PTY: exec the shell with tty:true, yielding the numeric
863
958
  * exec-session id the caller persists (ptyId<->execSessionId) so subsequent
@@ -877,9 +972,10 @@ declare class SandboxChannelAService {
877
972
  /** Resize an open PTY (SIGWINCH via stty against the exec-session). The SDK has
878
973
  * no resize method; stty in the same tty session updates the geometry. */
879
974
  ptyResize(req: PtyResizeRequest, execSessionId: number): Promise<void>;
880
- /** Close an open PTY: write exit/EOF. The caller marks the row closed + emits
881
- * terminal.pty.exited. */
882
- ptyClose(_req: PtyCloseRequest, execSessionId: number | null): Promise<void>;
975
+ /** Ask an open PTY to exit and return the exact provider banner. The routing
976
+ * session settles durable process authority only when that banner proves this
977
+ * locator exited or was lost; callers must keep metadata open otherwise. */
978
+ ptyClose(_req: PtyCloseRequest, execSessionId: number | null): Promise<string>;
883
979
  /** The current FS revision (for the caller to persist/seed). */
884
980
  currentRevision(): number;
885
981
  private joinRoot;
@@ -896,7 +992,6 @@ declare class SandboxChannelAService {
896
992
  emitGitChanged(repoPath: string, reason: GitChangedPayload["reason"]): Promise<void>;
897
993
  }
898
994
  declare function stripExecBanner(raw: string): string;
899
- declare function isExecSessionLostBanner(out: string, execSessionId: number): boolean;
900
995
  declare function assertSafeRelPath(p: string): string;
901
996
  declare function parsePorcelainV2(z: string): Omit<GitStatusResponse, "revision">;
902
997
  type NumstatEntry = {
@@ -2134,7 +2229,46 @@ interface ResolvedActiveBackend {
2134
2229
  sandboxId: string | null;
2135
2230
  /** A label for diagnostics ("modal" | "selfhosted" | the sandbox name). */
2136
2231
  kind: string;
2232
+ /** Exact durable home-lease epoch for a persistable provider. Absent for
2233
+ * connected-machine and other non-persistable route targets. */
2234
+ leaseEpoch?: number;
2235
+ /** Exact durable provider identity paired with `leaseEpoch`. This is internal
2236
+ * routing metadata only; it is never projected to an agent or public API. */
2237
+ providerInstanceId?: string;
2238
+ /** Active-pointer epoch observed when this route was resolved. The proxy fills
2239
+ * this internally even when a resolver omits it. */
2240
+ activeEpoch?: number;
2137
2241
  }
2242
+ /** Durable identity assigned to a provider exec that yielded instead of
2243
+ * exiting. The UUID is OpenGeni authority; the numeric provider session id is
2244
+ * only a locator within the exact copied backend route. */
2245
+ type RoutingRetainedProcess = {
2246
+ id: string;
2247
+ providerSessionId: number;
2248
+ };
2249
+ /** Exact copied route identity required to reconstruct an already-durable
2250
+ * retained process after the request/runtime object that opened it is gone.
2251
+ * The live session is deliberately not caller-supplied: adoption may bind only
2252
+ * to this proxy's construction-time default backend, so it cannot resolve or
2253
+ * follow the current active pointer. */
2254
+ type RoutingRetainedProcessAdoption = {
2255
+ process: RoutingRetainedProcess;
2256
+ backend: {
2257
+ sandboxId: string | null;
2258
+ leaseEpoch?: number;
2259
+ providerInstanceId?: string;
2260
+ activeEpoch: number;
2261
+ };
2262
+ };
2263
+ type RoutingRetainedProcessTerminalProof = {
2264
+ outcome: "exited";
2265
+ exitCode: number;
2266
+ reason: "provider_exit_banner";
2267
+ } | {
2268
+ outcome: "lost";
2269
+ exitCode: null;
2270
+ reason: "provider_session_lost_banner";
2271
+ };
2138
2272
  interface RoutingSandboxSessionDeps {
2139
2273
  /**
2140
2274
  * The DEFAULT backend resolved at construction time (the same shape `resolve()`
@@ -2166,7 +2300,68 @@ interface RoutingSandboxSessionDeps {
2166
2300
  maxFenceRetries?: number;
2167
2301
  /** Optional structured-log sink for swap/fence transitions (diagnostics). */
2168
2302
  onTransition?: (event: RoutingTransitionEvent) => void;
2303
+ /** Admit a filesystem-writing operation after resolving its exact route but
2304
+ * before invoking the provider. A rejection fails closed and is deliberately
2305
+ * outside provider fence-retry/error handling, so it can never replay the op
2306
+ * against a rival backend. */
2307
+ beforeMutation?: (input: {
2308
+ op: string;
2309
+ backend: ResolvedActiveBackend;
2310
+ }) => Promise<unknown>;
2311
+ /** Mark a mutation physically settled after its provider promise resolves OR
2312
+ * rejects. A resolved result is also revalidated against the same durable
2313
+ * route and attempt fence before its output is accepted. Settlement rejection
2314
+ * leaves a fail-closed blocker and the mutation must never be replayed. */
2315
+ afterMutation?: (input: {
2316
+ op: string;
2317
+ backend: ResolvedActiveBackend;
2318
+ admission: unknown;
2319
+ outcome: "resolved" | "rejected";
2320
+ /** Provider result for a resolved call. Never present for rejection. */
2321
+ result?: unknown;
2322
+ /** Stable candidate generated before durable promotion is attempted. It is
2323
+ * supplied only when the provider returned a positive yielded-session id. */
2324
+ retainedProcess?: RoutingRetainedProcess;
2325
+ }) => Promise<void>;
2326
+ /** Admit one model/user-visible stdin mutation under the already-durable
2327
+ * retained process authority. Control polling and helper execs never call it. */
2328
+ beforeProcessMutation?: (input: {
2329
+ op: string;
2330
+ backend: ResolvedActiveBackend;
2331
+ process: RoutingRetainedProcess;
2332
+ }) => Promise<unknown>;
2333
+ /** Physically settle one process-scoped stdin admission. */
2334
+ afterProcessMutation?: (input: {
2335
+ op: string;
2336
+ backend: ResolvedActiveBackend;
2337
+ process: RoutingRetainedProcess;
2338
+ admission: unknown;
2339
+ outcome: "resolved" | "rejected";
2340
+ result?: unknown;
2341
+ }) => Promise<void>;
2342
+ /** Close the durable parent admission/process holder only after exact exit or
2343
+ * matching provider-loss proof. Tracking is removed only after this resolves. */
2344
+ settleProcess?: (input: {
2345
+ backend: ResolvedActiveBackend;
2346
+ process: RoutingRetainedProcess;
2347
+ proof: RoutingRetainedProcessTerminalProof;
2348
+ }) => Promise<void>;
2349
+ /** Called only when an operation against the default/home backend throws a
2350
+ * non-fence error. Wiring may classify definitive provider disappearance and
2351
+ * atomically retire the exact lease epoch. Returning a result makes dispatch
2352
+ * throw a typed recovery-required error WITHOUT replaying the operation (the
2353
+ * original mutation may have reached the provider). */
2354
+ onDefaultBackendError?: (input: {
2355
+ op: string;
2356
+ error: unknown;
2357
+ kind: string;
2358
+ backend: ResolvedActiveBackend;
2359
+ }) => Promise<DefaultBackendLossResult | null>;
2169
2360
  }
2361
+ type DefaultBackendLossResult = {
2362
+ leaseEpoch: number;
2363
+ recovery: "pending" | "degraded" | "unrecoverable" | "superseded";
2364
+ };
2170
2365
  interface RoutingTransitionEvent {
2171
2366
  type: "resolved" | "fenced-retry" | "epoch-changed";
2172
2367
  fromEpoch: number;
@@ -2180,6 +2375,34 @@ declare class RoutingUnsupportedError extends Error {
2180
2375
  readonly name = "RoutingUnsupportedError";
2181
2376
  constructor(op: string, kind: string);
2182
2377
  }
2378
+ declare class RoutingBackendRecoveryRequiredError extends Error {
2379
+ readonly op: string;
2380
+ readonly leaseEpoch: number;
2381
+ readonly recovery: DefaultBackendLossResult["recovery"];
2382
+ readonly name = "RoutingBackendRecoveryRequiredError";
2383
+ readonly retryable: boolean;
2384
+ constructor(op: string, leaseEpoch: number, recovery: DefaultBackendLossResult["recovery"]);
2385
+ }
2386
+ /** A mutating provider call was admitted but could not be settled against the
2387
+ * exact route that admitted it. The provider may have applied the effect, so the
2388
+ * proxy rejects the output and explicitly forbids an automatic replay. */
2389
+ declare class RoutingMutationOutcomeUnknownError extends Error {
2390
+ readonly op: string;
2391
+ readonly name = "RoutingMutationOutcomeUnknownError";
2392
+ readonly retryable = false;
2393
+ constructor(op: string, message: string, options?: {
2394
+ cause?: unknown;
2395
+ });
2396
+ }
2397
+ /** An explicit process-aware operation named a numeric provider locator that
2398
+ * is not retained by this routing session. Callers must never fall back to the
2399
+ * current active pointer for such an operation. */
2400
+ declare class RoutingRetainedProcessNotFoundError extends Error {
2401
+ readonly providerSessionId: number;
2402
+ readonly name = "RoutingRetainedProcessNotFoundError";
2403
+ readonly retryable = false;
2404
+ constructor(providerSessionId: number);
2405
+ }
2183
2406
  /**
2184
2407
  * ONE stable session-shaped object the SDK binds to. Every method re-reads the
2185
2408
  * pointer, resolves the active backend (cached by epoch), and dispatches. A
@@ -2202,6 +2425,10 @@ declare class RoutingSandboxSession implements RoutableBackendSession {
2202
2425
  private cachedSandboxId;
2203
2426
  private cached;
2204
2427
  private lastResolved;
2428
+ /** Provider session ids are scoped to one backend instance. Each entry copies
2429
+ * that exact resolved route so pointer movement can never redirect stdin,
2430
+ * polling, or process-group helpers to another box. */
2431
+ private readonly retainedProcesses;
2205
2432
  desktopInput?: (event: unknown) => Promise<void>;
2206
2433
  screenshot?: () => Promise<{
2207
2434
  png: Uint8Array;
@@ -2234,6 +2461,20 @@ declare class RoutingSandboxSession implements RoutableBackendSession {
2234
2461
  * is THE per-call re-read that makes a mid-turn swap land on the next op.
2235
2462
  */
2236
2463
  private resolve;
2464
+ private invalidate;
2465
+ private registerRetainedProcess;
2466
+ private retainedProcess;
2467
+ /** Reconstruct one process that was already promoted durably by an earlier
2468
+ * request. Adoption never reads the active pointer and never repeats parent
2469
+ * promotion. It can bind only to the exact construction-time default backend;
2470
+ * callers must reject non-default routes until they can independently rebuild
2471
+ * that provider session from its copied durable identity. */
2472
+ adoptRetainedProcess(input: RoutingRetainedProcessAdoption): void;
2473
+ private ensureParentPromotion;
2474
+ private settleRetainedProcess;
2475
+ private flushPendingProcessMutation;
2476
+ private dispatchProcessMutation;
2477
+ private dispatchProcessControl;
2237
2478
  /**
2238
2479
  * Dispatch an op to the currently-active backend, retrying on a stale-epoch
2239
2480
  * fence. The sequence per attempt:
@@ -2268,6 +2509,25 @@ declare class RoutingSandboxSession implements RoutableBackendSession {
2268
2509
  exec(args: unknown): Promise<unknown>;
2269
2510
  execCommand(args: unknown): Promise<string>;
2270
2511
  writeStdin(args: unknown): Promise<string>;
2512
+ /** Whether a positive provider session locator is still pinned to the exact
2513
+ * backend that yielded it. This synchronous probe is used only to select the
2514
+ * process-aware routing surface; it is not itself durable authority. */
2515
+ hasRetainedProcess(providerSessionId: number): boolean;
2516
+ /** Return only OpenGeni's durable UUID + provider locator. Backend/session
2517
+ * objects remain private so a caller cannot forge route authority from this
2518
+ * diagnostic handoff. */
2519
+ retainedProcessIdentity(providerSessionId: number): RoutingRetainedProcess | null;
2520
+ /** Model/user-visible stdin is a distinct workspace mutation admission under
2521
+ * the durable retained-process holder. It never re-reads the active pointer. */
2522
+ writeStdinForProcessMutation(args: unknown): Promise<string>;
2523
+ /** Cancellation and drain polling are control operations. They stay pinned to
2524
+ * the process backend and may prove terminal state, but never advance the
2525
+ * workspace generation. */
2526
+ writeStdinForProcessControl(args: unknown): Promise<string>;
2527
+ /** Run a PID/PGID marker or signal helper on the retained process's exact
2528
+ * backend. The helper is control-plane work and therefore has no workspace
2529
+ * mutation admission of its own. */
2530
+ execCommandForProcessControl(providerSessionId: number, args: unknown): Promise<string>;
2271
2531
  cancelExecCommand(opId: string): Promise<boolean>;
2272
2532
  readFile(args: unknown): Promise<string | Uint8Array>;
2273
2533
  writeFile(args: unknown): Promise<unknown>;
@@ -2291,7 +2551,10 @@ declare class RoutingSandboxSession implements RoutableBackendSession {
2291
2551
  * direct delegate returns undefined and every lazy turn would die at bind. Return a
2292
2552
  * LAZY EDITOR PROXY instead: a non-null editor whose async ops resolve the active
2293
2553
  * backend (establishing the box on first use, via `dispatch`) and delegate to its
2294
- * real editor — mirroring how this proxy defers exec/readFile. */
2554
+ * real editor — mirroring how this proxy defers exec/readFile. Even when an
2555
+ * eager editor already exists, returning it directly would bypass per-edit
2556
+ * route resolution and mutation-generation admission, so every editor is
2557
+ * represented by this dispatching proxy. */
2295
2558
  createEditor(runAs?: string): unknown;
2296
2559
  resolveExposedPort(port: number): Promise<ExposedPortEndpoint>;
2297
2560
  /** Serialize the active backend's session state. Used by the resume-by-id seam
@@ -2321,6 +2584,18 @@ interface ActiveBackendResolverDeps {
2321
2584
  defaultBackend: RoutableBackendSession;
2322
2585
  /** A label for the default backend (its backend id: "modal"/"selfhosted"/…). */
2323
2586
  defaultKind: string;
2587
+ /**
2588
+ * Re-resolve the session's HOME backend after the route cache is fenced.
2589
+ *
2590
+ * The normal path returns `defaultBackend` (the turn's already-established
2591
+ * handle), but an API-side same-target repair can rematerialize that lease
2592
+ * while a worker turn is still alive. Such a repair advances the route epoch
2593
+ * without changing the null pointer; callers that can resume the current
2594
+ * lease-owned identity may provide this callback so the next epoch does not
2595
+ * keep dispatching to the dead pre-repair object. This callback must never
2596
+ * create a provider or replay an operation.
2597
+ */
2598
+ resolveDefaultBackend?: (pointer: ActivePointer) => Promise<ResolvedActiveBackend>;
2324
2599
  /** Look up a first-class sandbox by id (the swap target). Returns null when the
2325
2600
  * id is unknown or not in this workspace (the caller 409s the swap). */
2326
2601
  getSandbox(sandboxId: string): Promise<RoutableSandbox | null>;
@@ -2549,23 +2824,22 @@ type EstablishedSandboxSession = {
2549
2824
  /** Set when a create-authorized reattach found the envelope's box GONE
2550
2825
  * (provider NotFound) and fell through to cold-restore. */
2551
2826
  lostInstanceId?: string;
2827
+ /** Exact durable archive revision verified byte-for-byte after hydration. */
2828
+ restoredArchive?: WorkspaceArchiveDescriptor;
2552
2829
  };
2830
+ declare class SandboxExecReadinessError extends Error {
2831
+ readonly backend: string;
2832
+ readonly code: "exec_probe_unavailable" | "exec_probe_timeout" | "exec_probe_failed";
2833
+ readonly timeoutMs: number;
2834
+ readonly exitCode: number | null;
2835
+ readonly name = "SandboxExecReadinessError";
2836
+ constructor(backend: string, code: "exec_probe_unavailable" | "exec_probe_timeout" | "exec_probe_failed", timeoutMs: number, exitCode?: number | null);
2837
+ }
2838
+ /** A provider handle is not workspace readiness. Modal can return a handle
2839
+ * before its command router accepts exec, so every create path must pass this
2840
+ * bounded probe before atomically publishing the lease warm/ready. */
2841
+ declare function verifySandboxExecReadiness(established: EstablishedSandboxSession, timeoutMs?: number): Promise<void>;
2553
2842
  type SandboxCreatedCallback = (established: EstablishedSandboxSession) => Promise<void>;
2554
- /**
2555
- * Per-provider NotFound discriminator. The @openai/agents-extensions
2556
- * `isProviderSandboxNotFoundError` / `assertResumeRecreateAllowed` helpers live
2557
- * under `@openai/agents-extensions/sandbox/shared`, which is NOT an exported
2558
- * subpath (the package `exports` map only exposes `./sandbox/<provider>`), so we
2559
- * re-implement the discrimination here by inspecting the thrown error shape.
2560
- *
2561
- * "Box no longer running" (the box was reaped / idled out / 24h-ceiling) is the
2562
- * ONLY error that licenses a cold-restore via create(). Every other resume
2563
- * failure (transient provider error, auth, network) must propagate so the caller
2564
- * backs off — never spawns a rival box. We err on the side of NOT recreating:
2565
- * an unrecognized error is treated as "not NotFound" (propagate), because a
2566
- * false-positive recreate is the dangerous direction (double-spawn).
2567
- */
2568
- declare function isProviderSandboxNotFoundError(backendId: string, error: unknown): boolean;
2569
2843
  /**
2570
2844
  * Establish from one recovery envelope under an explicit creation policy. The
2571
2845
  * envelope is the lease's box-identity descriptor (the same per-turn `_sandbox`
@@ -2585,6 +2859,10 @@ declare function establishSandboxSessionFromEnvelope(settings: Settings, envelop
2585
2859
  backendOverride?: SandboxBackend;
2586
2860
  environment?: Record<string, string>;
2587
2861
  onSandboxCreated?: SandboxCreatedCallback;
2862
+ /** Called after archive hydration but immediately before the exact workspace
2863
+ * fingerprint probe. Lease-aware callers persist `verifying` here so a box
2864
+ * is never observable as ready while verification is in flight. */
2865
+ onWorkspaceRestoreVerifying?: (descriptor: WorkspaceArchiveDescriptor) => Promise<void>;
2588
2866
  metrics?: RuntimeMetricsHooks;
2589
2867
  }): Promise<EstablishedSandboxSession>;
2590
2868
  /**
@@ -2600,5 +2878,30 @@ declare function establishSandboxSessionFromEnvelope(settings: Settings, envelop
2600
2878
  * no warm-reattach).
2601
2879
  */
2602
2880
  declare function serializeEstablishedSandboxEnvelope(established: EstablishedSandboxSession): Promise<Record<string, unknown> | null>;
2881
+ /**
2882
+ * Whether a replacement envelope contains a provider-resumable identity. An
2883
+ * archive-only envelope is intentionally valid recovery metadata, but it is
2884
+ * never proof that the newly-created provider box can be resumed or attached.
2885
+ */
2886
+ declare function hasPersistableSandboxProviderIdentity(envelope: Record<string, unknown> | null | undefined): envelope is Record<string, unknown>;
2887
+ /** A replacement provider may not be published warm without a resumable
2888
+ * identity. Archive-only state is retained only when the caller rolls back to
2889
+ * cold and needs the verified workspace bytes for the next attempt. */
2890
+ declare class SandboxReplacementProviderStateError extends Error {
2891
+ readonly backend: string;
2892
+ readonly code: "replacement_provider_state_unpersistable";
2893
+ constructor(backend: string);
2894
+ }
2895
+ declare function requirePersistableReplacementSandboxEnvelope(envelope: Record<string, unknown> | null, backend: string): Record<string, unknown>;
2896
+ /**
2897
+ * Build the only resume envelope that may be published for a newly-created
2898
+ * replacement sandbox. Historical state contributes durable archive pointers
2899
+ * only; it can never substitute for serialization of the replacement's provider
2900
+ * identity. If replacement serialization is unavailable or fails, publication
2901
+ * keeps an archive-only envelope (when one exists) or null. The new instance id
2902
+ * remains separately fenced on the lease, while later attach/resume fails closed
2903
+ * rather than targeting the dead provider that initiated rematerialization.
2904
+ */
2905
+ declare function serializeReplacementSandboxEnvelope(established: EstablishedSandboxSession, archiveSource: Record<string, unknown> | null): Promise<Record<string, unknown> | null>;
2603
2906
 
2604
- export { type NegotiationContext as $, type ActiveBackendResolverDeps as A, type BackendUnresolvableCode as B, ChannelAConflictError as C, DEFAULT_DESKTOP_GEOMETRY as D, type EnsureDisplayStackOptions as E, type ExposeStreamPortResult as F, type ExposedPortEndpoint as G, FAULT_FIELD_WHAT_HAPPENED as H, FAULT_FIELD_WHAT_PRESERVED as I, FAULT_FIELD_WHAT_TO_TRY as J, FAULT_FIELD_WHICH_LAYER as K, type LiveModalSandboxLeaseAttribution as L, type MaterializeRunCredentialsOptions as M, type MintStreamTokenInput as N, MockAgentResponder as O, type MockAgentResponderOptions as P, type MockExecHandler as Q, type RunCredentialSessionReady as R, type ModalModuleLoader as S, type ModalOrphanSweepResult as T, type ModalOrphanSweepTermination as U, type ModalSandboxAttribution as V, NEVER_SENT_DETAIL_KEY as W, NatsControlRpc as X, type NatsOpStreamConnection as Y, NatsOpStreamTransport as Z, type NatsRequestConnection as _, type RuntimeMetricsHooks as a, type SelfhostedNegotiationInput as a$, type NormalizedRunCredentialMaterial as a0, type NumstatEntry as a1, OP_STREAM_ACK_INTERVAL_MS as a2, OP_STREAM_DEFAULT_WINDOW_BYTES as a3, OP_STREAM_RECONNECT_HOLD_MS as a4, OP_STREAM_SILENCE_TIMEOUT_MS as a5, type OpStreamExecOutcome as a6, type OpStreamJournal as a7, type OpStreamSubscription as a8, type OpStreamTransport as a9, SELFHOSTED_DRAINING_MAX_RETRIES as aA, SELFHOSTED_EXEC_DRAINING_MAX_RETRIES as aB, SELFHOSTED_IDEMPOTENT_READONLY_OPS as aC, SELFHOSTED_INFRASTRUCTURE_FAULT_CLASSES as aD, SELFHOSTED_NEVER_SENT_MAX_RETRIES as aE, SELFHOSTED_RECONNECT_WINDOW_MS as aF, SELFHOSTED_RELAY_STREAM_PATH as aG, SELFHOSTED_RETRY_BACKOFF_BASE_MS as aH, SELFHOSTED_RETRY_BACKOFF_CAP_MS as aI, SELFHOSTED_RETRY_BACKOFF_FACTOR as aJ, SELFHOSTED_TIMEOUT_MAX_RETRIES as aK, STREAM_PORT as aL, STREAM_TOKEN_DEFAULT_TTL_SECONDS as aM, SandboxChannelAService as aN, type SandboxChannelAServiceOptions as aO, SandboxConfigError as aP, type SandboxCreatedCallback as aQ, SandboxProviderUnavailableError as aR, SandboxResumeStateUnavailableError as aS, type SelfhostedApplyDiff as aT, SelfhostedControlError as aU, type SelfhostedEditor as aV, type SelfhostedEnrollment as aW, type SelfhostedExecArgs as aX, type SelfhostedExecResult as aY, type SelfhostedImageOutput as aZ, type SelfhostedLivenessState as a_, OpStreamUnavailableError as aa, PROVIDER_REGISTRY as ab, type ProviderConstructionContext as ac, type ProviderRegistration as ad, REPOSITORY_DISCOVERY_LIMIT as ae, type RecordingArtifactMetadata as af, type RecordingCodec as ag, type RecordingContentType as ah, RecordingError as ai, type RecordingProcess as aj, RecordingUnavailableError as ak, type RepositoryDiscoveryDegradedReason as al, type RepositoryDiscoveryResult as am, type ResolvedActiveBackend as an, type RevalidateModalOrphanTermination as ao, type RoutableBackendSession as ap, type RoutableSandbox as aq, RoutingSandboxSession as ar, type RoutingSandboxSessionDeps as as, type RoutingTransitionEvent as at, RoutingUnsupportedError as au, type RunCredentialCommandRunner as av, type RunCredentialCommandSession as aw, type RunCredentialExpectedScope as ax, RunCredentialValidationError as ay, SELFHOSTED_DEFAULT_TIMEOUT_MS as az, ActiveBackendUnresolvableError as b, offlineControlResponse as b$, type SelfhostedOpObservation as b0, type SelfhostedOpObserver as b1, type SelfhostedOpStreamDeps as b2, type SelfhostedRelayConfig as b3, type SelfhostedRetryClock as b4, type SelfhostedRetryDecision as b5, SelfhostedSandboxClient as b6, SelfhostedSession as b7, type SelfhostedSessionBuild as b8, type SelfhostedSessionDeps as b9, deletePriorPersistedSnapshot as bA, deleteRecordingArtifacts as bB, deserializeSandboxSessionStateEnvelope as bC, desktopCapableBackend as bD, drainingExhaustedError as bE, drainingMessage as bF, ensureDisplayStack as bG, ensureModalRegistryImage as bH, ensureTerminalServer as bI, establishSandboxSessionFromEnvelope as bJ, execDeadlineHint as bK, exposeStreamPort as bL, extForCodec as bM, inspectRecordingArtifact as bN, isExecSessionLostBanner as bO, isProviderSandboxNotFoundError as bP, isSelfhostedProviderNotFoundError as bQ, makeActiveBackendResolver as bR, materializeRunCredentials as bS, mintStreamToken as bT, modalSandboxAttributionEnvironment as bU, modalSandboxAttributionTags as bV, negotiateCapabilities as bW, negotiateSelfhostedCapabilities as bX, nextDurableOpId as bY, normalizeRunCredentialsResolution as bZ, offlineAgentError as b_, type SelfhostedSessionState as ba, type SelfhostedUnavailableReason as bb, type StartRecordingInput as bc, StreamPortUnavailableError as bd, type SwapTargetEstablishability as be, TERMINAL_SERVER_TIMEOUT_MS as bf, TerminalServerError as bg, TerminalServerUnsupportedError as bh, ToolspaceTokenPathError as bi, agentErrorToControlError as bj, assertDescriptorRegistryInvariants as bk, assertProviderRegistryInvariants as bl, assertSafeRelPath as bm, backendSupportsOs as bn, buildDisplayStackScript as bo, buildSelfhostedBackendSession as bp, buildStreamUrl as bq, buildTerminalServerScript as br, clearRunCredentials as bs, clearRunCredentialsForAttempt as bt, contentTypeForCodec as bu, createSandboxClient as bv, createSandboxClientForBackend as bw, decideSelfhostedRetry as bx, decodeModalSnapshotId as by, defaultSelfhostedRetryClock as bz, type ActivePointer as c, opAckSubject as c0, opFrameSubject as c1, parseExecBannerExitCode as c2, parseExecBannerSessionId as c3, parseNumstatZ as c4, parsePorcelainV2 as c5, parseUnifiedPatch as c6, payloadTooLargeMessage as c7, readWorkspaceArchiveFromEnvelopeSessionState as c8, recordingStorageKey as c9, toolspaceTokenFileFromEnvironment as cA, uploadRecordingArtifact as cB, verifyStreamToken as cC, withRunCredentialEnvironment as cD, withRunCredentialsClient as cE, withRunCredentialsSession as cF, withToolspaceTokenClient as cG, withToolspaceTokenEnvironment as cH, withToolspaceTokenSession as cI, renderSelfhostedFault as ca, restoredSandboxSessionStateFromEntry as cb, runCredentialPointerFile as cc, runCredentialRoot as cd, runWithToolCallCorrelation as ce, sandboxStateEntryFromRunState as cf, sanitizeOpIdToken as cg, selectBackend as ch, selfhostedFaultClass as ci, selfhostedLiveness as cj, selfhostedRetryBackoffMs as ck, serializeEstablishedSandboxEnvelope as cl, setSelfhostedApplyDiff as cm, startRecording as cn, stopRecording as co, stripExecBanner as cp, subjectFor as cq, swapTargetEstablishability as cr, sweepModalOrphanSandboxes as cs, tagModalSandbox as ct, tearDownDisplayStack as cu, tearDownTerminalServer as cv, terminateModalSandboxById as cw, timeoutAgentError as cx, timeoutControlResponse as cy, toolspaceTokenFileForSession as cz, type ChannelAEmitter as d, type ChannelAExecArgs as e, type ChannelAExecResult as f, ChannelANotFoundError as g, type ChannelASession as h, ChannelAUnavailableError as i, ChannelAUnsupportedError as j, ChannelAValidationError as k, type ControlRpc as l, DISPLAY_STACK_TIMEOUT_MS as m, type DesktopGeometry as n, type DisplayStackCallerKind as o, type DisplayStackClassification as p, DisplayStackError as q, type DisplayStackTelemetryContext as r, type DisplayStackTelemetryEvent as s, type DisplayStackTelemetryStatus as t, DisplayStackUnsupportedError as u, type EnsureDisplayStackResult as v, type EnsureTerminalServerOptions as w, type EnsureTerminalServerResult as x, type EstablishedSandboxSession as y, type ExposeStreamPortInput as z };
2907
+ export { type NatsRequestConnection as $, type ActiveBackendResolverDeps as A, type BackendUnresolvableCode as B, ChannelAConflictError as C, DEFAULT_DESKTOP_GEOMETRY as D, type EnsureDisplayStackOptions as E, type ExposeStreamPortInput as F, type ExposeStreamPortResult as G, type ExposedPortEndpoint as H, FAULT_FIELD_WHAT_HAPPENED as I, FAULT_FIELD_WHAT_PRESERVED as J, FAULT_FIELD_WHAT_TO_TRY as K, FAULT_FIELD_WHICH_LAYER as L, type LiveModalSandboxLeaseAttribution as M, type MaterializeRunCredentialsOptions as N, type MintStreamTokenInput as O, MockAgentResponder as P, type MockAgentResponderOptions as Q, type RunCredentialSessionReady as R, type MockExecHandler as S, type ModalModuleLoader as T, type ModalOrphanSweepResult as U, type ModalOrphanSweepTermination as V, type ModalSandboxAttribution as W, NEVER_SENT_DETAIL_KEY as X, NatsControlRpc as Y, type NatsOpStreamConnection as Z, NatsOpStreamTransport as _, type RuntimeMetricsHooks as a, SandboxProviderUnavailableError as a$, type NegotiationContext as a0, type NormalizedRunCredentialMaterial as a1, type NumstatEntry as a2, OP_STREAM_ACK_INTERVAL_MS as a3, OP_STREAM_DEFAULT_WINDOW_BYTES as a4, OP_STREAM_RECONNECT_HOLD_MS as a5, OP_STREAM_SILENCE_TIMEOUT_MS as a6, type OpStreamExecOutcome as a7, type OpStreamJournal as a8, type OpStreamSubscription as a9, RoutingSandboxSession as aA, type RoutingSandboxSessionDeps as aB, type RoutingTransitionEvent as aC, RoutingUnsupportedError as aD, type RunCredentialCommandRunner as aE, type RunCredentialCommandSession as aF, type RunCredentialExpectedScope as aG, RunCredentialValidationError as aH, SELFHOSTED_DEFAULT_TIMEOUT_MS as aI, SELFHOSTED_DRAINING_MAX_RETRIES as aJ, SELFHOSTED_EXEC_DRAINING_MAX_RETRIES as aK, SELFHOSTED_IDEMPOTENT_READONLY_OPS as aL, SELFHOSTED_INFRASTRUCTURE_FAULT_CLASSES as aM, SELFHOSTED_NEVER_SENT_MAX_RETRIES as aN, SELFHOSTED_RECONNECT_WINDOW_MS as aO, SELFHOSTED_RELAY_STREAM_PATH as aP, SELFHOSTED_RETRY_BACKOFF_BASE_MS as aQ, SELFHOSTED_RETRY_BACKOFF_CAP_MS as aR, SELFHOSTED_RETRY_BACKOFF_FACTOR as aS, SELFHOSTED_TIMEOUT_MAX_RETRIES as aT, STREAM_PORT as aU, STREAM_TOKEN_DEFAULT_TTL_SECONDS as aV, SandboxChannelAService as aW, type SandboxChannelAServiceOptions as aX, SandboxConfigError as aY, type SandboxCreatedCallback as aZ, SandboxExecReadinessError as a_, type OpStreamTransport as aa, OpStreamUnavailableError as ab, PROVIDER_REGISTRY as ac, type ProviderConstructionContext as ad, type ProviderRegistration as ae, type ProviderSandboxFailure as af, type ProviderSandboxFailureKind as ag, REPOSITORY_DISCOVERY_LIMIT as ah, type RecordingArtifactMetadata as ai, type RecordingCodec as aj, type RecordingContentType as ak, RecordingError as al, type RecordingProcess as am, RecordingUnavailableError as an, type RepositoryDiscoveryDegradedReason as ao, type RepositoryDiscoveryResult as ap, type ResolvedActiveBackend as aq, type RevalidateModalOrphanTermination as ar, type RoutableBackendSession as as, type RoutableSandbox as at, RoutingBackendRecoveryRequiredError as au, RoutingMutationOutcomeUnknownError as av, type RoutingRetainedProcess as aw, type RoutingRetainedProcessAdoption as ax, RoutingRetainedProcessNotFoundError as ay, type RoutingRetainedProcessTerminalProof as az, ActiveBackendUnresolvableError as b, ensureTerminalServer as b$, SandboxReplacementProviderStateError as b0, SandboxResumeStateUnavailableError as b1, type SelfhostedApplyDiff as b2, SelfhostedControlError as b3, type SelfhostedEditor as b4, type SelfhostedEnrollment as b5, type SelfhostedExecArgs as b6, type SelfhostedExecResult as b7, type SelfhostedImageOutput as b8, type SelfhostedLivenessState as b9, agentErrorToControlError as bA, assertDescriptorRegistryInvariants as bB, assertProviderRegistryInvariants as bC, assertSafeRelPath as bD, backendSupportsOs as bE, buildDisplayStackScript as bF, buildSelfhostedBackendSession as bG, buildStreamUrl as bH, buildTerminalServerScript as bI, captureVerifiedWorkspaceArchive as bJ, classifyProviderSandboxFailure as bK, clearRunCredentials as bL, clearRunCredentialsForAttempt as bM, contentTypeForCodec as bN, createSandboxClient as bO, createSandboxClientForBackend as bP, decideSelfhostedRetry as bQ, decodeModalSnapshotId as bR, defaultSelfhostedRetryClock as bS, deletePriorPersistedSnapshot as bT, deleteRecordingArtifacts as bU, deserializeSandboxSessionStateEnvelope as bV, desktopCapableBackend as bW, drainingExhaustedError as bX, drainingMessage as bY, ensureDisplayStack as bZ, ensureModalRegistryImage as b_, type SelfhostedNegotiationInput as ba, type SelfhostedOpObservation as bb, type SelfhostedOpObserver as bc, type SelfhostedOpStreamDeps as bd, type SelfhostedRelayConfig as be, type SelfhostedRetryClock as bf, type SelfhostedRetryDecision as bg, SelfhostedSandboxClient as bh, SelfhostedSession as bi, type SelfhostedSessionBuild as bj, type SelfhostedSessionDeps as bk, type SelfhostedSessionState as bl, type SelfhostedUnavailableReason as bm, type StartRecordingInput as bn, StreamPortUnavailableError as bo, type SwapTargetEstablishability as bp, TERMINAL_SERVER_TIMEOUT_MS as bq, TerminalServerError as br, TerminalServerUnsupportedError as bs, ToolspaceTokenPathError as bt, type VerifiedWorkspaceArchive as bu, WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION as bv, type WorkspaceArchiveDescriptor as bw, type WorkspaceArchiveIntegrityCode as bx, WorkspaceArchiveIntegrityError as by, type WorkspaceTreeFingerprint as bz, type ActivePointer as c, toolspaceTokenFileFromEnvironment as c$, establishSandboxSessionFromEnvelope as c0, execDeadlineHint as c1, exposeStreamPort as c2, extForCodec as c3, fingerprintSandboxWorkspace as c4, hasPersistableSandboxProviderIdentity as c5, inspectRecordingArtifact as c6, isExecSessionLostBanner as c7, isProviderSandboxGoneDuringRoutedOperation as c8, isProviderSandboxNotFoundError as c9, requirePersistableReplacementSandboxEnvelope as cA, restoredSandboxSessionStateFromEntry as cB, runCredentialPointerFile as cC, runCredentialRoot as cD, runWithToolCallCorrelation as cE, sandboxStateEntryFromRunState as cF, sanitizeOpIdToken as cG, selectBackend as cH, selfhostedFaultClass as cI, selfhostedLiveness as cJ, selfhostedRetryBackoffMs as cK, serializeEstablishedSandboxEnvelope as cL, serializeReplacementSandboxEnvelope as cM, setSelfhostedApplyDiff as cN, startRecording as cO, stopRecording as cP, stripExecBanner as cQ, subjectFor as cR, swapTargetEstablishability as cS, sweepModalOrphanSandboxes as cT, tagModalSandbox as cU, tearDownDisplayStack as cV, tearDownTerminalServer as cW, terminateModalSandboxById as cX, timeoutAgentError as cY, timeoutControlResponse as cZ, toolspaceTokenFileForSession as c_, isProviderSandboxTransientError as ca, isSelfhostedProviderNotFoundError as cb, makeActiveBackendResolver as cc, materializeRunCredentials as cd, mintStreamToken as ce, modalSandboxAttributionEnvironment as cf, modalSandboxAttributionTags as cg, negotiateCapabilities as ch, negotiateSelfhostedCapabilities as ci, nextDurableOpId as cj, normalizeRunCredentialsResolution as ck, offlineAgentError as cl, offlineControlResponse as cm, opAckSubject as cn, opFrameSubject as co, parseExecBannerExitCode as cp, parseExecBannerSessionId as cq, parseNumstatZ as cr, parsePorcelainV2 as cs, parseUnifiedPatch as ct, parseWorkspaceArchiveDescriptor as cu, payloadTooLargeMessage as cv, readVerifiedWorkspaceArchive as cw, readWorkspaceArchiveFromEnvelopeSessionState as cx, recordingStorageKey as cy, renderSelfhostedFault as cz, type ChannelAEmitter as d, uploadRecordingArtifact as d0, verifyRestoredWorkspace as d1, verifySandboxExecReadiness as d2, verifyStreamToken as d3, withRunCredentialEnvironment as d4, withRunCredentialsClient as d5, withRunCredentialsSession as d6, withToolspaceTokenClient as d7, withToolspaceTokenEnvironment as d8, withToolspaceTokenSession as d9, type ChannelAExecArgs as e, type ChannelAExecResult as f, ChannelANotFoundError as g, type ChannelASession as h, ChannelAUnavailableError as i, ChannelAUnsupportedError as j, ChannelAValidationError as k, type ControlRpc as l, DISPLAY_STACK_TIMEOUT_MS as m, type DefaultBackendLossResult as n, type DesktopGeometry as o, type DisplayStackCallerKind as p, type DisplayStackClassification as q, DisplayStackError as r, type DisplayStackTelemetryContext as s, type DisplayStackTelemetryEvent as t, type DisplayStackTelemetryStatus as u, DisplayStackUnsupportedError as v, type EnsureDisplayStackResult as w, type EnsureTerminalServerOptions as x, type EnsureTerminalServerResult as y, type EstablishedSandboxSession as z };