@opengeni/runtime 0.13.0 → 0.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-65UDUFUO.js → chunk-JGUQSAG5.js} +1887 -172
- package/dist/chunk-JGUQSAG5.js.map +1 -0
- package/dist/{chunk-HAN5D27J.js → chunk-QYXOVIUK.js} +24 -4
- package/dist/chunk-QYXOVIUK.js.map +1 -0
- package/dist/{index-DGUrY_yR.d.ts → index-DU-KXVlx.d.ts} +328 -25
- package/dist/index.d.ts +25 -3
- package/dist/index.js +71 -675
- package/dist/index.js.map +1 -1
- package/dist/mcp-network.d.ts +4 -1
- package/dist/mcp-network.js +5 -1
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +39 -1
- package/package.json +3 -3
- package/src/index.ts +31 -9
- package/src/mcp-network.ts +28 -3
- package/src/sandbox/channel-a.ts +92 -46
- package/src/sandbox/exec-banner.ts +15 -0
- package/src/sandbox/index.ts +360 -145
- package/src/sandbox/provider-errors.ts +175 -0
- package/src/sandbox/routing/backend-resolver.ts +15 -0
- package/src/sandbox/routing/routing-session.ts +730 -36
- package/src/sandbox/select.ts +8 -0
- package/src/sandbox/turn-tool-cancellation.ts +366 -92
- package/src/sandbox/workspace-archive.ts +289 -0
- package/dist/chunk-65UDUFUO.js.map +0 -1
- package/dist/chunk-HAN5D27J.js.map +0 -1
|
@@ -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;
|
|
@@ -147,12 +154,23 @@ async function boundedParallelMap(values, concurrency, mapper) {
|
|
|
147
154
|
}
|
|
148
155
|
function guardedMcpFetch(settings, fetchImpl, options = {}) {
|
|
149
156
|
return async (input, init) => {
|
|
150
|
-
const
|
|
151
|
-
fetchImpl,
|
|
157
|
+
const destinationOptions = {
|
|
152
158
|
...options.dnsLookup ? { dnsLookup: options.dnsLookup } : {},
|
|
153
159
|
label: "MCP endpoint",
|
|
154
160
|
requireHttpsOutsideLocalTest: options.requireHttpsOutsideLocalTest ?? true
|
|
155
|
-
}
|
|
161
|
+
};
|
|
162
|
+
let response;
|
|
163
|
+
if (options.pinResolvedDestination === false) {
|
|
164
|
+
await resolvePinnedDestination(input instanceof Request ? input.url : input, settings, {
|
|
165
|
+
...destinationOptions
|
|
166
|
+
});
|
|
167
|
+
response = await fetchImpl(input, { ...init, redirect: "manual" });
|
|
168
|
+
} else {
|
|
169
|
+
response = await pinnedFetch(input, init, settings, {
|
|
170
|
+
fetchImpl,
|
|
171
|
+
...destinationOptions
|
|
172
|
+
});
|
|
173
|
+
}
|
|
156
174
|
return boundMcpResponseBody(response, options.maxResponseBytes ?? MCP_MAX_RESPONSE_BYTES);
|
|
157
175
|
};
|
|
158
176
|
}
|
|
@@ -269,6 +287,7 @@ export {
|
|
|
269
287
|
MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES,
|
|
270
288
|
MCP_MAX_SELECTED_SERVERS,
|
|
271
289
|
MCP_MAX_CONCURRENT_SERVER_OPERATIONS,
|
|
290
|
+
MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS,
|
|
272
291
|
MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES,
|
|
273
292
|
MCP_MAX_AGGREGATE_TOOL_LIST_BYTES,
|
|
274
293
|
MCP_MAX_TOOL_SEARCH_SOURCES,
|
|
@@ -279,6 +298,7 @@ export {
|
|
|
279
298
|
assertMcpPayloadWithinBytes,
|
|
280
299
|
assertMcpToolListWithinBounds,
|
|
281
300
|
assertMcpServerSelectionWithinBounds,
|
|
301
|
+
mcpOuterConnectTimeoutMs,
|
|
282
302
|
McpAggregateToolListBudget,
|
|
283
303
|
boundedParallelMap,
|
|
284
304
|
guardedMcpFetch,
|
|
@@ -289,4 +309,4 @@ export {
|
|
|
289
309
|
isNonPublicMcpAddress,
|
|
290
310
|
undiciFetch
|
|
291
311
|
};
|
|
292
|
-
//# sourceMappingURL=chunk-
|
|
312
|
+
//# sourceMappingURL=chunk-QYXOVIUK.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 pinResolvedDestination?: boolean;\n requireHttpsOutsideLocalTest?: boolean;\n } = {},\n): (input: TInput, init?: RequestInit) => Promise<Response> {\n return async (input: TInput, init?: RequestInit) => {\n const destinationOptions = {\n ...(options.dnsLookup ? { dnsLookup: options.dnsLookup } : {}),\n label: \"MCP endpoint\",\n requireHttpsOutsideLocalTest: options.requireHttpsOutsideLocalTest ?? true,\n };\n let response: Response;\n if (options.pinResolvedDestination === false) {\n await resolvePinnedDestination(input instanceof Request ? input.url : input, settings, {\n ...destinationOptions,\n });\n response = await fetchImpl(input, { ...init, redirect: \"manual\" });\n } else {\n response = await pinnedFetch(input, init, settings, {\n fetchImpl: fetchImpl as FetchLike,\n ...destinationOptions,\n });\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":";AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAEP,SAAS,mBAAmB;AAErB,IAAM,yBAAyB,IAAI,OAAO;AAC1C,IAAM,gCAAgC,OAAO;AAC7C,IAAM,gCAAgC,MAAM;AAC5C,IAAM,0BAA0B,IAAI,OAAO;AAC3C,IAAM,4BAA4B;AAClC,IAAM,4BAA4B,OAAO;AACzC,IAAM,uCAAuC,MAAM;AACnD,IAAM,2BAA2B;AACjC,IAAM,uCAAuC;AAI7C,IAAM,uCAAuC;AAC7C,IAAM,sCAAsC;AAC5C,IAAM,oCAAoC,KAAK,OAAO;AACtD,IAAM,8BAA8B;AACpC,IAAM,0CAA0C;AAChD,IAAM,wCAAwC,KAAK;AAEnD,IAAM,0BAAN,cAAsC,MAAM;AAAA,EACjD,YACW,OACA,aACA,UACT;AACA,UAAM,GAAG,KAAK,gBAAgB,QAAQ,oBAAoB;AAJjD;AACA;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,uBAAuB,OAAwB;AAC7D,MAAI;AACJ,MAAI;AACF,iBAAa,KAAK,UAAU,KAAK,KAAK;AAAA,EACxC,QAAQ;AACN,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,SAAO,OAAO,WAAW,UAAU;AACrC;AAEO,SAAS,4BAA4B,OAAgB,UAAkB,OAAqB;AACjG,QAAM,cAAc,uBAAuB,KAAK;AAChD,MAAI,cAAc,UAAU;AAC1B,UAAM,IAAI,wBAAwB,OAAO,aAAa,QAAQ;AAAA,EAChE;AACF;AAEO,SAAS,8BAAiC,OAAmC;AAClF,MAAI,MAAM,SAAS,2BAA2B;AAC5C,UAAM,IAAI,wBAAwB,iBAAiB,MAAM,QAAQ,yBAAyB;AAAA,EAC5F;AACA,aAAW,QAAQ,OAAO;AACxB,UAAM,YAAY,uBAAuB,IAAI;AAC7C,QAAI,YAAY,+BAA+B;AAC7C,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAIA,QAAM,aAAa,uBAAuB,KAAK;AAC/C,MAAI,aAAa,yBAAyB;AACxC,UAAM,IAAI,wBAAwB,iBAAiB,YAAY,uBAAuB;AAAA,EACxF;AACA,SAAO;AACT;AAEO,SAAS,qCAAwC,SAAqC;AAC3F,MAAI,QAAQ,SAAS,0BAA0B;AAC7C,UAAM,IAAI;AAAA,MACR;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,yBACd,oBACQ;AACR,SAAO,KAAK;AAAA,IACV;AAAA,IACA,GAAG,mBAAmB,QAAQ,CAAC,cAAe,cAAc,SAAY,CAAC,IAAI,CAAC,SAAS,CAAE;AAAA,EAC3F;AACF;AAaO,IAAM,6BAAN,MAAiC;AAAA,EAKtC,YACmB,QAAQ,2BACR,aAAa,qCACb,WAAW,mCAC5B;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EARc,gBAAgB,oBAAI,IAAqC;AAAA,EAClE,eAAe;AAAA,EACf,aAAa;AAAA,EAQrB,QAAW,UAAkB,OAAmC;AAC9D,kCAA8B,KAAK;AACnC,UAAM,eAAe;AAAA,MACnB,SAAS,MAAM;AAAA;AAAA;AAAA;AAAA,MAIf,OAAO,uBAAuB,KAAK;AAAA,IACrC;AACA,UAAM,WAAW,KAAK,cAAc,IAAI,QAAQ,KAAK,EAAE,SAAS,GAAG,OAAO,EAAE;AAC5E,UAAM,cAAc,KAAK,eAAe,SAAS,UAAU,aAAa;AACxE,QAAI,cAAc,KAAK,YAAY;AACjC,YAAM,IAAI,wBAAwB,KAAK,OAAO,aAAa,KAAK,UAAU;AAAA,IAC5E;AACA,UAAM,YAAY,KAAK,aAAa,SAAS,QAAQ,aAAa;AAClE,QAAI,YAAY,KAAK,UAAU;AAC7B,YAAM,IAAI,wBAAwB,KAAK,OAAO,WAAW,KAAK,QAAQ;AAAA,IACxE;AACA,SAAK,cAAc,IAAI,UAAU,YAAY;AAC7C,SAAK,eAAe;AACpB,SAAK,aAAa;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,UAAwB;AAC7B,UAAM,WAAW,KAAK,cAAc,IAAI,QAAQ;AAChD,QAAI,CAAC,SAAU;AACf,SAAK,cAAc,OAAO,QAAQ;AAClC,SAAK,gBAAgB,SAAS;AAC9B,SAAK,cAAc,SAAS;AAAA,EAC9B;AAAA,EAEA,WAA8C;AAC5C,WAAO,EAAE,SAAS,KAAK,cAAc,OAAO,KAAK,WAAW;AAAA,EAC9D;AACF;AAGA,eAAsB,mBACpB,QACA,aACA,QACc;AACd,MAAI,CAAC,OAAO,UAAU,WAAW,KAAK,cAAc,GAAG;AACrD,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AAEjC,QAAM,UAAU,IAAI,MAAS,OAAO,MAAM;AAC1C,QAAM,SAAmD,CAAC;AAC1D,MAAI,YAAY;AAChB,MAAI,UAAU;AACd,QAAM,SAAS,YAAY;AACzB,WAAO,CAAC,SAAS;AACf,YAAM,QAAQ;AACd,UAAI,SAAS,OAAO,OAAQ;AAC5B,mBAAa;AACb,UAAI;AACF,gBAAQ,KAAK,IAAI,MAAM,OAAO,OAAO,KAAK,GAAI,KAAK;AAAA,MACrD,SAAS,OAAO;AACd,eAAO,KAAK,EAAE,OAAO,MAAM,CAAC;AAC5B,kBAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AACA,QAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,aAAa,OAAO,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC;AAC9F,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO,KAAK,CAAC,MAAM,UAAU,KAAK,QAAQ,MAAM,KAAK;AACrD,UAAM,OAAO,CAAC,EAAG;AAAA,EACnB;AACA,SAAO;AACT;AAaO,SAAS,gBACd,UACA,WACA,UAKI,CAAC,GACqD;AAC1D,SAAO,OAAO,OAAe,SAAuB;AAClD,UAAM,qBAAqB;AAAA,MACzB,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC5D,OAAO;AAAA,MACP,8BAA8B,QAAQ,gCAAgC;AAAA,IACxE;AACA,QAAI;AACJ,QAAI,QAAQ,2BAA2B,OAAO;AAC5C,YAAM,yBAAyB,iBAAiB,UAAU,MAAM,MAAM,OAAO,UAAU;AAAA,QACrF,GAAG;AAAA,MACL,CAAC;AACD,iBAAW,MAAM,UAAU,OAAO,EAAE,GAAG,MAAM,UAAU,SAAS,CAAC;AAAA,IACnE,OAAO;AACL,iBAAW,MAAM,YAAY,OAAO,MAAM,UAAU;AAAA,QAClD;AAAA,QACA,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AACA,WAAO,qBAAqB,UAAU,QAAQ,oBAAoB,sBAAsB;AAAA,EAC1F;AACF;AAEO,SAAS,qBAAqB,UAAoB,UAA4B;AACnF,QAAM,iBAAiB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC;AACpE,MAAI,OAAO,SAAS,cAAc,KAAK,iBAAiB,UAAU;AAChE,SAAK,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AAClD,UAAM,IAAI,wBAAwB,gBAAgB,gBAAgB,QAAQ;AAAA,EAC5E;AACA,MAAI,CAAC,SAAS,MAAM;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,SAAS,KAAK,UAAU;AACvC,MAAI,gBAAgB;AACpB,QAAM,OAAO,IAAI,eAA2B;AAAA,IAC1C,MAAM,KAAK,YAAY;AACrB,UAAI;AACF,cAAM,QAAQ,MAAM,OAAO,KAAK;AAChC,YAAI,MAAM,MAAM;AACd,qBAAW,MAAM;AACjB;AAAA,QACF;AACA,yBAAiB,MAAM,MAAM;AAC7B,YAAI,gBAAgB,UAAU;AAC5B,gBAAM,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3C,qBAAW,MAAM,IAAI,wBAAwB,gBAAgB,eAAe,QAAQ,CAAC;AACrF;AAAA,QACF;AACA,mBAAW,QAAQ,MAAM,KAAK;AAAA,MAChC,SAAS,OAAO;AACd,mBAAW,MAAM,KAAK;AAAA,MACxB;AAAA,IACF;AAAA,IACA,MAAM,OAAO,QAAQ;AACnB,YAAM,OAAO,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,IACnD;AAAA,EACF,CAAC;AACD,QAAM,UAAU,IAAI,SAAS,MAAM;AAAA,IACjC,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,IACrB,SAAS,SAAS;AAAA,EACpB,CAAC;AACD,SAAO,iBAAiB,SAAS;AAAA,IAC/B,YAAY,EAAE,OAAO,SAAS,WAAW;AAAA,IACzC,MAAM,EAAE,OAAO,SAAS,KAAK;AAAA,IAC7B,KAAK,EAAE,OAAO,SAAS,IAAI;AAAA,EAC7B,CAAC;AACD,SAAO;AACT;AAEA,eAAsB,sBAAsB,UAAmC;AAC7E,QAAM,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AACrD;AAGA,eAAsB,kBACpB,SACA,WAAW,+BACO;AAClB,QAAM,WAAW,QAAQ,QAAQ,IAAI,gBAAgB;AACrD,MAAI,aAAa,MAAM;AACrB,UAAM,aAAa,SAAS,KAAK;AACjC,QAAI,CAAC,QAAQ,KAAK,UAAU,GAAG;AAC7B,YAAM,QAAQ,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AAClD,YAAM,IAAI,wBAAwB,eAAe,GAAG,QAAQ;AAAA,IAC9D;AACA,UAAM,gBAAgB,OAAO,UAAU;AACvC,QAAI,CAAC,OAAO,cAAc,aAAa,KAAK,gBAAgB,UAAU;AACpE,YAAM,QAAQ,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AAClD,YAAM,IAAI,wBAAwB,eAAe,eAAe,QAAQ;AAAA,IAC1E;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,MAAM;AACjB,WAAO;AAAA,EACT;AACA,QAAM,SAAS,QAAQ,KAAK,UAAU;AACtC,QAAM,SAAuB,CAAC;AAC9B,MAAI,gBAAgB;AACpB,MAAI;AACF,eAAS;AACP,YAAM,SAAS,MAAM,OAAO,KAAK;AACjC,UAAI,OAAO,KAAM;AACjB,uBAAiB,OAAO,MAAM;AAC9B,UAAI,gBAAgB,UAAU;AAC5B,cAAM,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3C,cAAM,IAAI,wBAAwB,eAAe,eAAe,QAAQ;AAAA,MAC1E;AACA,aAAO,KAAK,OAAO,KAAK;AAAA,IAC1B;AAAA,EACF,SAAS,OAAO;AACd,UAAM,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3C,UAAM;AAAA,EACR,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACA,QAAM,OAAO,IAAI,WAAW,aAAa;AACzC,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,SAAK,IAAI,OAAO,MAAM;AACtB,cAAU,MAAM;AAAA,EAClB;AACA,SAAO,IAAI,QAAQ,SAAS,EAAE,MAAM,SAAS,QAAQ,QAAQ,CAAC;AAChE;AAEA,eAAsB,4BACpB,QACA,UACA,UAAqC,CAAC,GACvB;AACf,QAAM,yBAAyB,QAAQ,UAAU;AAAA,IAC/C,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC5D,OAAO;AAAA,IACP,8BAA8B;AAAA,EAChC,CAAC;AACH;AAEO,IAAM,wBAAwB;","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
|
|
858
|
-
*
|
|
859
|
-
*
|
|
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
|
-
/**
|
|
881
|
-
*
|
|
882
|
-
|
|
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
|
|
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 };
|