@opengeni/runtime 0.5.0 → 0.6.0
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-Q36E4MDM.js → chunk-BHA2SU3H.js} +54 -3
- package/dist/chunk-BHA2SU3H.js.map +1 -0
- package/dist/{index-BrdnxaAW.d.ts → index-otZkoLYq.d.ts} +11 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +3 -1
- package/package.json +2 -2
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/providers/modal.ts +107 -2
- package/dist/chunk-Q36E4MDM.js.map +0 -1
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, a as ActiveBackendUnresolvableError, b as ActivePointer, C as ChannelAConflictError, c as ChannelAEmitter, d as ChannelAExecArgs, e as ChannelAExecResult, f as ChannelANotFoundError, g as ChannelASession, h as ChannelAUnsupportedError, i as ChannelAValidationError, j as ControlRpc, D as DEFAULT_DESKTOP_GEOMETRY, k as DISPLAY_STACK_TIMEOUT_MS, l as DesktopGeometry, m as DisplayStackError, n as DisplayStackUnsupportedError, E as EnsureDisplayStackOptions, o as EnsureDisplayStackResult, p as EnsureTerminalServerOptions, q as EnsureTerminalServerResult, r as EstablishedSandboxSession, s as ExposeStreamPortInput, t as ExposeStreamPortResult, u as ExposedPortEndpoint, F as FinalizeRecordingResult, L as LiveModalSandboxLeaseAttribution, M as MintStreamTokenInput, v as MockAgentResponder, w as MockAgentResponderOptions, x as MockExecHandler, y as
|
|
4
|
+
export { A as ActiveBackendResolverDeps, a as ActiveBackendUnresolvableError, b as ActivePointer, C as ChannelAConflictError, c as ChannelAEmitter, d as ChannelAExecArgs, e as ChannelAExecResult, f as ChannelANotFoundError, g as ChannelASession, h as ChannelAUnsupportedError, i as ChannelAValidationError, j as ControlRpc, D as DEFAULT_DESKTOP_GEOMETRY, k as DISPLAY_STACK_TIMEOUT_MS, l as DesktopGeometry, m as DisplayStackError, n as DisplayStackUnsupportedError, E as EnsureDisplayStackOptions, o as EnsureDisplayStackResult, p as EnsureTerminalServerOptions, q as EnsureTerminalServerResult, r as EstablishedSandboxSession, s as ExposeStreamPortInput, t as ExposeStreamPortResult, u as ExposedPortEndpoint, F as FinalizeRecordingResult, L as LiveModalSandboxLeaseAttribution, M as MintStreamTokenInput, v as MockAgentResponder, w as MockAgentResponderOptions, x as MockExecHandler, y as ModalModuleLoader, z as ModalOrphanSweepResult, B as ModalSandboxAttribution, N as NatsControlRpc, G as NatsRequestConnection, H as NegotiationContext, I as NumstatEntry, P as PROVIDER_REGISTRY, J as ProviderConstructionContext, K as ProviderRegistration, O as RecordingCodec, Q as RecordingContentType, S as RecordingError, T as RecordingProcess, U as RecordingUnavailableError, V as ResolvedActiveBackend, W as RoutableBackendSession, X as RoutableSandbox, Y as RoutingSandboxSession, Z as RoutingSandboxSessionDeps, _ as RoutingTransitionEvent, $ as RoutingUnsupportedError, a0 as SELFHOSTED_DEFAULT_TIMEOUT_MS, a1 as SELFHOSTED_RECONNECT_WINDOW_MS, a2 as SELFHOSTED_RELAY_STREAM_PATH, a3 as STREAM_PORT, a4 as STREAM_TOKEN_DEFAULT_TTL_SECONDS, a5 as SandboxChannelAService, a6 as SandboxChannelAServiceOptions, a7 as SandboxConfigError, a8 as SandboxCreatedCallback, a9 as SandboxProviderUnavailableError, aa as SelfhostedApplyDiff, ab as SelfhostedControlError, ac as SelfhostedEditor, ad as SelfhostedEnrollment, ae as SelfhostedExecArgs, af as SelfhostedExecResult, ag as SelfhostedImageOutput, ah as SelfhostedLivenessState, ai as SelfhostedNegotiationInput, aj as SelfhostedRelayConfig, ak as SelfhostedSandboxClient, al as SelfhostedSession, am as SelfhostedSessionBuild, an as SelfhostedSessionDeps, ao as SelfhostedSessionState, ap as SelfhostedUnavailableReason, aq as StartRecordingInput, ar as StreamPortUnavailableError, as as TERMINAL_SERVER_TIMEOUT_MS, at as TerminalServerError, au as TerminalServerUnsupportedError, av as agentErrorToControlError, aw as assertDescriptorRegistryInvariants, ax as assertProviderRegistryInvariants, ay as assertSafeRelPath, az as backendSupportsOs, aA as buildDisplayStackScript, aB as buildSelfhostedBackendSession, aC as buildStreamUrl, aD as buildTerminalServerScript, aE as contentTypeForCodec, aF as createSandboxClient, aG as createSandboxClientForBackend, aH as decodeModalSnapshotId, aI as deletePriorPersistedSnapshot, aJ as deleteRecordingArtifacts, aK as deserializeSandboxSessionStateEnvelope, aL as desktopCapableBackend, aM as ensureDisplayStack, aN as ensureModalRegistryImage, aO as ensureTerminalServer, aP as establishSandboxSessionFromEnvelope, aQ as exposeStreamPort, aR as extForCodec, aS as isExecSessionLostBanner, aT as isProviderSandboxNotFoundError, aU as isSelfhostedProviderNotFoundError, aV as isWorkspaceEscapeError, aW as makeActiveBackendResolver, aX as mintStreamToken, aY as modalSandboxAttributionEnvironment, aZ as modalSandboxAttributionTags, a_ as negotiateCapabilities, a$ as negotiateSelfhostedCapabilities, b0 as offlineAgentError, b1 as offlineControlResponse, b2 as parseExecBannerSessionId, b3 as parseNumstatZ, b4 as parsePorcelainV2, b5 as parseUnifiedPatch, b6 as readRecordingBytes, b7 as readWorkspaceArchiveFromEnvelopeSessionState, b8 as recordingStorageKey, b9 as restoredSandboxSessionStateFromEntry, ba as sandboxStateEntryFromRunState, bb as selectBackend, bc as selfhostedLiveness, bd as serializeEstablishedSandboxEnvelope, be as setSelfhostedApplyDiff, bf as startRecording, bg as stopRecording, bh as stripExecBanner, bi as subjectFor, bj as sweepModalOrphanSandboxes, bk as tagModalSandbox, bl as tearDownDisplayStack, bm as tearDownTerminalServer, bn as terminateModalSandboxById, bo as timeoutAgentError, bp as timeoutControlResponse, bq as verifyStreamToken } from '../index-otZkoLYq.js';
|
|
5
5
|
import 'modal';
|
|
6
6
|
import '@opengeni/agent-proto';
|
package/dist/sandbox/index.js
CHANGED
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
deserializeSandboxSessionStateEnvelope,
|
|
54
54
|
desktopCapableBackend,
|
|
55
55
|
ensureDisplayStack,
|
|
56
|
+
ensureModalRegistryImage,
|
|
56
57
|
ensureTerminalServer,
|
|
57
58
|
establishSandboxSessionFromEnvelope,
|
|
58
59
|
exposeStreamPort,
|
|
@@ -95,7 +96,7 @@ import {
|
|
|
95
96
|
timeoutAgentError,
|
|
96
97
|
timeoutControlResponse,
|
|
97
98
|
verifyStreamToken
|
|
98
|
-
} from "../chunk-
|
|
99
|
+
} from "../chunk-BHA2SU3H.js";
|
|
99
100
|
export {
|
|
100
101
|
ActiveBackendUnresolvableError,
|
|
101
102
|
CAPABILITY_DESCRIPTORS,
|
|
@@ -151,6 +152,7 @@ export {
|
|
|
151
152
|
deserializeSandboxSessionStateEnvelope,
|
|
152
153
|
desktopCapableBackend,
|
|
153
154
|
ensureDisplayStack,
|
|
155
|
+
ensureModalRegistryImage,
|
|
154
156
|
ensureTerminalServer,
|
|
155
157
|
establishSandboxSessionFromEnvelope,
|
|
156
158
|
exposeStreamPort,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@opengeni/agent-proto": "^0.2.1",
|
|
34
|
-
"@opengeni/config": "^0.
|
|
34
|
+
"@opengeni/config": "^0.4.0",
|
|
35
35
|
"@opengeni/contracts": "^0.9.0",
|
|
36
36
|
"@openai/agents": "^0.11.6",
|
|
37
37
|
"@openai/agents-extensions": "^0.11.6",
|
package/src/sandbox/index.ts
CHANGED
|
@@ -55,12 +55,14 @@ export {
|
|
|
55
55
|
type ProviderConstructionContext,
|
|
56
56
|
} from "./providers";
|
|
57
57
|
export {
|
|
58
|
+
ensureModalRegistryImage,
|
|
58
59
|
modalSandboxAttributionEnvironment,
|
|
59
60
|
modalSandboxAttributionTags,
|
|
60
61
|
sweepModalOrphanSandboxes,
|
|
61
62
|
tagModalSandbox,
|
|
62
63
|
terminateModalSandboxById,
|
|
63
64
|
type LiveModalSandboxLeaseAttribution,
|
|
65
|
+
type ModalModuleLoader,
|
|
64
66
|
type ModalOrphanSweepResult,
|
|
65
67
|
type ModalSandboxAttribution,
|
|
66
68
|
} from "./providers/modal";
|
|
@@ -87,8 +87,9 @@ export const modalProvider: ProviderRegistration = {
|
|
|
87
87
|
if (settings.modalWorkspacePersistence) {
|
|
88
88
|
options.workspacePersistence = settings.modalWorkspacePersistence;
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const imageSelector = resolveModalImageSelector(settings);
|
|
91
|
+
if (imageSelector) {
|
|
92
|
+
options.image = imageSelector;
|
|
92
93
|
}
|
|
93
94
|
if (settings.modalTokenId) {
|
|
94
95
|
options.tokenId = settings.modalTokenId;
|
|
@@ -106,6 +107,110 @@ export const modalProvider: ProviderRegistration = {
|
|
|
106
107
|
type ModalModule = typeof import("modal");
|
|
107
108
|
type ModalClientLike = InstanceType<ModalModule["ModalClient"]>;
|
|
108
109
|
|
|
110
|
+
// --- Private-registry image resolution (OPENGENI_MODAL_IMAGE_REGISTRY_SECRET) ------
|
|
111
|
+
//
|
|
112
|
+
// The Agents-extension Modal backend resolves `modalImageRef` via
|
|
113
|
+
// `Image.fromRegistry(tag)` with NO secret, so it can only pull PUBLIC images. To run
|
|
114
|
+
// a PRIVATE image we resolve the named Modal Secret and pre-build the authenticated
|
|
115
|
+
// `fromRegistry(tag, secret)` image ONCE per process, then hand the provider `build`
|
|
116
|
+
// a `ModalImageSelector.fromImage(...)`. `build` is synchronous and modal is imported
|
|
117
|
+
// lazily (never loaded for non-modal backends), so resolution can't happen inside
|
|
118
|
+
// `build`; the worker boot awaits `ensureModalRegistryImage` first and `build` reads
|
|
119
|
+
// the settled result. Modal images are lazy, workspace-scoped definitions, so an image
|
|
120
|
+
// built by this module's client is usable by the ModalSandboxClient's own client.
|
|
121
|
+
|
|
122
|
+
/** Loader seam so unit tests can inject a fake modal module. */
|
|
123
|
+
export type ModalModuleLoader = () => Promise<
|
|
124
|
+
Pick<ModalModule, "ModalClient" | "Secret">
|
|
125
|
+
>;
|
|
126
|
+
|
|
127
|
+
const defaultModalLoader: ModalModuleLoader = () => import("modal");
|
|
128
|
+
|
|
129
|
+
/** Settled, synchronously-readable resolved images, keyed per config. */
|
|
130
|
+
const resolvedRegistryImages = new Map<string, unknown>();
|
|
131
|
+
/** In-flight resolutions, for cross-call de-duplication. */
|
|
132
|
+
const inFlightRegistryImages = new Map<string, Promise<void>>();
|
|
133
|
+
|
|
134
|
+
function registryImageCacheKey(settings: Settings): string {
|
|
135
|
+
return [
|
|
136
|
+
settings.modalImageRef ?? "",
|
|
137
|
+
settings.modalImageRegistrySecret ?? "",
|
|
138
|
+
settings.modalEnvironment ?? "",
|
|
139
|
+
].join("|");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Resolve + cache the private-registry Modal image. No-op unless BOTH
|
|
144
|
+
* `modalImageRef` and `modalImageRegistrySecret` are set. Memoized per
|
|
145
|
+
* (imageRef, secret, environment) so it runs once per worker process. Awaited at
|
|
146
|
+
* worker boot BEFORE the first sandbox is created; `build` then reads the resolved
|
|
147
|
+
* image and otherwise falls back to the public `fromTag` path.
|
|
148
|
+
*/
|
|
149
|
+
export async function ensureModalRegistryImage(
|
|
150
|
+
settings: Settings,
|
|
151
|
+
loadModal: ModalModuleLoader = defaultModalLoader,
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
if (!settings.modalImageRegistrySecret || !settings.modalImageRef) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const key = registryImageCacheKey(settings);
|
|
157
|
+
if (resolvedRegistryImages.has(key)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
let pending = inFlightRegistryImages.get(key);
|
|
161
|
+
if (!pending) {
|
|
162
|
+
pending = (async () => {
|
|
163
|
+
const modal = await loadModal();
|
|
164
|
+
const client = new modal.ModalClient(modalClientOptions(settings));
|
|
165
|
+
const secret = await modal.Secret.fromName(
|
|
166
|
+
settings.modalImageRegistrySecret!,
|
|
167
|
+
settings.modalEnvironment ? { environment: settings.modalEnvironment } : undefined,
|
|
168
|
+
);
|
|
169
|
+
// fromRegistry is synchronous and returns a lazy image definition (built
|
|
170
|
+
// server-side at sandbox create); the resolved secretId travels with it.
|
|
171
|
+
const image = client.images.fromRegistry(settings.modalImageRef!, secret);
|
|
172
|
+
resolvedRegistryImages.set(key, image);
|
|
173
|
+
})().finally(() => {
|
|
174
|
+
inFlightRegistryImages.delete(key);
|
|
175
|
+
});
|
|
176
|
+
inFlightRegistryImages.set(key, pending);
|
|
177
|
+
}
|
|
178
|
+
await pending;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** The resolved private-registry image for these settings, or undefined if none. */
|
|
182
|
+
function cachedModalRegistryImage(settings: Settings): unknown | undefined {
|
|
183
|
+
if (!settings.modalImageRegistrySecret || !settings.modalImageRef) {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
return resolvedRegistryImages.get(registryImageCacheKey(settings));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Choose the image selector for a Modal sandbox client from settings. Returns:
|
|
191
|
+
* - `fromImage(resolved)` when a private-registry secret is configured AND the
|
|
192
|
+
* image has been resolved (ensureModalRegistryImage ran at worker boot);
|
|
193
|
+
* - `fromTag(modalImageRef)` for the public path (no secret, or cold cache — the
|
|
194
|
+
* resume/attach paths never pull an image so the tag branch is harmless there);
|
|
195
|
+
* - `undefined` when no image ref is set (Modal uses its default image).
|
|
196
|
+
* Exported for unit tests.
|
|
197
|
+
*/
|
|
198
|
+
export function resolveModalImageSelector(settings: Settings): ModalImageSelector | undefined {
|
|
199
|
+
if (!settings.modalImageRef) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
const registryImage = cachedModalRegistryImage(settings);
|
|
203
|
+
return registryImage
|
|
204
|
+
? ModalImageSelector.fromImage(registryImage as Parameters<typeof ModalImageSelector.fromImage>[0])
|
|
205
|
+
: ModalImageSelector.fromTag(settings.modalImageRef);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Test-only: clear the resolved/in-flight image caches. */
|
|
209
|
+
export function __resetModalRegistryImageCacheForTest(): void {
|
|
210
|
+
resolvedRegistryImages.clear();
|
|
211
|
+
inFlightRegistryImages.clear();
|
|
212
|
+
}
|
|
213
|
+
|
|
109
214
|
function modalClientOptions(settings: Settings): ConstructorParameters<ModalModule["ModalClient"]>[0] {
|
|
110
215
|
return {
|
|
111
216
|
...(settings.modalTokenId ? { tokenId: settings.modalTokenId } : {}),
|