@opengeni/runtime 0.4.0 → 0.5.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.
@@ -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 ModalOrphanSweepResult, z as ModalSandboxAttribution, N as NatsControlRpc, B as NatsRequestConnection, G as NegotiationContext, H as NumstatEntry, P as PROVIDER_REGISTRY, I as ProviderConstructionContext, J as ProviderRegistration, K as RecordingCodec, O as RecordingContentType, Q as RecordingError, S as RecordingProcess, T as RecordingUnavailableError, U as ResolvedActiveBackend, V as RoutableBackendSession, W as RoutableSandbox, X as RoutingSandboxSession, Y as RoutingSandboxSessionDeps, Z as RoutingTransitionEvent, _ as RoutingUnsupportedError, $ as SELFHOSTED_DEFAULT_TIMEOUT_MS, a0 as SELFHOSTED_RECONNECT_WINDOW_MS, a1 as SELFHOSTED_RELAY_STREAM_PATH, a2 as STREAM_PORT, a3 as STREAM_TOKEN_DEFAULT_TTL_SECONDS, a4 as SandboxChannelAService, a5 as SandboxChannelAServiceOptions, a6 as SandboxConfigError, a7 as SandboxCreatedCallback, a8 as SandboxProviderUnavailableError, a9 as SelfhostedApplyDiff, aa as SelfhostedControlError, ab as SelfhostedEditor, ac as SelfhostedEnrollment, ad as SelfhostedExecArgs, ae as SelfhostedExecResult, af as SelfhostedImageOutput, ag as SelfhostedLivenessState, ah as SelfhostedNegotiationInput, ai as SelfhostedRelayConfig, aj as SelfhostedSandboxClient, ak as SelfhostedSession, al as SelfhostedSessionBuild, am as SelfhostedSessionDeps, an as SelfhostedSessionState, ao as SelfhostedUnavailableReason, ap as StartRecordingInput, aq as StreamPortUnavailableError, ar as TERMINAL_SERVER_TIMEOUT_MS, as as TerminalServerError, at as TerminalServerUnsupportedError, au as agentErrorToControlError, av as assertDescriptorRegistryInvariants, aw as assertProviderRegistryInvariants, ax as assertSafeRelPath, ay as backendSupportsOs, az as buildDisplayStackScript, aA as buildSelfhostedBackendSession, aB as buildStreamUrl, aC as buildTerminalServerScript, aD as contentTypeForCodec, aE as createSandboxClient, aF as createSandboxClientForBackend, aG as decodeModalSnapshotId, aH as deletePriorPersistedSnapshot, aI as deleteRecordingArtifacts, aJ as deserializeSandboxSessionStateEnvelope, aK as desktopCapableBackend, aL as ensureDisplayStack, aM as ensureTerminalServer, aN as establishSandboxSessionFromEnvelope, aO as exposeStreamPort, aP as extForCodec, aQ as isExecSessionLostBanner, aR as isProviderSandboxNotFoundError, aS as isSelfhostedProviderNotFoundError, aT as isWorkspaceEscapeError, aU as makeActiveBackendResolver, aV as mintStreamToken, aW as modalSandboxAttributionEnvironment, aX as modalSandboxAttributionTags, aY as negotiateCapabilities, aZ as negotiateSelfhostedCapabilities, a_ as offlineAgentError, a$ as offlineControlResponse, b0 as parseExecBannerSessionId, b1 as parseNumstatZ, b2 as parsePorcelainV2, b3 as parseUnifiedPatch, b4 as readRecordingBytes, b5 as readWorkspaceArchiveFromEnvelopeSessionState, b6 as recordingStorageKey, b7 as restoredSandboxSessionStateFromEntry, b8 as sandboxStateEntryFromRunState, b9 as selectBackend, ba as selfhostedLiveness, bb as serializeEstablishedSandboxEnvelope, bc as setSelfhostedApplyDiff, bd as startRecording, be as stopRecording, bf as stripExecBanner, bg as subjectFor, bh as sweepModalOrphanSandboxes, bi as tagModalSandbox, bj as tearDownDisplayStack, bk as tearDownTerminalServer, bl as terminateModalSandboxById, bm as timeoutAgentError, bn as timeoutControlResponse, bo as verifyStreamToken } from '../index-CSGkld-v.js';
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 ModalOrphanSweepResult, z as ModalSandboxAttribution, N as NatsControlRpc, B as NatsRequestConnection, G as NegotiationContext, H as NumstatEntry, P as PROVIDER_REGISTRY, I as ProviderConstructionContext, J as ProviderRegistration, K as RecordingCodec, O as RecordingContentType, Q as RecordingError, S as RecordingProcess, T as RecordingUnavailableError, U as ResolvedActiveBackend, V as RoutableBackendSession, W as RoutableSandbox, X as RoutingSandboxSession, Y as RoutingSandboxSessionDeps, Z as RoutingTransitionEvent, _ as RoutingUnsupportedError, $ as SELFHOSTED_DEFAULT_TIMEOUT_MS, a0 as SELFHOSTED_RECONNECT_WINDOW_MS, a1 as SELFHOSTED_RELAY_STREAM_PATH, a2 as STREAM_PORT, a3 as STREAM_TOKEN_DEFAULT_TTL_SECONDS, a4 as SandboxChannelAService, a5 as SandboxChannelAServiceOptions, a6 as SandboxConfigError, a7 as SandboxCreatedCallback, a8 as SandboxProviderUnavailableError, a9 as SelfhostedApplyDiff, aa as SelfhostedControlError, ab as SelfhostedEditor, ac as SelfhostedEnrollment, ad as SelfhostedExecArgs, ae as SelfhostedExecResult, af as SelfhostedImageOutput, ag as SelfhostedLivenessState, ah as SelfhostedNegotiationInput, ai as SelfhostedRelayConfig, aj as SelfhostedSandboxClient, ak as SelfhostedSession, al as SelfhostedSessionBuild, am as SelfhostedSessionDeps, an as SelfhostedSessionState, ao as SelfhostedUnavailableReason, ap as StartRecordingInput, aq as StreamPortUnavailableError, ar as TERMINAL_SERVER_TIMEOUT_MS, as as TerminalServerError, at as TerminalServerUnsupportedError, au as agentErrorToControlError, av as assertDescriptorRegistryInvariants, aw as assertProviderRegistryInvariants, ax as assertSafeRelPath, ay as backendSupportsOs, az as buildDisplayStackScript, aA as buildSelfhostedBackendSession, aB as buildStreamUrl, aC as buildTerminalServerScript, aD as contentTypeForCodec, aE as createSandboxClient, aF as createSandboxClientForBackend, aG as decodeModalSnapshotId, aH as deletePriorPersistedSnapshot, aI as deleteRecordingArtifacts, aJ as deserializeSandboxSessionStateEnvelope, aK as desktopCapableBackend, aL as ensureDisplayStack, aM as ensureTerminalServer, aN as establishSandboxSessionFromEnvelope, aO as exposeStreamPort, aP as extForCodec, aQ as isExecSessionLostBanner, aR as isProviderSandboxNotFoundError, aS as isSelfhostedProviderNotFoundError, aT as isWorkspaceEscapeError, aU as makeActiveBackendResolver, aV as mintStreamToken, aW as modalSandboxAttributionEnvironment, aX as modalSandboxAttributionTags, aY as negotiateCapabilities, aZ as negotiateSelfhostedCapabilities, a_ as offlineAgentError, a$ as offlineControlResponse, b0 as parseExecBannerSessionId, b1 as parseNumstatZ, b2 as parsePorcelainV2, b3 as parseUnifiedPatch, b4 as readRecordingBytes, b5 as readWorkspaceArchiveFromEnvelopeSessionState, b6 as recordingStorageKey, b7 as restoredSandboxSessionStateFromEntry, b8 as sandboxStateEntryFromRunState, b9 as selectBackend, ba as selfhostedLiveness, bb as serializeEstablishedSandboxEnvelope, bc as setSelfhostedApplyDiff, bd as startRecording, be as stopRecording, bf as stripExecBanner, bg as subjectFor, bh as sweepModalOrphanSandboxes, bi as tagModalSandbox, bj as tearDownDisplayStack, bk as tearDownTerminalServer, bl as terminateModalSandboxById, bm as timeoutAgentError, bn as timeoutControlResponse, bo as verifyStreamToken } from '../index-BrdnxaAW.js';
5
5
  import 'modal';
