@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.
- package/dist/{chunk-65UDUFUO.js → chunk-JGUQSAG5.js} +1887 -172
- package/dist/chunk-JGUQSAG5.js.map +1 -0
- package/dist/{chunk-HAN5D27J.js → chunk-SSB7VOLE.js} +10 -1
- package/dist/chunk-SSB7VOLE.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 +65 -673
- package/dist/index.js.map +1 -1
- package/dist/mcp-network.d.ts +3 -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 +20 -7
- package/src/mcp-network.ts +13 -0
- 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
package/dist/mcp-network.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ declare const MCP_MAX_TOOL_RESULT_BYTES: number;
|
|
|
11
11
|
declare const MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES: number;
|
|
12
12
|
declare const MCP_MAX_SELECTED_SERVERS = 64;
|
|
13
13
|
declare const MCP_MAX_CONCURRENT_SERVER_OPERATIONS = 8;
|
|
14
|
+
declare const MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS = 10000;
|
|
14
15
|
declare const MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = 4096;
|
|
15
16
|
declare const MCP_MAX_AGGREGATE_TOOL_LIST_BYTES: number;
|
|
16
17
|
declare const MCP_MAX_TOOL_SEARCH_SOURCES = 64;
|
|
@@ -26,6 +27,7 @@ declare function mcpSerializedSizeBytes(value: unknown): number;
|
|
|
26
27
|
declare function assertMcpPayloadWithinBytes(value: unknown, maxBytes: number, label: string): void;
|
|
27
28
|
declare function assertMcpToolListWithinBounds<T>(tools: readonly T[]): readonly T[];
|
|
28
29
|
declare function assertMcpServerSelectionWithinBounds<T>(servers: readonly T[]): readonly T[];
|
|
30
|
+
declare function mcpOuterConnectTimeoutMs(configuredTimeouts: readonly (number | undefined)[]): number;
|
|
29
31
|
type McpToolListContribution = {
|
|
30
32
|
entries: number;
|
|
31
33
|
bytes: number;
|
|
@@ -75,4 +77,4 @@ declare function assertMcpDestinationAllowed(rawUrl: string, settings: Pick<Sett
|
|
|
75
77
|
}): Promise<void>;
|
|
76
78
|
declare const isNonPublicMcpAddress: typeof isNonPublicAddress;
|
|
77
79
|
|
|
78
|
-
export { MCP_MAX_AGGREGATE_TOOL_LIST_BYTES, MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES, MCP_MAX_CONCURRENT_SERVER_OPERATIONS, MCP_MAX_INBOUND_REQUEST_BYTES, MCP_MAX_RESPONSE_BYTES, MCP_MAX_SELECTED_SERVERS, MCP_MAX_TOOL_DEFINITION_BYTES, MCP_MAX_TOOL_LIST_BYTES, MCP_MAX_TOOL_LIST_ENTRIES, MCP_MAX_TOOL_RESULT_BYTES, MCP_MAX_TOOL_SEARCH_DESCRIPTION_BYTES, MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES, MCP_MAX_TOOL_SEARCH_SOURCES, MCP_MAX_TOOL_SEARCH_SOURCE_LABEL_LENGTH, McpAggregateToolListBudget, McpPayloadTooLargeError, assertMcpDestinationAllowed, assertMcpPayloadWithinBytes, assertMcpServerSelectionWithinBounds, assertMcpToolListWithinBounds, boundMcpResponseBody, boundedMcpRequest, boundedParallelMap, cancelMcpResponseBody, guardedMcpFetch, isNonPublicMcpAddress, mcpSerializedSizeBytes };
|
|
80
|
+
export { MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS, MCP_MAX_AGGREGATE_TOOL_LIST_BYTES, MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES, MCP_MAX_CONCURRENT_SERVER_OPERATIONS, MCP_MAX_INBOUND_REQUEST_BYTES, MCP_MAX_RESPONSE_BYTES, MCP_MAX_SELECTED_SERVERS, MCP_MAX_TOOL_DEFINITION_BYTES, MCP_MAX_TOOL_LIST_BYTES, MCP_MAX_TOOL_LIST_ENTRIES, MCP_MAX_TOOL_RESULT_BYTES, MCP_MAX_TOOL_SEARCH_DESCRIPTION_BYTES, MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES, MCP_MAX_TOOL_SEARCH_SOURCES, MCP_MAX_TOOL_SEARCH_SOURCE_LABEL_LENGTH, McpAggregateToolListBudget, McpPayloadTooLargeError, assertMcpDestinationAllowed, assertMcpPayloadWithinBytes, assertMcpServerSelectionWithinBounds, assertMcpToolListWithinBounds, boundMcpResponseBody, boundedMcpRequest, boundedParallelMap, cancelMcpResponseBody, guardedMcpFetch, isNonPublicMcpAddress, mcpOuterConnectTimeoutMs, mcpSerializedSizeBytes };
|
package/dist/mcp-network.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS,
|
|
2
3
|
MCP_MAX_AGGREGATE_TOOL_LIST_BYTES,
|
|
3
4
|
MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES,
|
|
4
5
|
MCP_MAX_CONCURRENT_SERVER_OPERATIONS,
|
|
@@ -25,11 +26,13 @@ import {
|
|
|
25
26
|
cancelMcpResponseBody,
|
|
26
27
|
guardedMcpFetch,
|
|
27
28
|
isNonPublicMcpAddress,
|
|
29
|
+
mcpOuterConnectTimeoutMs,
|
|
28
30
|
mcpSerializedSizeBytes,
|
|
29
31
|
undiciFetch
|
|
30
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-SSB7VOLE.js";
|
|
31
33
|
import "./chunk-PZ5AY32C.js";
|
|
32
34
|
export {
|
|
35
|
+
MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS,
|
|
33
36
|
MCP_MAX_AGGREGATE_TOOL_LIST_BYTES,
|
|
34
37
|
MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES,
|
|
35
38
|
MCP_MAX_CONCURRENT_SERVER_OPERATIONS,
|
|
@@ -56,6 +59,7 @@ export {
|
|
|
56
59
|
cancelMcpResponseBody,
|
|
57
60
|
guardedMcpFetch,
|
|
58
61
|
isNonPublicMcpAddress,
|
|
62
|
+
mcpOuterConnectTimeoutMs,
|
|
59
63
|
mcpSerializedSizeBytes,
|
|
60
64
|
undiciFetch
|
|
61
65
|
};
|
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { collectSandboxEnvironment, parseExposedPorts } from '@opengeni/config';
|
|
2
2
|
export { CAPABILITY_DESCRIPTORS, CapabilityDescriptor, DESKTOP_STREAM_PORT, StreamTokenPayload, StreamTokenPayload as StreamTokenPayloadType, TERMINAL_STREAM_PORT } from '@opengeni/contracts';
|
|
3
3
|
import '@openai/agents/sandbox';
|
|
4
|
-
export { A as ActiveBackendResolverDeps, b as ActiveBackendUnresolvableError, c as ActivePointer, B as BackendUnresolvableCode, C as ChannelAConflictError, d as ChannelAEmitter, e as ChannelAExecArgs, f as ChannelAExecResult, g as ChannelANotFoundError, h as ChannelASession, i as ChannelAUnavailableError, j as ChannelAUnsupportedError, k as ChannelAValidationError, l as ControlRpc, D as DEFAULT_DESKTOP_GEOMETRY, m as DISPLAY_STACK_TIMEOUT_MS, n as
|
|
4
|
+
export { A as ActiveBackendResolverDeps, b as ActiveBackendUnresolvableError, c as ActivePointer, B as BackendUnresolvableCode, C as ChannelAConflictError, d as ChannelAEmitter, e as ChannelAExecArgs, f as ChannelAExecResult, g as ChannelANotFoundError, h as ChannelASession, i as ChannelAUnavailableError, j as ChannelAUnsupportedError, k as ChannelAValidationError, l as ControlRpc, D as DEFAULT_DESKTOP_GEOMETRY, m as DISPLAY_STACK_TIMEOUT_MS, n as DefaultBackendLossResult, o as DesktopGeometry, p as DisplayStackCallerKind, q as DisplayStackClassification, r as DisplayStackError, s as DisplayStackTelemetryContext, t as DisplayStackTelemetryEvent, u as DisplayStackTelemetryStatus, v as DisplayStackUnsupportedError, E as EnsureDisplayStackOptions, w as EnsureDisplayStackResult, x as EnsureTerminalServerOptions, y as EnsureTerminalServerResult, z as EstablishedSandboxSession, F as ExposeStreamPortInput, G as ExposeStreamPortResult, H as ExposedPortEndpoint, I as FAULT_FIELD_WHAT_HAPPENED, J as FAULT_FIELD_WHAT_PRESERVED, K as FAULT_FIELD_WHAT_TO_TRY, L as FAULT_FIELD_WHICH_LAYER, M as LiveModalSandboxLeaseAttribution, N as MaterializeRunCredentialsOptions, O as MintStreamTokenInput, P as MockAgentResponder, Q as MockAgentResponderOptions, S as MockExecHandler, T as ModalModuleLoader, U as ModalOrphanSweepResult, V as ModalOrphanSweepTermination, W as ModalSandboxAttribution, X as NEVER_SENT_DETAIL_KEY, Y as NatsControlRpc, Z as NatsOpStreamConnection, _ as NatsOpStreamTransport, $ as NatsRequestConnection, a0 as NegotiationContext, a1 as NormalizedRunCredentialMaterial, a2 as NumstatEntry, a3 as OP_STREAM_ACK_INTERVAL_MS, a4 as OP_STREAM_DEFAULT_WINDOW_BYTES, a5 as OP_STREAM_RECONNECT_HOLD_MS, a6 as OP_STREAM_SILENCE_TIMEOUT_MS, a7 as OpStreamExecOutcome, a8 as OpStreamJournal, a9 as OpStreamSubscription, aa as OpStreamTransport, ab as OpStreamUnavailableError, ac as PROVIDER_REGISTRY, ad as ProviderConstructionContext, ae as ProviderRegistration, af as ProviderSandboxFailure, ag as ProviderSandboxFailureKind, ah as REPOSITORY_DISCOVERY_LIMIT, ai as RecordingArtifactMetadata, aj as RecordingCodec, ak as RecordingContentType, al as RecordingError, am as RecordingProcess, an as RecordingUnavailableError, ao as RepositoryDiscoveryDegradedReason, ap as RepositoryDiscoveryResult, aq as ResolvedActiveBackend, ar as RevalidateModalOrphanTermination, as as RoutableBackendSession, at as RoutableSandbox, au as RoutingBackendRecoveryRequiredError, av as RoutingMutationOutcomeUnknownError, aw as RoutingRetainedProcess, ax as RoutingRetainedProcessAdoption, ay as RoutingRetainedProcessNotFoundError, az as RoutingRetainedProcessTerminalProof, aA as RoutingSandboxSession, aB as RoutingSandboxSessionDeps, aC as RoutingTransitionEvent, aD as RoutingUnsupportedError, aE as RunCredentialCommandRunner, aF as RunCredentialCommandSession, aG as RunCredentialExpectedScope, R as RunCredentialSessionReady, aH as RunCredentialValidationError, aI as SELFHOSTED_DEFAULT_TIMEOUT_MS, aJ as SELFHOSTED_DRAINING_MAX_RETRIES, aK as SELFHOSTED_EXEC_DRAINING_MAX_RETRIES, aL as SELFHOSTED_IDEMPOTENT_READONLY_OPS, aM as SELFHOSTED_INFRASTRUCTURE_FAULT_CLASSES, aN as SELFHOSTED_NEVER_SENT_MAX_RETRIES, aO as SELFHOSTED_RECONNECT_WINDOW_MS, aP as SELFHOSTED_RELAY_STREAM_PATH, aQ as SELFHOSTED_RETRY_BACKOFF_BASE_MS, aR as SELFHOSTED_RETRY_BACKOFF_CAP_MS, aS as SELFHOSTED_RETRY_BACKOFF_FACTOR, aT as SELFHOSTED_TIMEOUT_MAX_RETRIES, aU as STREAM_PORT, aV as STREAM_TOKEN_DEFAULT_TTL_SECONDS, aW as SandboxChannelAService, aX as SandboxChannelAServiceOptions, aY as SandboxConfigError, aZ as SandboxCreatedCallback, a_ as SandboxExecReadinessError, a$ as SandboxProviderUnavailableError, b0 as SandboxReplacementProviderStateError, b1 as SandboxResumeStateUnavailableError, b2 as SelfhostedApplyDiff, b3 as SelfhostedControlError, b4 as SelfhostedEditor, b5 as SelfhostedEnrollment, b6 as SelfhostedExecArgs, b7 as SelfhostedExecResult, b8 as SelfhostedImageOutput, b9 as SelfhostedLivenessState, ba as SelfhostedNegotiationInput, bb as SelfhostedOpObservation, bc as SelfhostedOpObserver, bd as SelfhostedOpStreamDeps, be as SelfhostedRelayConfig, bf as SelfhostedRetryClock, bg as SelfhostedRetryDecision, bh as SelfhostedSandboxClient, bi as SelfhostedSession, bj as SelfhostedSessionBuild, bk as SelfhostedSessionDeps, bl as SelfhostedSessionState, bm as SelfhostedUnavailableReason, bn as StartRecordingInput, bo as StreamPortUnavailableError, bp as SwapTargetEstablishability, bq as TERMINAL_SERVER_TIMEOUT_MS, br as TerminalServerError, bs as TerminalServerUnsupportedError, bt as ToolspaceTokenPathError, bu as VerifiedWorkspaceArchive, bv as WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION, bw as WorkspaceArchiveDescriptor, bx as WorkspaceArchiveIntegrityCode, by as WorkspaceArchiveIntegrityError, bz as WorkspaceTreeFingerprint, bA as agentErrorToControlError, bB as assertDescriptorRegistryInvariants, bC as assertProviderRegistryInvariants, bD as assertSafeRelPath, bE as backendSupportsOs, bF as buildDisplayStackScript, bG as buildSelfhostedBackendSession, bH as buildStreamUrl, bI as buildTerminalServerScript, bJ as captureVerifiedWorkspaceArchive, bK as classifyProviderSandboxFailure, bL as clearRunCredentials, bM as clearRunCredentialsForAttempt, bN as contentTypeForCodec, bO as createSandboxClient, bP as createSandboxClientForBackend, bQ as decideSelfhostedRetry, bR as decodeModalSnapshotId, bS as defaultSelfhostedRetryClock, bT as deletePriorPersistedSnapshot, bU as deleteRecordingArtifacts, bV as deserializeSandboxSessionStateEnvelope, bW as desktopCapableBackend, bX as drainingExhaustedError, bY as drainingMessage, bZ as ensureDisplayStack, b_ as ensureModalRegistryImage, b$ as ensureTerminalServer, c0 as establishSandboxSessionFromEnvelope, c1 as execDeadlineHint, c2 as exposeStreamPort, c3 as extForCodec, c4 as fingerprintSandboxWorkspace, c5 as hasPersistableSandboxProviderIdentity, c6 as inspectRecordingArtifact, c7 as isExecSessionLostBanner, c8 as isProviderSandboxGoneDuringRoutedOperation, c9 as isProviderSandboxNotFoundError, ca as isProviderSandboxTransientError, cb as isSelfhostedProviderNotFoundError, cc as makeActiveBackendResolver, cd as materializeRunCredentials, ce as mintStreamToken, cf as modalSandboxAttributionEnvironment, cg as modalSandboxAttributionTags, ch as negotiateCapabilities, ci as negotiateSelfhostedCapabilities, cj as nextDurableOpId, ck as normalizeRunCredentialsResolution, cl as offlineAgentError, cm as offlineControlResponse, cn as opAckSubject, co as opFrameSubject, cp as parseExecBannerExitCode, cq as parseExecBannerSessionId, cr as parseNumstatZ, cs as parsePorcelainV2, ct as parseUnifiedPatch, cu as parseWorkspaceArchiveDescriptor, cv as payloadTooLargeMessage, cw as readVerifiedWorkspaceArchive, cx as readWorkspaceArchiveFromEnvelopeSessionState, cy as recordingStorageKey, cz as renderSelfhostedFault, cA as requirePersistableReplacementSandboxEnvelope, cB as restoredSandboxSessionStateFromEntry, cC as runCredentialPointerFile, cD as runCredentialRoot, cE as runWithToolCallCorrelation, cF as sandboxStateEntryFromRunState, cG as sanitizeOpIdToken, cH as selectBackend, cI as selfhostedFaultClass, cJ as selfhostedLiveness, cK as selfhostedRetryBackoffMs, cL as serializeEstablishedSandboxEnvelope, cM as serializeReplacementSandboxEnvelope, cN as setSelfhostedApplyDiff, cO as startRecording, cP as stopRecording, cQ as stripExecBanner, cR as subjectFor, cS as swapTargetEstablishability, cT as sweepModalOrphanSandboxes, cU as tagModalSandbox, cV as tearDownDisplayStack, cW as tearDownTerminalServer, cX as terminateModalSandboxById, cY as timeoutAgentError, cZ as timeoutControlResponse, c_ as toolspaceTokenFileForSession, c$ as toolspaceTokenFileFromEnvironment, d0 as uploadRecordingArtifact, d1 as verifyRestoredWorkspace, d2 as verifySandboxExecReadiness, d3 as verifyStreamToken, d4 as withRunCredentialEnvironment, d5 as withRunCredentialsClient, d6 as withRunCredentialsSession, d7 as withToolspaceTokenClient, d8 as withToolspaceTokenEnvironment, d9 as withToolspaceTokenSession } from '../index-DU-KXVlx.js';
|
|
5
5
|
import 'modal';
|
|
6
6
|
import '@opengeni/agent-proto';
|
package/dist/sandbox/index.js
CHANGED
|
@@ -28,6 +28,9 @@ import {
|
|
|
28
28
|
REPOSITORY_DISCOVERY_LIMIT,
|
|
29
29
|
RecordingError,
|
|
30
30
|
RecordingUnavailableError,
|
|
31
|
+
RoutingBackendRecoveryRequiredError,
|
|
32
|
+
RoutingMutationOutcomeUnknownError,
|
|
33
|
+
RoutingRetainedProcessNotFoundError,
|
|
31
34
|
RoutingSandboxSession,
|
|
32
35
|
RoutingUnsupportedError,
|
|
33
36
|
RunCredentialValidationError,
|
|
@@ -47,7 +50,9 @@ import {
|
|
|
47
50
|
STREAM_TOKEN_DEFAULT_TTL_SECONDS,
|
|
48
51
|
SandboxChannelAService,
|
|
49
52
|
SandboxConfigError,
|
|
53
|
+
SandboxExecReadinessError,
|
|
50
54
|
SandboxProviderUnavailableError,
|
|
55
|
+
SandboxReplacementProviderStateError,
|
|
51
56
|
SandboxResumeStateUnavailableError,
|
|
52
57
|
SelfhostedControlError,
|
|
53
58
|
SelfhostedSandboxClient,
|
|
@@ -59,6 +64,8 @@ import {
|
|
|
59
64
|
TerminalServerError,
|
|
60
65
|
TerminalServerUnsupportedError,
|
|
61
66
|
ToolspaceTokenPathError,
|
|
67
|
+
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
68
|
+
WorkspaceArchiveIntegrityError,
|
|
62
69
|
agentErrorToControlError,
|
|
63
70
|
assertDescriptorRegistryInvariants,
|
|
64
71
|
assertProviderRegistryInvariants,
|
|
@@ -68,6 +75,8 @@ import {
|
|
|
68
75
|
buildSelfhostedBackendSession,
|
|
69
76
|
buildStreamUrl,
|
|
70
77
|
buildTerminalServerScript,
|
|
78
|
+
captureVerifiedWorkspaceArchive,
|
|
79
|
+
classifyProviderSandboxFailure,
|
|
71
80
|
clearRunCredentials,
|
|
72
81
|
clearRunCredentialsForAttempt,
|
|
73
82
|
collectSandboxEnvironment,
|
|
@@ -90,9 +99,13 @@ import {
|
|
|
90
99
|
execDeadlineHint,
|
|
91
100
|
exposeStreamPort,
|
|
92
101
|
extForCodec,
|
|
102
|
+
fingerprintSandboxWorkspace,
|
|
103
|
+
hasPersistableSandboxProviderIdentity,
|
|
93
104
|
inspectRecordingArtifact,
|
|
94
105
|
isExecSessionLostBanner,
|
|
106
|
+
isProviderSandboxGoneDuringRoutedOperation,
|
|
95
107
|
isProviderSandboxNotFoundError,
|
|
108
|
+
isProviderSandboxTransientError,
|
|
96
109
|
isSelfhostedProviderNotFoundError,
|
|
97
110
|
makeActiveBackendResolver,
|
|
98
111
|
materializeRunCredentials,
|
|
@@ -113,10 +126,13 @@ import {
|
|
|
113
126
|
parseNumstatZ,
|
|
114
127
|
parsePorcelainV2,
|
|
115
128
|
parseUnifiedPatch,
|
|
129
|
+
parseWorkspaceArchiveDescriptor,
|
|
116
130
|
payloadTooLargeMessage,
|
|
131
|
+
readVerifiedWorkspaceArchive,
|
|
117
132
|
readWorkspaceArchiveFromEnvelopeSessionState,
|
|
118
133
|
recordingStorageKey,
|
|
119
134
|
renderSelfhostedFault,
|
|
135
|
+
requirePersistableReplacementSandboxEnvelope,
|
|
120
136
|
restoredSandboxSessionStateFromEntry,
|
|
121
137
|
runCredentialPointerFile,
|
|
122
138
|
runCredentialRoot,
|
|
@@ -128,6 +144,7 @@ import {
|
|
|
128
144
|
selfhostedLiveness,
|
|
129
145
|
selfhostedRetryBackoffMs,
|
|
130
146
|
serializeEstablishedSandboxEnvelope,
|
|
147
|
+
serializeReplacementSandboxEnvelope,
|
|
131
148
|
setSelfhostedApplyDiff,
|
|
132
149
|
startRecording,
|
|
133
150
|
stopRecording,
|
|
@@ -144,6 +161,8 @@ import {
|
|
|
144
161
|
toolspaceTokenFileForSession,
|
|
145
162
|
toolspaceTokenFileFromEnvironment,
|
|
146
163
|
uploadRecordingArtifact,
|
|
164
|
+
verifyRestoredWorkspace,
|
|
165
|
+
verifySandboxExecReadiness,
|
|
147
166
|
verifyStreamToken,
|
|
148
167
|
withRunCredentialEnvironment,
|
|
149
168
|
withRunCredentialsClient,
|
|
@@ -151,7 +170,7 @@ import {
|
|
|
151
170
|
withToolspaceTokenClient,
|
|
152
171
|
withToolspaceTokenEnvironment,
|
|
153
172
|
withToolspaceTokenSession
|
|
154
|
-
} from "../chunk-
|
|
173
|
+
} from "../chunk-JGUQSAG5.js";
|
|
155
174
|
import "../chunk-4YJ5Z52Z.js";
|
|
156
175
|
import "../chunk-K4V4QYCL.js";
|
|
157
176
|
import "../chunk-PZ5AY32C.js";
|
|
@@ -185,6 +204,9 @@ export {
|
|
|
185
204
|
REPOSITORY_DISCOVERY_LIMIT,
|
|
186
205
|
RecordingError,
|
|
187
206
|
RecordingUnavailableError,
|
|
207
|
+
RoutingBackendRecoveryRequiredError,
|
|
208
|
+
RoutingMutationOutcomeUnknownError,
|
|
209
|
+
RoutingRetainedProcessNotFoundError,
|
|
188
210
|
RoutingSandboxSession,
|
|
189
211
|
RoutingUnsupportedError,
|
|
190
212
|
RunCredentialValidationError,
|
|
@@ -204,7 +226,9 @@ export {
|
|
|
204
226
|
STREAM_TOKEN_DEFAULT_TTL_SECONDS,
|
|
205
227
|
SandboxChannelAService,
|
|
206
228
|
SandboxConfigError,
|
|
229
|
+
SandboxExecReadinessError,
|
|
207
230
|
SandboxProviderUnavailableError,
|
|
231
|
+
SandboxReplacementProviderStateError,
|
|
208
232
|
SandboxResumeStateUnavailableError,
|
|
209
233
|
SelfhostedControlError,
|
|
210
234
|
SelfhostedSandboxClient,
|
|
@@ -216,6 +240,8 @@ export {
|
|
|
216
240
|
TerminalServerError,
|
|
217
241
|
TerminalServerUnsupportedError,
|
|
218
242
|
ToolspaceTokenPathError,
|
|
243
|
+
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
244
|
+
WorkspaceArchiveIntegrityError,
|
|
219
245
|
agentErrorToControlError,
|
|
220
246
|
assertDescriptorRegistryInvariants,
|
|
221
247
|
assertProviderRegistryInvariants,
|
|
@@ -225,6 +251,8 @@ export {
|
|
|
225
251
|
buildSelfhostedBackendSession,
|
|
226
252
|
buildStreamUrl,
|
|
227
253
|
buildTerminalServerScript,
|
|
254
|
+
captureVerifiedWorkspaceArchive,
|
|
255
|
+
classifyProviderSandboxFailure,
|
|
228
256
|
clearRunCredentials,
|
|
229
257
|
clearRunCredentialsForAttempt,
|
|
230
258
|
collectSandboxEnvironment,
|
|
@@ -247,9 +275,13 @@ export {
|
|
|
247
275
|
execDeadlineHint,
|
|
248
276
|
exposeStreamPort,
|
|
249
277
|
extForCodec,
|
|
278
|
+
fingerprintSandboxWorkspace,
|
|
279
|
+
hasPersistableSandboxProviderIdentity,
|
|
250
280
|
inspectRecordingArtifact,
|
|
251
281
|
isExecSessionLostBanner,
|
|
282
|
+
isProviderSandboxGoneDuringRoutedOperation,
|
|
252
283
|
isProviderSandboxNotFoundError,
|
|
284
|
+
isProviderSandboxTransientError,
|
|
253
285
|
isSelfhostedProviderNotFoundError,
|
|
254
286
|
makeActiveBackendResolver,
|
|
255
287
|
materializeRunCredentials,
|
|
@@ -270,10 +302,13 @@ export {
|
|
|
270
302
|
parseNumstatZ,
|
|
271
303
|
parsePorcelainV2,
|
|
272
304
|
parseUnifiedPatch,
|
|
305
|
+
parseWorkspaceArchiveDescriptor,
|
|
273
306
|
payloadTooLargeMessage,
|
|
307
|
+
readVerifiedWorkspaceArchive,
|
|
274
308
|
readWorkspaceArchiveFromEnvelopeSessionState,
|
|
275
309
|
recordingStorageKey,
|
|
276
310
|
renderSelfhostedFault,
|
|
311
|
+
requirePersistableReplacementSandboxEnvelope,
|
|
277
312
|
restoredSandboxSessionStateFromEntry,
|
|
278
313
|
runCredentialPointerFile,
|
|
279
314
|
runCredentialRoot,
|
|
@@ -285,6 +320,7 @@ export {
|
|
|
285
320
|
selfhostedLiveness,
|
|
286
321
|
selfhostedRetryBackoffMs,
|
|
287
322
|
serializeEstablishedSandboxEnvelope,
|
|
323
|
+
serializeReplacementSandboxEnvelope,
|
|
288
324
|
setSelfhostedApplyDiff,
|
|
289
325
|
startRecording,
|
|
290
326
|
stopRecording,
|
|
@@ -301,6 +337,8 @@ export {
|
|
|
301
337
|
toolspaceTokenFileForSession,
|
|
302
338
|
toolspaceTokenFileFromEnvironment,
|
|
303
339
|
uploadRecordingArtifact,
|
|
340
|
+
verifyRestoredWorkspace,
|
|
341
|
+
verifySandboxExecReadiness,
|
|
304
342
|
verifyStreamToken,
|
|
305
343
|
withRunCredentialEnvironment,
|
|
306
344
|
withRunCredentialsClient,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/runtime",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"@openai/agents-extensions": "0.13.3",
|
|
51
51
|
"@opengeni/agent-proto": "^0.3.0",
|
|
52
52
|
"@opengeni/codex": "^0.2.7",
|
|
53
|
-
"@opengeni/config": "^0.
|
|
54
|
-
"@opengeni/contracts": "^0.
|
|
53
|
+
"@opengeni/config": "^0.7.0",
|
|
54
|
+
"@opengeni/contracts": "^0.19.0",
|
|
55
55
|
"@opengeni/network": "^0.1.1",
|
|
56
56
|
"debug": "4.4.3",
|
|
57
57
|
"modal": "0.7.6",
|
package/src/index.ts
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
boundedParallelMap,
|
|
50
50
|
cancelMcpResponseBody,
|
|
51
51
|
guardedMcpFetch,
|
|
52
|
+
mcpOuterConnectTimeoutMs,
|
|
52
53
|
undiciFetch,
|
|
53
54
|
} from "./mcp-network";
|
|
54
55
|
import {
|
|
@@ -2342,7 +2343,7 @@ export type ConnectedMcpServerBatches = {
|
|
|
2342
2343
|
*/
|
|
2343
2344
|
export async function connectMcpServersInBatches(
|
|
2344
2345
|
servers: MCPServer[],
|
|
2345
|
-
options: { strict: boolean },
|
|
2346
|
+
options: { strict: boolean; connectTimeoutMs?: number },
|
|
2346
2347
|
): Promise<ConnectedMcpServerBatches> {
|
|
2347
2348
|
assertMcpServerSelectionWithinBounds(servers);
|
|
2348
2349
|
const batches: ConnectedMcpServerBatch[] = [];
|
|
@@ -2352,6 +2353,9 @@ export async function connectMcpServersInBatches(
|
|
|
2352
2353
|
await connectMcpServers(
|
|
2353
2354
|
servers.slice(offset, offset + MCP_MAX_CONCURRENT_SERVER_OPERATIONS),
|
|
2354
2355
|
{
|
|
2356
|
+
...(options.connectTimeoutMs === undefined
|
|
2357
|
+
? {}
|
|
2358
|
+
: { connectTimeoutMs: options.connectTimeoutMs }),
|
|
2355
2359
|
connectInParallel: true,
|
|
2356
2360
|
strict: options.strict,
|
|
2357
2361
|
},
|
|
@@ -2478,24 +2482,33 @@ export async function prepareAgentTools(
|
|
|
2478
2482
|
server,
|
|
2479
2483
|
bestEffort,
|
|
2480
2484
|
optional,
|
|
2485
|
+
timeoutMs: config.timeoutMs,
|
|
2481
2486
|
};
|
|
2482
2487
|
},
|
|
2483
2488
|
);
|
|
2484
|
-
const
|
|
2485
|
-
const
|
|
2486
|
-
|
|
2487
|
-
|
|
2489
|
+
const requiredEntries = servers.filter((entry) => !entry.bestEffort);
|
|
2490
|
+
const bestEffortEntries = servers.filter((entry) => entry.bestEffort);
|
|
2491
|
+
const requiredServers = requiredEntries.map((entry) => entry.server);
|
|
2492
|
+
const bestEffortServers = bestEffortEntries.map((entry) => entry.server);
|
|
2488
2493
|
// Names of the OPTIONAL servers (not codex_apps) so a drop is surfaced as a
|
|
2489
2494
|
// warning; codex_apps keeps its historically-quiet drop (a not-logged-in
|
|
2490
2495
|
// ChatGPT plan is a normal, non-noteworthy state).
|
|
2491
2496
|
const optionalServerNames = new Set(
|
|
2492
2497
|
servers.filter((entry) => entry.optional).map((entry) => entry.server.name),
|
|
2493
2498
|
);
|
|
2494
|
-
const connectedRequired = await connectMcpServersInBatches(requiredServers, {
|
|
2499
|
+
const connectedRequired = await connectMcpServersInBatches(requiredServers, {
|
|
2500
|
+
strict: true,
|
|
2501
|
+
connectTimeoutMs: mcpOuterConnectTimeoutMs(requiredEntries.map((entry) => entry.timeoutMs)),
|
|
2502
|
+
});
|
|
2495
2503
|
let connectedBestEffort: ConnectedMcpServerBatches | null = null;
|
|
2496
2504
|
try {
|
|
2497
2505
|
connectedBestEffort = bestEffortServers.length
|
|
2498
|
-
? await connectMcpServersInBatches(bestEffortServers, {
|
|
2506
|
+
? await connectMcpServersInBatches(bestEffortServers, {
|
|
2507
|
+
strict: false,
|
|
2508
|
+
connectTimeoutMs: mcpOuterConnectTimeoutMs(
|
|
2509
|
+
bestEffortEntries.map((entry) => entry.timeoutMs),
|
|
2510
|
+
),
|
|
2511
|
+
})
|
|
2499
2512
|
: null;
|
|
2500
2513
|
} catch (error) {
|
|
2501
2514
|
await connectedRequired.close().catch(() => undefined);
|
package/src/mcp-network.ts
CHANGED
|
@@ -18,6 +18,10 @@ export const MCP_MAX_TOOL_RESULT_BYTES = 1024 * 1024;
|
|
|
18
18
|
export const MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES = 256 * 1024;
|
|
19
19
|
export const MCP_MAX_SELECTED_SERVERS = 64;
|
|
20
20
|
export const MCP_MAX_CONCURRENT_SERVER_OPERATIONS = 8;
|
|
21
|
+
// @openai/agents has a separate lifecycle fence around MCPServer.connect().
|
|
22
|
+
// It defaults to 10 seconds and can otherwise preempt a larger per-server
|
|
23
|
+
// transport timeout before that server finishes its own handshake.
|
|
24
|
+
export const MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS = 10_000;
|
|
21
25
|
export const MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = 4_096;
|
|
22
26
|
export const MCP_MAX_AGGREGATE_TOOL_LIST_BYTES = 16 * 1024 * 1024;
|
|
23
27
|
export const MCP_MAX_TOOL_SEARCH_SOURCES = 64;
|
|
@@ -87,6 +91,15 @@ export function assertMcpServerSelectionWithinBounds<T>(servers: readonly T[]):
|
|
|
87
91
|
return servers;
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
export function mcpOuterConnectTimeoutMs(
|
|
95
|
+
configuredTimeouts: readonly (number | undefined)[],
|
|
96
|
+
): number {
|
|
97
|
+
return Math.max(
|
|
98
|
+
MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS,
|
|
99
|
+
...configuredTimeouts.flatMap((timeoutMs) => (timeoutMs === undefined ? [] : [timeoutMs])),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
90
103
|
type McpToolListContribution = {
|
|
91
104
|
entries: number;
|
|
92
105
|
bytes: number;
|
package/src/sandbox/channel-a.ts
CHANGED
|
@@ -58,9 +58,21 @@ import type {
|
|
|
58
58
|
TerminalExecRequest,
|
|
59
59
|
TerminalExecResponse,
|
|
60
60
|
} from "@opengeni/contracts";
|
|
61
|
-
import {
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
import {
|
|
62
|
+
isExecSessionLostBanner,
|
|
63
|
+
parseExecBannerExitCode,
|
|
64
|
+
parseExecBannerSessionId,
|
|
65
|
+
} from "./exec-banner";
|
|
66
|
+
import {
|
|
67
|
+
createTurnToolCancellationController,
|
|
68
|
+
TurnSandboxCommandCancelledError,
|
|
69
|
+
} from "./turn-tool-cancellation";
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
isExecSessionLostBanner,
|
|
73
|
+
parseExecBannerExitCode,
|
|
74
|
+
parseExecBannerSessionId,
|
|
75
|
+
} from "./exec-banner";
|
|
64
76
|
|
|
65
77
|
// ── The minimal session surface Channel A consumes (a structural subset of the
|
|
66
78
|
// SDK's SandboxSession, all optional — capability-probed before use). ─────────
|
|
@@ -101,6 +113,21 @@ export type ChannelASession = {
|
|
|
101
113
|
yieldTimeMs?: number;
|
|
102
114
|
maxOutputTokens?: number;
|
|
103
115
|
}): Promise<string>;
|
|
116
|
+
writeStdinForProcessMutation?(args: {
|
|
117
|
+
sessionId: number;
|
|
118
|
+
chars?: string;
|
|
119
|
+
yieldTimeMs?: number;
|
|
120
|
+
maxOutputTokens?: number;
|
|
121
|
+
}): Promise<string>;
|
|
122
|
+
writeStdinForProcessControl?(args: {
|
|
123
|
+
sessionId: number;
|
|
124
|
+
chars?: string;
|
|
125
|
+
yieldTimeMs?: number;
|
|
126
|
+
maxOutputTokens?: number;
|
|
127
|
+
}): Promise<string>;
|
|
128
|
+
cancelExecCommand?(opId: string): Promise<boolean>;
|
|
129
|
+
hasRetainedProcess?(providerSessionId: number): boolean;
|
|
130
|
+
execCommandForProcessControl?(providerSessionId: number, args: ChannelAExecArgs): Promise<string>;
|
|
104
131
|
createEditor?(runAs?: string): ChannelAEditor;
|
|
105
132
|
supportsPty?(): boolean;
|
|
106
133
|
};
|
|
@@ -1133,17 +1160,49 @@ export class SandboxChannelAService {
|
|
|
1133
1160
|
|
|
1134
1161
|
// ════════════════════════ Terminal exec + PTY (A2) ════════════════════════
|
|
1135
1162
|
|
|
1136
|
-
/** Run a bounded command
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
* the agent firehose so other viewers see it. */
|
|
1163
|
+
/** Run a bounded command to physical completion and return buffered output.
|
|
1164
|
+
* A deadline cancels the exact provider operation, proves its process group
|
|
1165
|
+
* absent, and settles any retained-process admission before returning 124. */
|
|
1140
1166
|
async terminalExec(req: TerminalExecRequest): Promise<TerminalExecResponse> {
|
|
1141
|
-
const
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1167
|
+
const abort = new AbortController();
|
|
1168
|
+
const controller = createTurnToolCancellationController(abort.signal);
|
|
1169
|
+
const timeoutReason = new Error(`Terminal command exceeded ${req.timeoutMs}ms`);
|
|
1170
|
+
let timedOut = false;
|
|
1171
|
+
const timer = setTimeout(() => {
|
|
1172
|
+
timedOut = true;
|
|
1173
|
+
abort.abort(timeoutReason);
|
|
1174
|
+
}, req.timeoutMs);
|
|
1175
|
+
const terminalWorkdir = this.terminalWorkdir(req.cwd);
|
|
1176
|
+
let r: Awaited<ReturnType<typeof controller.runSandboxCommandStructured>>;
|
|
1177
|
+
try {
|
|
1178
|
+
r = await controller.runSandboxCommandStructured(this.session, {
|
|
1179
|
+
cmd: req.command,
|
|
1180
|
+
...(terminalWorkdir ? { workdir: terminalWorkdir } : {}),
|
|
1181
|
+
...(this.runAs ? { runAs: this.runAs } : {}),
|
|
1182
|
+
yieldTimeMs: req.timeoutMs,
|
|
1183
|
+
});
|
|
1184
|
+
if (timedOut) {
|
|
1185
|
+
await controller.waitForQuiescence();
|
|
1186
|
+
r = {
|
|
1187
|
+
stdout: "",
|
|
1188
|
+
stderr: timeoutReason.message,
|
|
1189
|
+
exitCode: 124,
|
|
1190
|
+
wallTimeSeconds: req.timeoutMs / 1_000,
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
} catch (error) {
|
|
1194
|
+
controller.cancel(error);
|
|
1195
|
+
await controller.waitForQuiescence();
|
|
1196
|
+
if (!timedOut && !(error instanceof TurnSandboxCommandCancelledError)) throw error;
|
|
1197
|
+
r = {
|
|
1198
|
+
stdout: "",
|
|
1199
|
+
stderr: timeoutReason.message,
|
|
1200
|
+
exitCode: 124,
|
|
1201
|
+
wallTimeSeconds: req.timeoutMs / 1_000,
|
|
1202
|
+
};
|
|
1203
|
+
} finally {
|
|
1204
|
+
clearTimeout(timer);
|
|
1205
|
+
}
|
|
1147
1206
|
if (req.emitStream && (r.stdout || r.stderr)) {
|
|
1148
1207
|
const events: { type: SessionEventType; payload: unknown }[] = [];
|
|
1149
1208
|
const commandId = crypto.randomUUID();
|
|
@@ -1163,7 +1222,7 @@ export class SandboxChannelAService {
|
|
|
1163
1222
|
stdout: r.stdout,
|
|
1164
1223
|
stderr: r.stderr,
|
|
1165
1224
|
exitCode: r.exitCode,
|
|
1166
|
-
running,
|
|
1225
|
+
running: false,
|
|
1167
1226
|
wallTimeSeconds: r.wallTimeSeconds,
|
|
1168
1227
|
};
|
|
1169
1228
|
}
|
|
@@ -1203,10 +1262,13 @@ export class SandboxChannelAService {
|
|
|
1203
1262
|
* it as terminal.pty.output.delta). Throws ChannelAUnsupportedError when the
|
|
1204
1263
|
* backend has no writeStdin. */
|
|
1205
1264
|
async ptyWrite(_req: PtyWriteRequest, execSessionId: number, data: string): Promise<string> {
|
|
1206
|
-
|
|
1265
|
+
const write =
|
|
1266
|
+
this.session.writeStdinForProcessMutation?.bind(this.session) ??
|
|
1267
|
+
this.session.writeStdin?.bind(this.session);
|
|
1268
|
+
if (!write) {
|
|
1207
1269
|
throw new ChannelAUnsupportedError("interactive terminal unsupported on this backend");
|
|
1208
1270
|
}
|
|
1209
|
-
const out = await
|
|
1271
|
+
const out = await write({
|
|
1210
1272
|
sessionId: execSessionId,
|
|
1211
1273
|
chars: data,
|
|
1212
1274
|
yieldTimeMs: 250,
|
|
@@ -1228,25 +1290,27 @@ export class SandboxChannelAService {
|
|
|
1228
1290
|
/** Resize an open PTY (SIGWINCH via stty against the exec-session). The SDK has
|
|
1229
1291
|
* no resize method; stty in the same tty session updates the geometry. */
|
|
1230
1292
|
async ptyResize(req: PtyResizeRequest, execSessionId: number): Promise<void> {
|
|
1231
|
-
|
|
1293
|
+
const write =
|
|
1294
|
+
this.session.writeStdinForProcessControl?.bind(this.session) ??
|
|
1295
|
+
this.session.writeStdin?.bind(this.session);
|
|
1296
|
+
if (!write) return;
|
|
1232
1297
|
// Send a stty in-band on the same pty session.
|
|
1233
|
-
await
|
|
1298
|
+
await write({
|
|
1234
1299
|
sessionId: execSessionId,
|
|
1235
1300
|
chars: `stty cols ${req.cols} rows ${req.rows}\n`,
|
|
1236
1301
|
yieldTimeMs: 50,
|
|
1237
1302
|
});
|
|
1238
1303
|
}
|
|
1239
1304
|
|
|
1240
|
-
/**
|
|
1241
|
-
*
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}
|
|
1305
|
+
/** Ask an open PTY to exit and return the exact provider banner. The routing
|
|
1306
|
+
* session settles durable process authority only when that banner proves this
|
|
1307
|
+
* locator exited or was lost; callers must keep metadata open otherwise. */
|
|
1308
|
+
async ptyClose(_req: PtyCloseRequest, execSessionId: number | null): Promise<string> {
|
|
1309
|
+
const write =
|
|
1310
|
+
this.session.writeStdinForProcessControl?.bind(this.session) ??
|
|
1311
|
+
this.session.writeStdin?.bind(this.session);
|
|
1312
|
+
if (execSessionId === null || !write) return "";
|
|
1313
|
+
return await write({ sessionId: execSessionId, chars: "", yieldTimeMs: 250 }); // EOF
|
|
1250
1314
|
}
|
|
1251
1315
|
|
|
1252
1316
|
// ──────────────────────────── helpers ──────────────────────────────────────
|
|
@@ -1435,24 +1499,6 @@ function isDefinitePathNotFoundError(error: unknown): boolean {
|
|
|
1435
1499
|
);
|
|
1436
1500
|
}
|
|
1437
1501
|
|
|
1438
|
-
// Detect the Modal "the exec-session you're writing to no longer exists" banner.
|
|
1439
|
-
// writeStdin reports a vanished session as a non-throwing string of the shape
|
|
1440
|
-
// `write_stdin failed: session not found: <N>` (it does NOT raise). This is a
|
|
1441
|
-
// hard cancellation-fence fact, so classify only the complete known banner (or
|
|
1442
|
-
// its bare provider fact) carrying the exact tracked numeric id. ID-less,
|
|
1443
|
-
// malformed, mismatched, or embellished/ambiguous text must remain fail-closed.
|
|
1444
|
-
export function isExecSessionLostBanner(out: string, execSessionId: number): boolean {
|
|
1445
|
-
if (!out || !Number.isSafeInteger(execSessionId) || execSessionId < 0) return false;
|
|
1446
|
-
const match = out.match(/^(?:write_stdin failed: )?session not found: (\d+)$/);
|
|
1447
|
-
// JavaScript's `$` also matches immediately before one final line terminator.
|
|
1448
|
-
// Requiring the regex match to consume the entire string keeps even that
|
|
1449
|
-
// otherwise-special case fail-closed.
|
|
1450
|
-
if (!match || match[0] !== out) return false;
|
|
1451
|
-
// String equality is intentional: parseInt would normalize malformed facts
|
|
1452
|
-
// such as `01` and can round an out-of-range integer into another identity.
|
|
1453
|
-
return match[1] === String(execSessionId);
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
1502
|
function sniffBinary(bytes: Buffer): boolean {
|
|
1457
1503
|
const n = Math.min(bytes.byteLength, 8192);
|
|
1458
1504
|
for (let i = 0; i < n; i++) if (bytes[i] === 0) return true;
|
|
@@ -65,3 +65,18 @@ export function parseExecBannerExitCode(raw: string): number | null {
|
|
|
65
65
|
const banner = parseExecResponseBanner(raw);
|
|
66
66
|
return banner.kind === "exited" ? banner.exitCode : null;
|
|
67
67
|
}
|
|
68
|
+
|
|
69
|
+
// Detect the Modal "the exec-session you're writing to no longer exists" fact.
|
|
70
|
+
// This is process-lifetime authority, so classify only the complete known
|
|
71
|
+
// banner (or its bare provider form) carrying the exact tracked numeric id.
|
|
72
|
+
export function isExecSessionLostBanner(out: string, execSessionId: number): boolean {
|
|
73
|
+
if (!out || !Number.isSafeInteger(execSessionId) || execSessionId < 0) return false;
|
|
74
|
+
const match = out.match(/^(?:write_stdin failed: )?session not found: (\d+)$/);
|
|
75
|
+
// JavaScript's `$` also matches immediately before one final line terminator.
|
|
76
|
+
// Requiring the regex match to consume the entire string keeps even that
|
|
77
|
+
// otherwise-special case fail-closed.
|
|
78
|
+
if (!match || match[0] !== out) return false;
|
|
79
|
+
// String equality is intentional: parseInt would normalize malformed facts
|
|
80
|
+
// such as `01` and can round an out-of-range integer into another identity.
|
|
81
|
+
return match[1] === String(execSessionId);
|
|
82
|
+
}
|