@opengeni/runtime 0.3.0 → 0.3.1

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/index.d.ts CHANGED
@@ -7,7 +7,8 @@ import { ReasoningEffort, SessionEventType, ResourceRef, ToolRef, Permission } f
7
7
  export { CAPABILITY_DESCRIPTORS, CapabilityDescriptor, DESKTOP_STREAM_PORT, StreamTokenPayload, StreamTokenPayload as StreamTokenPayloadType, TERMINAL_STREAM_PORT } from '@opengeni/contracts';
8
8
  import { Capability, SandboxSessionLike, SandboxSessionState, Manifest, Capabilities, LocalDirLazySkillSource, SandboxClient } from '@openai/agents/sandbox';
9
9
  import OpenAI from 'openai';
10
- export { ActiveBackendResolverDeps, ActiveBackendUnresolvableError, ActivePointer, ChannelAConflictError, ChannelAEmitter, ChannelAExecArgs, ChannelAExecResult, ChannelANotFoundError, ChannelASession, ChannelAUnsupportedError, ChannelAValidationError, ControlRpc, DEFAULT_DESKTOP_GEOMETRY, DISPLAY_STACK_TIMEOUT_MS, DesktopGeometry, DisplayStackError, DisplayStackUnsupportedError, EnsureDisplayStackOptions, EnsureDisplayStackResult, EnsureTerminalServerOptions, EnsureTerminalServerResult, EstablishedSandboxSession, ExposeStreamPortInput, ExposeStreamPortResult, ExposedPortEndpoint, FinalizeRecordingResult, LiveModalSandboxLeaseAttribution, MintStreamTokenInput, MockAgentResponder, MockAgentResponderOptions, MockExecHandler, ModalOrphanSweepResult, ModalSandboxAttribution, NatsControlRpc, NatsRequestConnection, NegotiationContext, NumstatEntry, PROVIDER_REGISTRY, ProviderConstructionContext, ProviderRegistration, RecordingCodec, RecordingContentType, RecordingError, RecordingProcess, RecordingUnavailableError, ResolvedActiveBackend, RoutableBackendSession, RoutableSandbox, RoutingSandboxSession, RoutingSandboxSessionDeps, RoutingTransitionEvent, RoutingUnsupportedError, SELFHOSTED_DEFAULT_TIMEOUT_MS, SELFHOSTED_RECONNECT_WINDOW_MS, SELFHOSTED_RELAY_STREAM_PATH, STREAM_PORT, STREAM_TOKEN_DEFAULT_TTL_SECONDS, SandboxChannelAService, SandboxChannelAServiceOptions, SandboxConfigError, SandboxCreatedCallback, SandboxProviderUnavailableError, SelfhostedApplyDiff, SelfhostedControlError, SelfhostedEditor, SelfhostedEnrollment, SelfhostedExecArgs, SelfhostedExecResult, SelfhostedImageOutput, SelfhostedLivenessState, SelfhostedNegotiationInput, SelfhostedRelayConfig, SelfhostedSandboxClient, SelfhostedSession, SelfhostedSessionBuild, SelfhostedSessionDeps, SelfhostedSessionState, SelfhostedUnavailableReason, StartRecordingInput, StreamPortUnavailableError, TERMINAL_SERVER_TIMEOUT_MS, TerminalServerError, TerminalServerUnsupportedError, agentErrorToControlError, assertDescriptorRegistryInvariants, assertProviderRegistryInvariants, assertSafeRelPath, backendSupportsOs, buildDisplayStackScript, buildSelfhostedBackendSession, buildStreamUrl, buildTerminalServerScript, contentTypeForCodec, createSandboxClient, createSandboxClientForBackend, decodeModalSnapshotId, deletePriorPersistedSnapshot, deleteRecordingArtifacts, deserializeSandboxSessionStateEnvelope, desktopCapableBackend, ensureDisplayStack, ensureTerminalServer, establishSandboxSessionFromEnvelope, exposeStreamPort, extForCodec, isExecSessionLostBanner, isProviderSandboxNotFoundError, isSelfhostedProviderNotFoundError, isWorkspaceEscapeError, makeActiveBackendResolver, mintStreamToken, modalSandboxAttributionEnvironment, modalSandboxAttributionTags, negotiateCapabilities, negotiateSelfhostedCapabilities, offlineAgentError, offlineControlResponse, parseExecBannerSessionId, parseNumstatZ, parsePorcelainV2, parseUnifiedPatch, readRecordingBytes, readWorkspaceArchiveFromEnvelopeSessionState, recordingStorageKey, restoredSandboxSessionStateFromEntry, sandboxStateEntryFromRunState, selectBackend, selfhostedLiveness, serializeEstablishedSandboxEnvelope, setSelfhostedApplyDiff, startRecording, stopRecording, stripExecBanner, subjectFor, sweepModalOrphanSandboxes, tagModalSandbox, tearDownDisplayStack, tearDownTerminalServer, terminateModalSandboxById, timeoutAgentError, timeoutControlResponse, verifyStreamToken } from './sandbox/index.js';
10
+ import { R as RuntimeMetricsHooks } from './index-CSGkld-v.js';
11
+ 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';
11
12
  import 'modal';