6
6
  import '@opengeni/agent-proto';
@@ -95,7 +95,7 @@ import {
95
95
  timeoutAgentError,
96
96
  timeoutControlResponse,
97
97
  verifyStreamToken
98
- } from "../chunk-HGQ252FL.js";
98
+ } from "../chunk-Q36E4MDM.js";
99
99
  export {
100
100
  ActiveBackendUnresolvableError,
101
101
  CAPABILITY_DESCRIPTORS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/runtime",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -937,6 +937,25 @@ export function appendSessionInstructions(composed: string, sessionInstructions?
937
937
  return trimmed ? `${composed} ${trimmed}` : composed;
938
938
  }
939
939
 
940
+ /**
941
+ * Appends the generic programmatic-tool-calling (toolspace) directive to the
942
+ * composed workspace + CORE instructions, joined by " ". This is GENERIC
943
+ * substrate prompting — the same text for every host, never per-host copy.
944
+ *
945
+ * Included ONLY when `toolspaceAvailable` is true, which the caller sets from the
946
+ * exact condition that gates the sandbox token mint: the toolspace feature is
947
+ * enabled AND a toolspace token was minted for THIS turn. That mint now happens
948
+ * on every backend including selfhosted (connected machines get the token too),
949
+ * so the block appears there as well; a turn with no minted token (feature off)
950
+ * has no toolspace URL/token in its sandbox and must not advertise a capability
951
+ * that is not there — the gate is false and this is a no-op. Placed BEFORE the
952
+ * per-session instructions so host/session specificity still wins over this
953
+ * substrate note.
954
+ */
955
+ export function appendToolspaceInstructions(composed: string, toolspaceAvailable: boolean): string {
956
+ return toolspaceAvailable ? `${composed} ${TOOLSPACE_PROGRAMMATIC_DIRECTIVE}` : composed;
957
+ }
958
+
940
959
  /**
941
960
  * Appends the one-shot genesis title directive (genesis turn only), joined by
942
961
  * " " and always LAST so a white-label persona template or a per-session
@@ -1030,14 +1049,21 @@ export function buildOpenGeniAgent(settings: Settings, resources: ResourceRef[],
1030
1049
  // Persona composition order (all one system-level instructions string):
1031
1050
  // 1. workspace instructionsTemplate (or deployment default) with the
1032
1051
  // non-bypassable CORE substituted at {{core}} — composeAgentInstructions,
1033
- // 2. + the per-session persona instructions (session-specific, LAST so it
1034
- // refines the workspace persona),
1035
- // 3. + the one-shot genesis title directive (genesis turn only).
1036
- // With no session instructions and no genesis hint this is byte-identical to
1037
- // the historical composed instructions.
1052
+ // 2. + the generic programmatic-tool-calling (toolspace) directive, ONLY
1053
+ // when a toolspace token was minted for this turn (feature enabled + a
1054
+ // per-turn seed — the mint gate, which includes selfhosted turns since
1055
+ // they now receive the token too) — appendToolspaceInstructions,
1056
+ // 3. + the per-session persona instructions (session-specific, so it
1057
+ // refines both the workspace persona and the substrate note),
1058
+ // 4. + the one-shot genesis title directive (genesis turn only).
1059
+ // With no toolspace token, no session instructions, and no genesis hint this
1060
+ // is byte-identical to the historical composed instructions.
1038
1061
  instructions: appendGenesisTitleDirective(
1039
1062
  appendSessionInstructions(
1040
- composeAgentInstructions(options.instructionsTemplate ?? settings.agentInstructionsTemplate, options.workspaceEnvironment),
1063
+ appendToolspaceInstructions(
1064
+ composeAgentInstructions(options.instructionsTemplate ?? settings.agentInstructionsTemplate, options.workspaceEnvironment),
1065
+ settings.toolspaceEnabled && Boolean(options.toolspaceTokenSeed),
1066
+ ),
1041
1067
  options.sessionInstructions,
1042
1068
  ),
1043
1069
  options.genesisTitleHint,
@@ -2194,6 +2220,13 @@ export type ContextRobustnessFilterOptions = {
2194
2220
  export const GENESIS_TITLE_DIRECTIVE =
2195
2221
  "This is the first turn of a new session. Before responding to the user, call the opengeni__set_session_title tool with a concise 3-7 word title that summarizes what this session is about, then address the user's request normally.";
2196
2222
 
2223
+ // Generic substrate prompting for programmatic tool calling (toolspace). Same
2224
+ // text for every host; gated per-turn by appendToolspaceInstructions on the
2225
+ // presence of a minted toolspace token, so it only appears when the sandbox
2226
+ // actually exposes the ogtool CLI + $OPENGENI_TOOLSPACE_URL/_TOKEN_FILE.
2227
+ export const TOOLSPACE_PROGRAMMATIC_DIRECTIVE =
2228
+ "Every tool on your MCP surface is also callable programmatically from the sandbox shell, so scripts can invoke tools without a model round trip per call. Run `ogtool list` to see the available tools and their input schemas (from tools/list), then `ogtool call <tool-name> '<json-args>'`; equivalently, POST MCP JSON-RPC to $OPENGENI_TOOLSPACE_URL with the bearer token read from $OPENGENI_TOOLSPACE_TOKEN_FILE. Prefer programmatic calls for loops, polling, and bulk filtering: their results stay in the sandbox and do not consume your context window. Tools that require human approval must still be invoked normally — called programmatically they return a typed error.";
2229
+
2197
2230
  /**
2198
2231
  * callModelInputFilter that removes provider-assigned item ids (rs_/msg_/fc_…)
2199
2232
  * from every input item immediately before each model call. Responses-API
@@ -2398,6 +2431,22 @@ export async function runAgentStream(agent: Agent<any, any>, input: PreparedAgen
2398
2431
  ...(runAs ? { runAs } : {}),
2399
2432
  });
2400
2433
  }
2434
+ } else {
2435
+ // SELFHOSTED TOOLSPACE (parity): the platform setup hooks (repository clone,
2436
+ // az login) and file materialization stay OFF the user's real machine — but
2437
+ // the toolspace token seed is the ONE piece of per-turn material that must
2438
+ // reach it. It writes a scoped, own-session-bound token to
2439
+ // $OPENGENI_TOOLSPACE_TOKEN_FILE over the SAME exec channel the clone-seed
2440
+ // uses (off-manifest, value never on the manifest), and it grants no more
2441
+ // than the machine owner's own authority (toolspace:call, this session, turn
2442
+ // TTL, budgeted, approval-tools excluded) — the invariant that makes it safe
2443
+ // to cross to a user machine when the git token is not. It is also the
2444
+ // machine's only path to programmatic tool calling. Seed it (only) here; the
2445
+ // hook list is empty when no toolspace token was minted for this turn.
2446
+ const toolspaceHooks = sandboxToolspaceTokenHooksForAgent(agent);
2447
+ if (toolspaceHooks.length > 0) {
2448
+ await runBeforeAgentStartHooks(setupSession, toolspaceHooks, ownedHookContext);
2449
+ }
2401
2450
  }
2402
2451
  // Keep the decoration as a safety net for any session the SDK does create/resume
2403
2452
  // through the client during this run (it is inert for the provided session).
@@ -144,6 +144,28 @@ export interface SelfhostedImageOutput {
144
144
  * (the turn pauses + retries); it is NOT a hard failure. */
