@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/{chunk-D5KU3QUC.js → chunk-HGQ252FL.js} +22 -3
- package/dist/chunk-HGQ252FL.js.map +1 -0
- package/dist/index-CSGkld-v.d.ts +1801 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +160 -37
- package/dist/index.js.map +1 -1
- package/dist/sandbox/index.d.ts +4 -1784
- package/dist/sandbox/index.js +1 -1
- package/package.json +3 -3
- package/src/history-sanitizer.ts +35 -38
- package/src/index.ts +67 -6
- package/src/metrics.ts +5 -0
- package/src/sandbox/display-stack.ts +25 -4
- package/src/sandbox/index.ts +28 -1
- package/src/sandbox-computer.ts +167 -36
- package/src/screenshot-error-card.ts +25 -0
- package/dist/chunk-D5KU3QUC.js.map +0 -1
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
|
-
|
|
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-
|
|
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 =
|
|
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
|
-
//
|
|
1250
|
-
//
|
|
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
|
|
1253
|
-
//
|
|
1254
|
-
//
|
|
1255
|
-
//
|
|
1256
|
-
//
|
|
1257
|
-
|
|
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
|
|
1280
|
+
cmd,
|
|
1260
1281
|
...this.runAs ? { runAs: this.runAs } : {},
|
|
1261
1282
|
yieldTimeMs: ACTION_YIELD_MS,
|
|
1262
|
-
// null disables the provider's
|
|
1263
|
-
//
|
|
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
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
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
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
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
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
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
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
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:
|
|
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,
|