12
13
  import '@opengeni/agent-proto';
13
14
 
@@ -65,6 +66,7 @@ declare class SandboxComputer implements Computer {
65
66
  private guardWrite;
66
67
  private shq;
67
68
  screenshot(): Promise<string>;
69
+ private readCmdRaw;
68
70
  private readScreenshotBytes;
69
71
  click(xp: number, yp: number, button: ComputerButton): Promise<void>;
70
72
  doubleClick(xp: number, yp: number): Promise<void>;
@@ -434,6 +436,7 @@ type SandboxFileDownload = {
434
436
  expiresAt?: Date | string;
435
437
  sizeBytes?: number;
436
438
  };
439
+ declare function configureRuntimeMetricsHooks(hooks: RuntimeMetricsHooks | null | undefined): void;
437
440
  type OpenGeniRuntime = {
438
441
  configure: (settings: Settings) => void;
439
442
  resolveTurnModel: (settings: Settings, modelId: string) => ReturnType<typeof resolveTurnModel>;
@@ -446,6 +449,7 @@ type OpenGeniRuntime = {
446
449
  type ProductionRuntimeOverrides = {
447
450
  model?: Model;
448
451
  sandboxClient?: unknown;
452
+ metrics?: RuntimeMetricsHooks;
449
453
  };
450
454
  declare function createProductionAgentRuntime(overrides?: ProductionRuntimeOverrides): OpenGeniRuntime;
451
455
  /**
@@ -455,7 +459,7 @@ declare function createProductionAgentRuntime(overrides?: ProductionRuntimeOverr
455
459
  * the OpenAI-platform path has only a key (the SDK default client is used via
456
460
  * setDefaultOpenAIKey there); the caller then constructs a key-only client.
457
461
  */
458
- declare function buildOpenAIClientFromSettings(settings: Settings): OpenAI;
462
+ declare function buildOpenAIClientFromSettings(settings: Settings, providerId?: string): OpenAI;
459
463
  declare function buildProviderClient(provider: ResolvedModelProvider, settings: Settings): OpenAI;
460
464
  /**
461
465
  * Bind a model id to a provider's OpenAI client as an @openai/agents `Model`
@@ -861,4 +865,4 @@ declare function azureOpenAIDefaultQuery(settings: Pick<Settings, "azureOpenaiAp
861
865
  */
862
866
  declare function lazySkillSourceWithPackSkills(packSkills: PackSkill[]): LocalDirLazySkillSource;
863
867
 
864
- export { type AgentSegmentInput, type BuildAgentOptions, CLIENT_COMPACTION_TRIGGER_FRACTION, COMPACTION_PROMPT, COMPACTION_SUMMARY_MARKER, COMPACT_USER_MESSAGE_MAX_TOKENS, type ClientCompactionDecision, CodexSubscriptionUnavailableError, type CompactionItem, CompactionNeededError, ComputerActionError, ComputerReadOnlyError, type ComputerToolMode, ComputerUnavailableError, type ComputerUseArgs, ComputerUseCapability, type ContextRobustnessFilterOptions, type ElideStaleScreenshotsOptions, type ElideStaleScreenshotsResult, GENESIS_TITLE_DIRECTIVE, type HistoryItem, type ModelResponseUsage, MultiProviderModelProvider, type NormalizedRuntimeEvent, type OpenGeniRuntime, type PackSkill, type PackSkillFile, type PrepareInputOptions, type PrepareToolsOptions, type PreparedAgentInput, type PreparedAgentTools, type ProductionRuntimeOverrides, type RunAgentStreamOptions, SCREENSHOT_OMITTED_PLACEHOLDER, SUMMARY_BUFFER_TOKENS, SUMMARY_PREFIX, SandboxComputer, type SandboxComputerOptions, type SandboxFileDownload, type SandboxLifecycleHook, type SandboxLifecycleHookContext, type SandboxLifecycleHookPhase, USER_MESSAGE_TRUNCATION_MARKER, type WorkspaceEnvironmentContext, agentsErrorRunState, appendGenesisTitleDirective, appendSessionInstructions, applyMissingManifestEntries, azureCliLoginCommand, azureOpenAIDefaultQuery, buildAgentCapabilities, buildCompactionPromptInput, buildCompactionReplacementHistory, buildManifest, buildModelInstance, buildOpenAIClientFromSettings, buildOpenGeniAgent, buildProviderClient, buildSummaryItem, callModelInputFilterForSettings, clientCompactionThresholdTokens, composeAgentInstructions, computerUse, configureOpenAI, contextRobustnessFilterForSettings, coreInstructions, createProductionAgentRuntime, decideClientCompaction, elideStaleScreenshotImages, enforceInputBudget, ensureReadableStreamFrom, estimateItemTokens, estimateTokens, extractResponseOutputText, findCompactionNeededError, findKeepBoundary, isCompactionSummary, isUserMessage, lazySkillSourceWithPackSkills, materializeSandboxFileDownloads, maxTurnsExceededRunState, modelResponseUsageFromSdkEvent, neutralizeToolSearchItemsInSerializedRunState, normalizeComputerCallsFilter, normalizeSdkEvent, normalizeToolOutputForEvent, prefixedMcpToolName, prepareAgentTools, prepareRunInput, renderCompactionPromptInputForChat, repositoryCloneCommand, repositoryUsesSandboxClone, resolveTurnModel, runAgentStream, runAzureCliLoginHook, runBeforeAgentStartHooks, runRepositoryCloneHook, sandboxCommandExitCode, sandboxCommandOutput, sandboxCommandStillRunning, sandboxFileDownloadsForAgent, sandboxLifecycleHooksForIds, sandboxRunAs, sanitizeHistoryItemsForModel, serializeApprovals, stripProviderItemIdsFilter, stripReasoningEncryptedContent, stripReasoningIdentityFromSerializedRunState, summarizeForCompaction, withManifestRefreshOnResume, withSandboxFileDownloads, withSandboxLifecycleHooks, workspaceEnvironmentInstructions };
868
+ export { type AgentSegmentInput, type BuildAgentOptions, CLIENT_COMPACTION_TRIGGER_FRACTION, COMPACTION_PROMPT, COMPACTION_SUMMARY_MARKER, COMPACT_USER_MESSAGE_MAX_TOKENS, type ClientCompactionDecision, CodexSubscriptionUnavailableError, type CompactionItem, CompactionNeededError, ComputerActionError, ComputerReadOnlyError, type ComputerToolMode, ComputerUnavailableError, type ComputerUseArgs, ComputerUseCapability, type ContextRobustnessFilterOptions, type ElideStaleScreenshotsOptions, type ElideStaleScreenshotsResult, GENESIS_TITLE_DIRECTIVE, type HistoryItem, type ModelResponseUsage, MultiProviderModelProvider, type NormalizedRuntimeEvent, type OpenGeniRuntime, type PackSkill, type PackSkillFile, type PrepareInputOptions, type PrepareToolsOptions, type PreparedAgentInput, type PreparedAgentTools, type ProductionRuntimeOverrides, type RunAgentStreamOptions, RuntimeMetricsHooks, SCREENSHOT_OMITTED_PLACEHOLDER, SUMMARY_BUFFER_TOKENS, SUMMARY_PREFIX, SandboxComputer, type SandboxComputerOptions, type SandboxFileDownload, type SandboxLifecycleHook, type SandboxLifecycleHookContext, type SandboxLifecycleHookPhase, USER_MESSAGE_TRUNCATION_MARKER, type WorkspaceEnvironmentContext, agentsErrorRunState, appendGenesisTitleDirective, appendSessionInstructions, applyMissingManifestEntries, azureCliLoginCommand, azureOpenAIDefaultQuery, buildAgentCapabilities, buildCompactionPromptInput, buildCompactionReplacementHistory, buildManifest, buildModelInstance, buildOpenAIClientFromSettings, buildOpenGeniAgent, buildProviderClient, buildSummaryItem, callModelInputFilterForSettings, clientCompactionThresholdTokens, composeAgentInstructions, computerUse, configureOpenAI, configureRuntimeMetricsHooks, contextRobustnessFilterForSettings, coreInstructions, createProductionAgentRuntime, decideClientCompaction, elideStaleScreenshotImages, enforceInputBudget, ensureReadableStreamFrom, estimateItemTokens, estimateTokens, extractResponseOutputText, findCompactionNeededError, findKeepBoundary, isCompactionSummary, isUserMessage, lazySkillSourceWithPackSkills, materializeSandboxFileDownloads, maxTurnsExceededRunState, modelResponseUsageFromSdkEvent, neutralizeToolSearchItemsInSerializedRunState, normalizeComputerCallsFilter, normalizeSdkEvent, normalizeToolOutputForEvent, prefixedMcpToolName, prepareAgentTools, prepareRunInput, renderCompactionPromptInputForChat, repositoryCloneCommand, repositoryUsesSandboxClone, resolveTurnModel, runAgentStream, runAzureCliLoginHook, runBeforeAgentStartHooks, runRepositoryCloneHook, sandboxCommandExitCode, sandboxCommandOutput, sandboxCommandStillRunning, sandboxFileDownloadsForAgent, sandboxLifecycleHooksForIds, sandboxRunAs, sanitizeHistoryItemsForModel, serializeApprovals, stripProviderItemIdsFilter, stripReasoningEncryptedContent, stripReasoningIdentityFromSerializedRunState, summarizeForCompaction, withManifestRefreshOnResume, withSandboxFileDownloads, withSandboxLifecycleHooks, workspaceEnvironmentInstructions };
package/dist/index.js CHANGED
@@ -95,7 +95,7 @@ import {
95
95
  timeoutAgentError,
96
96
  timeoutControlResponse,
97
97
  verifyStreamToken
98
- } from "./chunk-D5KU3QUC.js";
98
+ } from "./chunk-HGQ252FL.js";
99
99
 
100
100
  // src/index.ts
101
101
  import { AGENT_INSTRUCTIONS_CORE_PLACEHOLDER, collectSandboxEnvironment as collectSandboxEnvironment2, contextInputBudgetTokens, contextServerCompactThreshold, firstPartyMcpBaseUrl, resolveContextCompactionMode, resolveModelProvider, sandboxLifecycleHookIds } from "@opengeni/config";
@@ -116,6 +116,7 @@ import {
116
116
  setDefaultOpenAIClient,
117
117
  setDefaultOpenAIKey,
118
118
  setOpenAIResponsesTransport,
119
+ setTracingDisabled,
119
120
  webSearchTool,
120
121
  applyDiff
121
122
  } from "@openai/agents";
@@ -145,6 +146,9 @@ import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "
145
146
  import { dirname, isAbsolute, join, posix as posixPath, relative } from "path";
146
147
  import { fileURLToPath } from "url";
147
148
 
149
+ // src/screenshot-error-card.ts
150
+ var SCREENSHOT_FAILURE_CARD_IMAGE_URL = "data:image/png;base64,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";
151
+
148
152
  // src/history-sanitizer.ts
149
153
  var RESULT_TYPE_BY_CALL_TYPE = {
150
154
  function_call: "function_call_result",
@@ -466,7 +470,6 @@ function rewriteComputerCallsToActionsOnly(body) {
466
470
  }
467
471
  return changed;
468
472
  }
469
- var EMPTY_IMAGE_URL_PLACEHOLDER = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==";
470
473
  function rewriteEmptyComputerCallOutputImageUrls(body) {
471
474
  if (!body || typeof body !== "object") {
472
475
  return false;
@@ -491,7 +494,7 @@ function rewriteEmptyComputerCallOutputImageUrls(body) {
491
494
  const out = output;
492
495
  const imageUrl = out.image_url;
493
496
  if (typeof imageUrl !== "string" || imageUrl.length === 0) {
494
- out.image_url = EMPTY_IMAGE_URL_PLACEHOLDER;
497
+ out.image_url = SCREENSHOT_FAILURE_CARD_IMAGE_URL;
495
498
  changed = true;
496
499
  }
497
500
  }
@@ -1091,6 +1094,7 @@ var SCROLL_NOTCH_PIXELS = 100;
1091
1094
  var SCROLL_MAX_CLICKS = 15;
1092
1095
  var SCREENSHOT_WARMUP_BUDGET_MS = 3e4;
1093
1096
  var SCREENSHOT_RETRY_DELAY_MS = 750;
1097
+ var SCREENSHOT_READ_CHUNK_BYTES = 98304;
1094
1098
  var KEYSYM = {
1095
1099
  ctrl: "ctrl",
1096
1100
  control: "ctrl",
@@ -1131,6 +1135,12 @@ var ComputerUnavailableError = class extends Error {
1131
1135
  this.name = "ComputerUnavailableError";
1132
1136
  }
1133
1137
  };
1138
+ var ScreenshotReadError = class extends Error {
1139
+ constructor(message) {
1140
+ super(message);
1141
+ this.name = "ScreenshotReadError";
1142
+ }
1143
+ };
1134
1144
  var ComputerReadOnlyError = class extends Error {
1135
1145
  constructor() {
1136
1146
  super("computer-use is read-only \u2014 write actions are disabled");
@@ -1234,6 +1244,9 @@ var SandboxComputer = class {
1234
1244
  return Buffer.from(bytes).toString("base64");
1235
1245
  } catch (error) {
1236
1246
  lastError = error;
1247
+ if (error instanceof ScreenshotReadError) {
1248
+ throw error;
1249
+ }
1237
1250
  } finally {
1238
1251
  await this.x(`rm -f ${f}`).catch(() => void 0);
1239
1252
  }
@@ -1246,34 +1259,66 @@ var SandboxComputer = class {
1246
1259
  }
1247
1260
  throw new ComputerUnavailableError("scrot produced an empty screenshot (display not up?)");
1248
1261
  }
1249
- // Read the screenshot PNG bytes by base64-ing the absolute /tmp path through the
1250
- // SAME command primitive (exec ?? execCommand) — NOT `session.readFile` (Modal
1262
+ // Run a read-only command over the SAME command primitive computer actions use
1263
+ // (exec ?? execCommand) and return its RAW stdout body — NOT `session.readFile` (Modal
1251
1264
  // path-validates against /workspace and rejects /tmp) and NOT `this.x()` (its
1252
- // `sandboxCommandOutput` parser drops the execCommand STRING body, returning ""
1253
- // only the exec-object path has a structured body). We capture the RAW result,
1254
- // strip the execCommand banner ("…Output:\n<base64>"), strip whitespace, and
1255
- // decode. Binary-safe: base64 of the scrot is plain ASCII over stdout, no
1256
- // truncation (maxOutputTokens:null), mirroring recording.ts readRecordingBytes.
1257
- async readScreenshotBytes(path) {
1265
+ // `sandboxCommandOutput` parser drops the execCommand STRING body). exec exposes a
1266
+ // structured stdout; execCommand returns the formatted STRING, so we strip its banner
1267
+ // ("…Output:\n<body>") to recover the body.
1268
+ //
1269
+ // ROUTING-PROXY SEAM: when the selfhosted feature is on, the turn's box is wrapped in a
1270
+ // `RoutingSandboxSession`, which ALWAYS exposes an `exec` method — but for a Modal-backed
1271
+ // box (no native `exec`) that method internally falls back to `execCommand` and returns
1272
+ // the formatted STRING, not a `{output}` object. `sandboxCommandOutput` returns "" for a
1273
+ // string, so a naive `sandboxCommandOutput(await session.exec())` silently dropped the
1274
+ // whole screenshot body → empty read → "display not up" error card on EVERY Modal
1275
+ // computer-use turn once routing was enabled. So a STRING exec result is banner-stripped
1276
+ // exactly like the direct execCommand path; only a structured object goes to
1277
+ // sandboxCommandOutput.
1278
+ async readCmdRaw(cmd) {
1258
1279
  const args = {
1259
- cmd: `DISPLAY=${this.display} base64 ${path}`,
1280
+ cmd,
1260
1281
  ...this.runAs ? { runAs: this.runAs } : {},
1261
1282
  yieldTimeMs: ACTION_YIELD_MS,
1262
- // null disables the provider's output truncation so a full-screen PNG's
1263
- // base64 is never clipped (the SDK's truncateOutput passes through on null).
1283
+ // null disables the provider's TOKEN truncation; the byte cap this method chunks
1284
+ // around is a separate, lower-level exec-stdout buffer limit.
1264
1285
  maxOutputTokens: null
1265
1286
  };
1266
- let raw;
1267
1287
  if (typeof this.session.exec === "function") {
1268
- raw = sandboxCommandOutput(await this.session.exec(args));
1269
- } else if (typeof this.session.execCommand === "function") {
1270
- raw = stripExecBanner(await this.session.execCommand(args));
1271
- } else {
1272
- throw new ComputerUnavailableError("session cannot run commands (no exec/execCommand) \u2014 screenshots unavailable");
1288
+ const result = await this.session.exec(args);
1289
+ return typeof result === "string" ? stripExecBanner(result) : sandboxCommandOutput(result);
1290
+ }
1291
+ if (typeof this.session.execCommand === "function") {
1292
+ return stripExecBanner(await this.session.execCommand(args));
1273
1293
  }
1274
- const b64 = raw.replace(/\s+/g, "");
1275
- if (b64.length === 0) return new Uint8Array();
1276
- return Uint8Array.from(Buffer.from(b64, "base64"));
1294
+ throw new ComputerUnavailableError("session cannot run commands (no exec/execCommand) \u2014 screenshots unavailable");
1295
+ }
1296
+ // Read the screenshot PNG bytes off the box. A SINGLE `base64 <file>` over Modal's
1297
+ // exec silently returns "" once the base64 exceeds the exec-stdout buffer cap (a full
1298
+ // desktop ~296 KB base64 trips it — the blank-frame incident). So we size the file
1299
+ // first, then base64 it in SCREENSHOT_READ_CHUNK_BYTES-sized, 3-byte-aligned chunks
1300
+ // (each read's base64 stays well under the cap) and reconstruct — validating the total
1301
+ // against the on-box size and failing LOUD on any short read rather than handing back a
1302
+ // truncated/blank frame. Binary-safe: base64 is plain ASCII over stdout.
1303
+ async readScreenshotBytes(path) {
1304
+ const sizeRaw = (await this.readCmdRaw(`wc -c < ${path} 2>/dev/null`)).replace(/[^0-9]/g, "");
1305
+ const fileSize = Number.parseInt(sizeRaw, 10);
1306
+ if (!Number.isFinite(fileSize) || fileSize <= 0) return new Uint8Array();
1307
+ const chunks = [];
1308
+ const nChunks = Math.ceil(fileSize / SCREENSHOT_READ_CHUNK_BYTES);
1309
+ for (let i = 0; i < nChunks; i++) {
1310
+ const raw = await this.readCmdRaw(
1311
+ `dd if=${path} bs=${SCREENSHOT_READ_CHUNK_BYTES} skip=${i} count=1 2>/dev/null | base64`
1312
+ );
1313
+ chunks.push(Buffer.from(raw.replace(/\s+/g, ""), "base64"));
1314
+ }
1315
+ const bytes = Buffer.concat(chunks);
1316
+ if (bytes.length !== fileSize) {
1317
+ throw new ScreenshotReadError(
1318
+ `screenshot read reconstructed ${bytes.length}B of ${fileSize}B (${nChunks} chunk(s), path=${path}) \u2014 a chunk was truncated by the exec-output cap; frame incomplete`
1319
+ );
1320
+ }
1321
+ return new Uint8Array(bytes);
1277
1322
  }
1278
1323
  async click(xp, yp, button) {
1279
1324
  this.guardWrite();
@@ -1328,11 +1373,19 @@ var POINTER_BUTTON = {
1328
1373
  back: PointerButton.POINTER_BUTTON_UNSPECIFIED,
1329
1374
  forward: PointerButton.POINTER_BUTTON_UNSPECIFIED
1330
1375
  };
1376
+ var NATIVE_SCREENSHOT_WARMUP_BUDGET_MS = 6e3;
1377
+ var NATIVE_SCREENSHOT_RETRY_DELAY_MS = 400;
1378
+ function isTerminalCaptureDenial(error) {
1379
+ const msg = (error instanceof Error ? error.message : String(error ?? "")).toLowerCase();
1380
+ return msg.includes("screen recording") || msg.includes("permission is not granted") || msg.includes("consent");
1381
+ }
1331
1382
  var NativeDesktopComputer = class {
1332
1383
  environment;
1333
1384
  dimensions;
1334
1385
  session;
1335
1386
  readOnly;
1387
+ screenshotWarmupBudgetMs;
1388
+ screenshotRetryDelayMs;
1336
1389
  // The ENCODED vs NATIVE geometry of the MOST RECENT screenshot the model saw. The
1337
1390
  // model computes click coordinates in the encoded-pixel space of that screenshot;
1338
1391
  // when the agent downscaled the PNG to fit the transport budget, encoded < native,
@@ -1347,6 +1400,8 @@ var NativeDesktopComputer = class {
1347
1400
  this.dimensions = opts.dimensions ?? DEFAULT_DIMENSIONS;
1348
1401
  this.environment = opts.environment ?? "ubuntu";
1349
1402
  this.readOnly = opts.readOnly ?? false;
1403
+ this.screenshotWarmupBudgetMs = opts.screenshotWarmupBudgetMs ?? NATIVE_SCREENSHOT_WARMUP_BUDGET_MS;
1404
+ this.screenshotRetryDelayMs = opts.screenshotRetryDelayMs ?? NATIVE_SCREENSHOT_RETRY_DELAY_MS;
1350
1405
  }
1351
1406
  /** Rebind to a freshly resumed-by-id session after a box rollover / re-establish. */
1352
1407
  rebind(session) {
@@ -1376,13 +1431,36 @@ var NativeDesktopComputer = class {
1376
1431
  await this.session.desktopInput({ $case: "pointer", pointer: { x: n.x, y: n.y, action, button } });
1377
1432
  }
1378
1433
  async screenshot() {
1379
- const { png, width, height, nativeWidth, nativeHeight } = await this.session.screenshot();
1380
- if (png.length === 0) {
1381
- throw new ComputerUnavailableError("native desktop screenshot returned an empty frame (display not up?)");
1434
+ let lastError;
1435
+ const deadline = Date.now() + this.screenshotWarmupBudgetMs;
1436
+ let attempt = 0;
1437
+ while (true) {
1438
+ if (attempt > 0) {
1439
+ await new Promise((r) => setTimeout(r, this.screenshotRetryDelayMs));
1440
+ }
1441
+ attempt++;
1442
+ try {
1443
+ const { png, width, height, nativeWidth, nativeHeight } = await this.session.screenshot();
1444
+ if (png.length === 0) {
1445
+ throw new ComputerUnavailableError("native desktop screenshot returned an empty frame (display not up?)");
1446
+ }
1447
+ this.lastEncoded = [width, height];
1448
+ this.lastNative = [nativeWidth || width, nativeHeight || height];
1449
+ return Buffer.from(png).toString("base64");
1450
+ } catch (error) {
1451
+ lastError = error;
1452
+ if (isTerminalCaptureDenial(error)) break;
1453
+ }
1454
+ if (Date.now() + this.screenshotRetryDelayMs >= deadline) {
1455
+ break;
1456
+ }
1382
1457
  }
1383
- this.lastEncoded = [width, height];
1384
- this.lastNative = [nativeWidth || width, nativeHeight || height];
1385
- return Buffer.from(png).toString("base64");
1458
+ const reason = lastError instanceof Error ? lastError.message : String(lastError);
1459
+ console.warn(`[NativeDesktopComputer] screenshot failed after ${attempt} attempt(s): ${reason}`);
1460
+ if (lastError instanceof Error) {
1461
+ throw lastError;
1462
+ }
1463
+ throw new ComputerUnavailableError("native desktop screenshot returned an empty frame (display not up?)");
1386
1464
  }
1387
1465
  async click(x, y, button) {
1388
1466
  this.guardWrite();
@@ -1668,9 +1746,16 @@ function ensureReadableStreamFrom() {
1668
1746
  }
1669
1747
  });
1670
1748
  }
1749
+ var runtimeMetricsHooks = null;
1750
+ function configureRuntimeMetricsHooks(hooks) {
1751
+ runtimeMetricsHooks = hooks ?? null;
1752
+ }
1671
1753
  function createProductionAgentRuntime(overrides = {}) {
1672
1754
  return {
1673
- configure: configureOpenAI,
1755
+ configure: (settings) => {
1756
+ configureRuntimeMetricsHooks(overrides.metrics);
1757
+ configureOpenAI(settings);
1758
+ },
1674
1759
  // A test/override model shadows the registry routing entirely (the scripted
1675
1760
  // model used in worker tests is not in any provider's allow-list), so when
1676
1761
  // one is supplied resolveTurnModel reports "no resolution" and the caller
@@ -1689,7 +1774,7 @@ function createProductionAgentRuntime(overrides = {}) {
1689
1774
  serializeApprovals
1690
1775
  };
1691
1776
  }
1692
- function buildOpenAIClientFromSettings(settings) {
1777
+ function buildOpenAIClientFromSettings(settings, providerId = settings.openaiProvider) {
1693
1778
  if (settings.openaiProvider === "azure") {
1694
1779
  const baseURL = settings.azureOpenaiBaseUrl ?? azureDeploymentBaseUrl(settings);
1695
1780
  const apiKey = settings.azureOpenaiApiKey ?? settings.azureOpenaiAdToken ?? "azure-ad-token";
@@ -1704,13 +1789,14 @@ function buildOpenAIClientFromSettings(settings) {
1704
1789
  // seam — below the SDK responses converter, which always re-synthesizes BOTH
1705
1790
  // `action` and `actions` (rejected 400 "exactly one of action or actions").
1706
1791
  // See computerCallNormalizingFetch / rewriteComputerCallsToActionsOnly.
1707
- fetch: computerCallNormalizingFetch(globalThis.fetch)
1792
+ fetch: computerCallNormalizingFetch(instrumentedModelFetch(providerId, globalThis.fetch))
1708
1793
  });
1709
1794
  }
1710
1795
  return new OpenAI({
1711
1796
  apiKey: settings.openaiApiKey ?? process.env.OPENAI_API_KEY,
1712
1797
  ...settings.openaiBaseUrl ? { baseURL: settings.openaiBaseUrl } : {},
1713
- maxRetries: settings.openaiMaxRetries
1798
+ maxRetries: settings.openaiMaxRetries,
1799
+ fetch: instrumentedModelFetch(providerId, globalThis.fetch)
1714
1800
  });
1715
1801
  }
1716
1802
  var providerClientCache = /* @__PURE__ */ new Map();
@@ -1719,17 +1805,18 @@ function buildProviderClient(provider, settings) {
1719
1805
  if (cached) {
1720
1806
  return cached;
1721
1807
  }
1722
- const client = provider.builtin ? buildOpenAIClientFromSettings(settings) : provider.kind === "codex-subscription" ? new OpenAI({
1808
+ const client = provider.builtin ? buildOpenAIClientFromSettings(settings, provider.id) : provider.kind === "codex-subscription" ? new OpenAI({
1723
1809
  apiKey: provider.apiKey ?? "codex-subscription",
1724
1810
  ...provider.baseUrl ? { baseURL: provider.baseUrl } : {},
1725
1811
  maxRetries: settings.openaiMaxRetries,
1726
- fetch: codexSubscriptionFetch(globalThis.fetch)
1812
+ fetch: codexSubscriptionFetch(instrumentedModelFetch(provider.id, globalThis.fetch))
1727
1813
  }) : new OpenAI({
1728
1814
  ...provider.apiKey ? { apiKey: provider.apiKey } : {},
1729
1815
  ...provider.baseUrl ? { baseURL: provider.baseUrl } : {},
1730
1816
  maxRetries: settings.openaiMaxRetries,
1731
1817
  ...provider.defaultQuery ? { defaultQuery: provider.defaultQuery } : {},
1732
- ...provider.defaultHeaders ? { defaultHeaders: provider.defaultHeaders } : {}
1818
+ ...provider.defaultHeaders ? { defaultHeaders: provider.defaultHeaders } : {},
1819
+ fetch: instrumentedModelFetch(provider.id, globalThis.fetch)
1733
1820
  });
1734
1821
  providerClientCache.set(provider.id, client);
1735
1822
  return client;
@@ -1797,6 +1884,7 @@ var CodexSubscriptionUnavailableError = class extends Error {
1797
1884
  };
1798
1885
  function configureOpenAI(settings) {
1799
1886
  setOpenAIResponsesTransport(settings.openaiResponsesTransport);
1887
+ setTracingDisabled(settings.disableOpenaiTracing || !settings.observabilityOtlpEndpoint);
1800
1888
  const router = new MultiProviderModelProvider(settings);
1801
1889
  if (settings.openaiProvider === "azure") {
1802
1890
  setDefaultOpenAIClient(buildOpenAIClientFromSettings(settings));
@@ -1811,6 +1899,41 @@ function configureOpenAI(settings) {
1811
1899
  }
1812
1900
  setDefaultModelProvider(router);
1813
1901
  }
1902
+ function instrumentedModelFetch(provider, inner) {
1903
+ return (async (input, init) => {
1904
+ if (!isModelCallFetch(input)) {
1905
+ return await inner(input, init);
1906
+ }
1907
+ const started = performance.now();
1908
+ try {
1909
+ const response = await inner(input, init);
1910
+ recordModelCallMetric(provider, response.ok ? "completed" : "failed", started);
1911
+ return response;
1912
+ } catch (error) {
1913
+ recordModelCallMetric(provider, "failed", started);
1914
+ throw error;
1915
+ }
1916
+ });
1917
+ }
1918
+ function isModelCallFetch(input) {
1919
+ const rawUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
1920
+ if (typeof rawUrl !== "string" || rawUrl.length === 0) {
1921
+ return false;
1922
+ }
1923
+ try {
1924
+ const pathname = new URL(rawUrl, "http://opengeni.local").pathname;
1925
+ return pathname.endsWith("/responses") || pathname.endsWith("/chat/completions") || pathname.endsWith("/codex/responses");
1926
+ } catch {
1927
+ return /\/(?:codex\/)?responses(?:\?|$)|\/chat\/completions(?:\?|$)/.test(rawUrl);
1928
+ }
1929
+ }
1930
+ function recordModelCallMetric(provider, outcome, started) {
1931
+ const durationSeconds = Math.max(0, (performance.now() - started) / 1e3);
1932
+ try {
1933
+ runtimeMetricsHooks?.onModelCall?.({ provider, outcome, durationSeconds });
1934
+ } catch {
1935
+ }
1936
+ }
1814
1937
  async function summarizeForCompaction(settings, input, options = {}) {
1815
1938
  const client = options.client ?? buildOpenAIClientFromSettings(settings);
1816
1939
  const api = options.api ?? "responses";
@@ -2582,7 +2705,6 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
2582
2705
  // every mid-turn follow-up.
2583
2706
  callModelInputFilter
2584
2707
  };
2585
- void settings.disableOpenaiTracing;
2586
2708
  if (client) {
2587
2709
  runOptions.sandbox = {
2588
2710
  client,
@@ -3835,6 +3957,7 @@ export {
3835
3957
  composeAgentInstructions,
3836
3958
  computerUse,
3837
3959
  configureOpenAI,
3960
+ configureRuntimeMetricsHooks,
3838
3961
  contentTypeForCodec,
3839
3962
  contextRobustnessFilterForSettings,
3840
3963
  coreInstructions,