145
145
  export const SELFHOSTED_DEFAULT_TIMEOUT_MS = 30_000;
146
146
 
147
+ /**
148
+ * The ONLY manifest-environment keys exported into a selfhosted machine's exec
149
+ * shell. The manifest env is otherwise NOT consumed by selfhosted exec — the
150
+ * machine owns its own environment, and pushing HOME, GIT_ vars, and the like
151
+ * onto a real computer would clobber it. The toolspace pointers are the exception:
152
+ * `ogtool` (and the token-seed hook) need the non-secret programmatic-calling URL
153
+ * and the token-FILE PATH to reach the tool surface. The token VALUE never rides
154
+ * here — it is seeded to that file off-manifest over the same exec channel.
155
+ */
156
+ const SELFHOSTED_EXEC_ENV_ALLOWLIST = ["OPENGENI_TOOLSPACE_URL", "OPENGENI_TOOLSPACE_TOKEN_FILE"] as const;
157
+
158
+ function selfhostedExecEnv(environment: Record<string, string>): Record<string, string> {
159
+ const env: Record<string, string> = {};
160
+ for (const key of SELFHOSTED_EXEC_ENV_ALLOWLIST) {
161
+ const value = environment[key];
162
+ if (value) {
163
+ env[key] = value;
164
+ }
165
+ }
166
+ return env;
167
+ }
168
+
147
169
  /** The relay-URL shape config the session needs to build a stream endpoint. M8b
148
170
  * wires the real relay deployment behind THIS seam so `buildStreamUrl` works
149
171
  * unchanged behind `resolveExposedPort`. */
@@ -181,9 +203,11 @@ export interface SelfhostedSessionDeps {
181
203
  * session delta; `validateNoEnvironmentDelta` throws "Live sandbox sessions cannot
182
204
  * change manifest environment variables" on ANY env mismatch. So `state.manifest`'s
183
205
  * `environment` MUST EQUAL the turn's environment for the delta to be empty. The
184
- * selfhosted exec routes over NATS and does NOT consume the env, but the manifest
185
- * must carry it for parity. Omitted → `{}` (the negotiation-only / test path,
186
- * which never applies a turn manifest, so there is no delta to validate).
206
+ * selfhosted exec routes over NATS and does NOT consume this env wholesale (the
207
+ * machine owns its own shell), EXCEPT the allowlisted toolspace pointers it
208
+ * exports per exec so `ogtool` works — see SELFHOSTED_EXEC_ENV_ALLOWLIST. The
209
+ * manifest carries the full env for parity. Omitted → `{}` (the negotiation-only
210
+ * / test path, which never applies a turn manifest, so there is no delta).
187
211
  */
188
212
  environment?: Record<string, string>;
189
213
  /**
@@ -340,7 +364,11 @@ export class SelfhostedSession {
340
364
  // SELFHOSTED_VIRTUAL_ROOT). Empty → the session workingDir (itself "" by
341
365
  // default ⇒ the agent runs in its workspace_root).
342
366
  cwd: toMachinePath(args.workdir, this.workingDir),
343
- env: {},
367
+ // The machine owns its own shell environment; the manifest env is NOT
368
+ // exported here. The ONE exception is the non-secret toolspace pointers
369
+ // (URL + token-file path), so a programmatic `ogtool` call and the token-
370
+ // seed hook can find the tool surface. See SELFHOSTED_EXEC_ENV_ALLOWLIST.
371
+ env: selfhostedExecEnv(this.state.environment),
344
372
  stdin: new Uint8Array(0),
345
373
  timeoutMs: 0,
346
374
  };