@opengeni/runtime 0.2.3 → 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-KNW7AMQB.js → chunk-HGQ252FL.js} +251 -22
- package/dist/chunk-HGQ252FL.js.map +1 -0
- package/dist/index-CSGkld-v.d.ts +1801 -0
- package/dist/index.d.ts +23 -3
- package/dist/index.js +238 -39
- package/dist/index.js.map +1 -1
- package/dist/sandbox/index.d.ts +4 -1738
- package/dist/sandbox/index.js +11 -1
- package/package.json +3 -3
- package/src/history-sanitizer.ts +35 -38
- package/src/index.ts +133 -10
- package/src/metrics.ts +5 -0
- package/src/sandbox/display-stack.ts +69 -13
- package/src/sandbox/index.ts +100 -13
- package/src/sandbox/providers/modal.ts +225 -0
- package/src/sandbox/routing/routing-session.ts +2 -2
- package/src/sandbox/selfhosted/session.ts +21 -5
- package/src/sandbox-computer.ts +214 -48
- package/src/screenshot-error-card.ts +25 -0
- package/dist/chunk-KNW7AMQB.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,9 @@ 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';
|
|
12
|
+
import 'modal';
|
|
11
13
|
import '@opengeni/agent-proto';
|
|
12
14
|
|
|
13
15
|
type ComputerButton = "left" | "right" | "wheel" | "back" | "forward";
|
|
@@ -64,6 +66,7 @@ declare class SandboxComputer implements Computer {
|
|
|
64
66
|
private guardWrite;
|
|
65
67
|
private shq;
|
|
66
68
|
screenshot(): Promise<string>;
|
|
69
|
+
private readCmdRaw;
|
|
67
70
|
private readScreenshotBytes;
|
|
68
71
|
click(xp: number, yp: number, button: ComputerButton): Promise<void>;
|
|
69
72
|
doubleClick(xp: number, yp: number): Promise<void>;
|
|
@@ -433,6 +436,7 @@ type SandboxFileDownload = {
|
|
|
433
436
|
expiresAt?: Date | string;
|
|
434
437
|
sizeBytes?: number;
|
|
435
438
|
};
|
|
439
|
+
declare function configureRuntimeMetricsHooks(hooks: RuntimeMetricsHooks | null | undefined): void;
|
|
436
440
|
type OpenGeniRuntime = {
|
|
437
441
|
configure: (settings: Settings) => void;
|
|
438
442
|
resolveTurnModel: (settings: Settings, modelId: string) => ReturnType<typeof resolveTurnModel>;
|
|
@@ -445,6 +449,7 @@ type OpenGeniRuntime = {
|
|
|
445
449
|
type ProductionRuntimeOverrides = {
|
|
446
450
|
model?: Model;
|
|
447
451
|
sandboxClient?: unknown;
|
|
452
|
+
metrics?: RuntimeMetricsHooks;
|
|
448
453
|
};
|
|
449
454
|
declare function createProductionAgentRuntime(overrides?: ProductionRuntimeOverrides): OpenGeniRuntime;
|
|
450
455
|
/**
|
|
@@ -454,7 +459,7 @@ declare function createProductionAgentRuntime(overrides?: ProductionRuntimeOverr
|
|
|
454
459
|
* the OpenAI-platform path has only a key (the SDK default client is used via
|
|
455
460
|
* setDefaultOpenAIKey there); the caller then constructs a key-only client.
|
|
456
461
|
*/
|
|
457
|
-
declare function buildOpenAIClientFromSettings(settings: Settings): OpenAI;
|
|
462
|
+
declare function buildOpenAIClientFromSettings(settings: Settings, providerId?: string): OpenAI;
|
|
458
463
|
declare function buildProviderClient(provider: ResolvedModelProvider, settings: Settings): OpenAI;
|
|
459
464
|
/**
|
|
460
465
|
* Bind a model id to a provider's OpenAI client as an @openai/agents `Model`
|
|
@@ -569,6 +574,7 @@ type BuildAgentOptions = {
|
|
|
569
574
|
gitTokenSeed?: string;
|
|
570
575
|
genesisTitleHint?: boolean;
|
|
571
576
|
instructionsTemplate?: string;
|
|
577
|
+
sessionInstructions?: string;
|
|
572
578
|
packSkills?: PackSkill[];
|
|
573
579
|
};
|
|
574
580
|
type PackSkillFile = {
|
|
@@ -615,6 +621,20 @@ declare function coreInstructions(workspaceEnvironment?: WorkspaceEnvironmentCon
|
|
|
615
621
|
* with an empty environment reproduces the historical preamble byte-for-byte.
|
|
616
622
|
*/
|
|
617
623
|
declare function composeAgentInstructions(template: string, workspaceEnvironment?: WorkspaceEnvironmentContext): string;
|
|
624
|
+
/**
|
|
625
|
+
* Appends the per-session persona instructions to the already-composed
|
|
626
|
+
* (workspace + CORE) instructions, joined by " " — exactly the join used
|
|
627
|
+
* throughout the persona composition. The session slice is intentionally LAST
|
|
628
|
+
* (session-specific refinement of the workspace persona). An absent/blank value
|
|
629
|
+
* is a no-op that returns the composed string byte-for-byte.
|
|
630
|
+
*/
|
|
631
|
+
declare function appendSessionInstructions(composed: string, sessionInstructions?: string): string;
|
|
632
|
+
/**
|
|
633
|
+
* Appends the one-shot genesis title directive (genesis turn only), joined by
|
|
634
|
+
* " " and always LAST so a white-label persona template or a per-session
|
|
635
|
+
* instruction can't drop it. A no-op when the hint is absent.
|
|
636
|
+
*/
|
|
637
|
+
declare function appendGenesisTitleDirective(instructions: string, genesisTitleHint?: boolean): string;
|
|
618
638
|
declare function buildOpenGeniAgent(settings: Settings, resources: ResourceRef[], options?: BuildAgentOptions): Agent<any, any>;
|
|
619
639
|
/**
|
|
620
640
|
* Build the SandboxAgent capability set provider-aware.
|
|
@@ -845,4 +865,4 @@ declare function azureOpenAIDefaultQuery(settings: Pick<Settings, "azureOpenaiAp
|
|
|
845
865
|
*/
|
|
846
866
|
declare function lazySkillSourceWithPackSkills(packSkills: PackSkill[]): LocalDirLazySkillSource;
|
|
847
867
|
|
|
848
|
-
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, 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
|
@@ -63,6 +63,8 @@ import {
|
|
|
63
63
|
isWorkspaceEscapeError,
|
|
64
64
|
makeActiveBackendResolver,
|
|
65
65
|
mintStreamToken,
|
|
66
|
+
modalSandboxAttributionEnvironment,
|
|
67
|
+
modalSandboxAttributionTags,
|
|
66
68
|
negotiateCapabilities,
|
|
67
69
|
negotiateSelfhostedCapabilities,
|
|
68
70
|
offlineAgentError,
|
|
@@ -85,12 +87,15 @@ import {
|
|
|
85
87
|
stopRecording,
|
|
86
88
|
stripExecBanner,
|
|
87
89
|
subjectFor,
|
|
90
|
+
sweepModalOrphanSandboxes,
|
|
91
|
+
tagModalSandbox,
|
|
88
92
|
tearDownDisplayStack,
|
|
89
93
|
tearDownTerminalServer,
|
|
94
|
+
terminateModalSandboxById,
|
|
90
95
|
timeoutAgentError,
|
|
91
96
|
timeoutControlResponse,
|
|
92
97
|
verifyStreamToken
|
|
93
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-HGQ252FL.js";
|
|
94
99
|
|
|
95
100
|
// src/index.ts
|
|
96
101
|
import { AGENT_INSTRUCTIONS_CORE_PLACEHOLDER, collectSandboxEnvironment as collectSandboxEnvironment2, contextInputBudgetTokens, contextServerCompactThreshold, firstPartyMcpBaseUrl, resolveContextCompactionMode, resolveModelProvider, sandboxLifecycleHookIds } from "@opengeni/config";
|
|
@@ -111,6 +116,7 @@ import {
|
|
|
111
116
|
setDefaultOpenAIClient,
|
|
112
117
|
setDefaultOpenAIKey,
|
|
113
118
|
setOpenAIResponsesTransport,
|
|
119
|
+
setTracingDisabled,
|
|
114
120
|
webSearchTool,
|
|
115
121
|
applyDiff
|
|
116
122
|
} from "@openai/agents";
|
|
@@ -140,6 +146,9 @@ import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "
|
|
|
140
146
|
import { dirname, isAbsolute, join, posix as posixPath, relative } from "path";
|
|
141
147
|
import { fileURLToPath } from "url";
|
|
142
148
|
|
|
149
|
+
// src/screenshot-error-card.ts
|
|
150
|
+
var SCREENSHOT_FAILURE_CARD_IMAGE_URL = "data:image/png;base64,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";
|
|
151
|
+
|
|
143
152
|
// src/history-sanitizer.ts
|
|
144
153
|
var RESULT_TYPE_BY_CALL_TYPE = {
|
|
145
154
|
function_call: "function_call_result",
|
|
@@ -461,7 +470,6 @@ function rewriteComputerCallsToActionsOnly(body) {
|
|
|
461
470
|
}
|
|
462
471
|
return changed;
|
|
463
472
|
}
|
|
464
|
-
var EMPTY_IMAGE_URL_PLACEHOLDER = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==";
|
|
465
473
|
function rewriteEmptyComputerCallOutputImageUrls(body) {
|
|
466
474
|
if (!body || typeof body !== "object") {
|
|
467
475
|
return false;
|
|
@@ -486,7 +494,7 @@ function rewriteEmptyComputerCallOutputImageUrls(body) {
|
|
|
486
494
|
const out = output;
|
|
487
495
|
const imageUrl = out.image_url;
|
|
488
496
|
if (typeof imageUrl !== "string" || imageUrl.length === 0) {
|
|
489
|
-
out.image_url =
|
|
497
|
+
out.image_url = SCREENSHOT_FAILURE_CARD_IMAGE_URL;
|
|
490
498
|
changed = true;
|
|
491
499
|
}
|
|
492
500
|
}
|
|
@@ -1086,6 +1094,7 @@ var SCROLL_NOTCH_PIXELS = 100;
|
|
|
1086
1094
|
var SCROLL_MAX_CLICKS = 15;
|
|
1087
1095
|
var SCREENSHOT_WARMUP_BUDGET_MS = 3e4;
|
|
1088
1096
|
var SCREENSHOT_RETRY_DELAY_MS = 750;
|
|
1097
|
+
var SCREENSHOT_READ_CHUNK_BYTES = 98304;
|
|
1089
1098
|
var KEYSYM = {
|
|
1090
1099
|
ctrl: "ctrl",
|
|
1091
1100
|
control: "ctrl",
|
|
@@ -1126,6 +1135,12 @@ var ComputerUnavailableError = class extends Error {
|
|
|
1126
1135
|
this.name = "ComputerUnavailableError";
|
|
1127
1136
|
}
|
|
1128
1137
|
};
|
|
1138
|
+
var ScreenshotReadError = class extends Error {
|
|
1139
|
+
constructor(message) {
|
|
1140
|
+
super(message);
|
|
1141
|
+
this.name = "ScreenshotReadError";
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1129
1144
|
var ComputerReadOnlyError = class extends Error {
|
|
1130
1145
|
constructor() {
|
|
1131
1146
|
super("computer-use is read-only \u2014 write actions are disabled");
|
|
@@ -1229,6 +1244,9 @@ var SandboxComputer = class {
|
|
|
1229
1244
|
return Buffer.from(bytes).toString("base64");
|
|
1230
1245
|
} catch (error) {
|
|
1231
1246
|
lastError = error;
|
|
1247
|
+
if (error instanceof ScreenshotReadError) {
|
|
1248
|
+
throw error;
|
|
1249
|
+
}
|
|
1232
1250
|
} finally {
|
|
1233
1251
|
await this.x(`rm -f ${f}`).catch(() => void 0);
|
|
1234
1252
|
}
|
|
@@ -1241,34 +1259,66 @@ var SandboxComputer = class {
|
|
|
1241
1259
|
}
|
|
1242
1260
|
throw new ComputerUnavailableError("scrot produced an empty screenshot (display not up?)");
|
|
1243
1261
|
}
|
|
1244
|
-
//
|
|
1245
|
-
//
|
|
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
|
|
1246
1264
|
// path-validates against /workspace and rejects /tmp) and NOT `this.x()` (its
|
|
1247
|
-
// `sandboxCommandOutput` parser drops the execCommand STRING body
|
|
1248
|
-
//
|
|
1249
|
-
//
|
|
1250
|
-
//
|
|
1251
|
-
//
|
|
1252
|
-
|
|
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) {
|
|
1253
1279
|
const args = {
|
|
1254
|
-
cmd
|
|
1280
|
+
cmd,
|
|
1255
1281
|
...this.runAs ? { runAs: this.runAs } : {},
|
|
1256
1282
|
yieldTimeMs: ACTION_YIELD_MS,
|
|
1257
|
-
// null disables the provider's
|
|
1258
|
-
//
|
|
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.
|
|
1259
1285
|
maxOutputTokens: null
|
|
1260
1286
|
};
|
|
1261
|
-
let raw;
|
|
1262
1287
|
if (typeof this.session.exec === "function") {
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
raw = stripExecBanner(await this.session.execCommand(args));
|
|
1266
|
-
} else {
|
|
1267
|
-
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);
|
|
1268
1290
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1291
|
+
if (typeof this.session.execCommand === "function") {
|
|
1292
|
+
return stripExecBanner(await this.session.execCommand(args));
|
|
1293
|
+
}
|
|
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);
|
|
1272
1322
|
}
|
|
1273
1323
|
async click(xp, yp, button) {
|
|
1274
1324
|
this.guardWrite();
|
|
@@ -1323,16 +1373,35 @@ var POINTER_BUTTON = {
|
|
|
1323
1373
|
back: PointerButton.POINTER_BUTTON_UNSPECIFIED,
|
|
1324
1374
|
forward: PointerButton.POINTER_BUTTON_UNSPECIFIED
|
|
1325
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
|
+
}
|
|
1326
1382
|
var NativeDesktopComputer = class {
|
|
1327
1383
|
environment;
|
|
1328
1384
|
dimensions;
|
|
1329
1385
|
session;
|
|
1330
1386
|
readOnly;
|
|
1387
|
+
screenshotWarmupBudgetMs;
|
|
1388
|
+
screenshotRetryDelayMs;
|
|
1389
|
+
// The ENCODED vs NATIVE geometry of the MOST RECENT screenshot the model saw. The
|
|
1390
|
+
// model computes click coordinates in the encoded-pixel space of that screenshot;
|
|
1391
|
+
// when the agent downscaled the PNG to fit the transport budget, encoded < native,
|
|
1392
|
+
// so we scale coordinates back up to native pixels before injecting (the agent's
|
|
1393
|
+
// native inject — macOS CGEvent / Linux XTEST — expects native-pixel coordinates,
|
|
1394
|
+
// exactly as it received them pre-downscale). Null until the first screenshot;
|
|
1395
|
+
// equal encoded==native (or absent) ⇒ scale factor 1.0 ⇒ byte-identical behavior.
|
|
1396
|
+
lastEncoded = null;
|
|
1397
|
+
lastNative = null;
|
|
1331
1398
|
constructor(session, opts = {}) {
|
|
1332
1399
|
this.session = session;
|
|
1333
1400
|
this.dimensions = opts.dimensions ?? DEFAULT_DIMENSIONS;
|
|
1334
1401
|
this.environment = opts.environment ?? "ubuntu";
|
|
1335
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;
|
|
1336
1405
|
}
|
|
1337
1406
|
/** Rebind to a freshly resumed-by-id session after a box rollover / re-establish. */
|
|
1338
1407
|
rebind(session) {
|
|
@@ -1341,15 +1410,57 @@ var NativeDesktopComputer = class {
|
|
|
1341
1410
|
guardWrite() {
|
|
1342
1411
|
if (this.readOnly) throw new ComputerReadOnlyError();
|
|
1343
1412
|
}
|
|
1413
|
+
/** Scale a coordinate the model expressed in the MOST RECENT screenshot's
|
|
1414
|
+
* ENCODED pixel space back to NATIVE pixels. When the last frame was not
|
|
1415
|
+
* downscaled (encoded == native), or no screenshot has been taken yet, this is a
|
|
1416
|
+
* 1:1 identity — the byte-identical current behavior. The agent then applies its
|
|
1417
|
+
* own platform mapping (macOS divides native pixels by the backing scale to reach
|
|
1418
|
+
* CGEvent points; Linux XTEST is 1:1) exactly as it did pre-downscale. */
|
|
1419
|
+
toNative(x, y) {
|
|
1420
|
+
const enc = this.lastEncoded;
|
|
1421
|
+
const nat = this.lastNative;
|
|
1422
|
+
if (!enc || !nat || enc[0] <= 0 || enc[1] <= 0) return { x, y };
|
|
1423
|
+
if (enc[0] === nat[0] && enc[1] === nat[1]) return { x, y };
|
|
1424
|
+
return {
|
|
1425
|
+
x: Math.round(x * nat[0] / enc[0]),
|
|
1426
|
+
y: Math.round(y * nat[1] / enc[1])
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1344
1429
|
async pointer(x, y, action, button) {
|
|
1345
|
-
|
|
1430
|
+
const n = this.toNative(x, y);
|
|
1431
|
+
await this.session.desktopInput({ $case: "pointer", pointer: { x: n.x, y: n.y, action, button } });
|
|
1346
1432
|
}
|
|
1347
1433
|
async screenshot() {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
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
|
+
}
|
|
1351
1457
|
}
|
|
1352
|
-
|
|
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?)");
|
|
1353
1464
|
}
|
|
1354
1465
|
async click(x, y, button) {
|
|
1355
1466
|
this.guardWrite();
|
|
@@ -1365,7 +1476,8 @@ var NativeDesktopComputer = class {
|
|
|
1365
1476
|
}
|
|
1366
1477
|
async scroll(x, y, sx, sy) {
|
|
1367
1478
|
this.guardWrite();
|
|
1368
|
-
|
|
1479
|
+
const n = this.toNative(x, y);
|
|
1480
|
+
await this.session.desktopInput({ $case: "scroll", scroll: { x: n.x, y: n.y, deltaX: sx, deltaY: sy } });
|
|
1369
1481
|
}
|
|
1370
1482
|
async type(text) {
|
|
1371
1483
|
this.guardWrite();
|
|
@@ -1634,9 +1746,16 @@ function ensureReadableStreamFrom() {
|
|
|
1634
1746
|
}
|
|
1635
1747
|
});
|
|
1636
1748
|
}
|
|
1749
|
+
var runtimeMetricsHooks = null;
|
|
1750
|
+
function configureRuntimeMetricsHooks(hooks) {
|
|
1751
|
+
runtimeMetricsHooks = hooks ?? null;
|
|
1752
|
+
}
|
|
1637
1753
|
function createProductionAgentRuntime(overrides = {}) {
|
|
1638
1754
|
return {
|
|
1639
|
-
configure:
|
|
1755
|
+
configure: (settings) => {
|
|
1756
|
+
configureRuntimeMetricsHooks(overrides.metrics);
|
|
1757
|
+
configureOpenAI(settings);
|
|
1758
|
+
},
|
|
1640
1759
|
// A test/override model shadows the registry routing entirely (the scripted
|
|
1641
1760
|
// model used in worker tests is not in any provider's allow-list), so when
|
|
1642
1761
|
// one is supplied resolveTurnModel reports "no resolution" and the caller
|
|
@@ -1655,7 +1774,7 @@ function createProductionAgentRuntime(overrides = {}) {
|
|
|
1655
1774
|
serializeApprovals
|
|
1656
1775
|
};
|
|
1657
1776
|
}
|
|
1658
|
-
function buildOpenAIClientFromSettings(settings) {
|
|
1777
|
+
function buildOpenAIClientFromSettings(settings, providerId = settings.openaiProvider) {
|
|
1659
1778
|
if (settings.openaiProvider === "azure") {
|
|
1660
1779
|
const baseURL = settings.azureOpenaiBaseUrl ?? azureDeploymentBaseUrl(settings);
|
|
1661
1780
|
const apiKey = settings.azureOpenaiApiKey ?? settings.azureOpenaiAdToken ?? "azure-ad-token";
|
|
@@ -1670,13 +1789,14 @@ function buildOpenAIClientFromSettings(settings) {
|
|
|
1670
1789
|
// seam — below the SDK responses converter, which always re-synthesizes BOTH
|
|
1671
1790
|
// `action` and `actions` (rejected 400 "exactly one of action or actions").
|
|
1672
1791
|
// See computerCallNormalizingFetch / rewriteComputerCallsToActionsOnly.
|
|
1673
|
-
fetch: computerCallNormalizingFetch(globalThis.fetch)
|
|
1792
|
+
fetch: computerCallNormalizingFetch(instrumentedModelFetch(providerId, globalThis.fetch))
|
|
1674
1793
|
});
|
|
1675
1794
|
}
|
|
1676
1795
|
return new OpenAI({
|
|
1677
1796
|
apiKey: settings.openaiApiKey ?? process.env.OPENAI_API_KEY,
|
|
1678
1797
|
...settings.openaiBaseUrl ? { baseURL: settings.openaiBaseUrl } : {},
|
|
1679
|
-
maxRetries: settings.openaiMaxRetries
|
|
1798
|
+
maxRetries: settings.openaiMaxRetries,
|
|
1799
|
+
fetch: instrumentedModelFetch(providerId, globalThis.fetch)
|
|
1680
1800
|
});
|
|
1681
1801
|
}
|
|
1682
1802
|
var providerClientCache = /* @__PURE__ */ new Map();
|
|
@@ -1685,17 +1805,18 @@ function buildProviderClient(provider, settings) {
|
|
|
1685
1805
|
if (cached) {
|
|
1686
1806
|
return cached;
|
|
1687
1807
|
}
|
|
1688
|
-
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({
|
|
1689
1809
|
apiKey: provider.apiKey ?? "codex-subscription",
|
|
1690
1810
|
...provider.baseUrl ? { baseURL: provider.baseUrl } : {},
|
|
1691
1811
|
maxRetries: settings.openaiMaxRetries,
|
|
1692
|
-
fetch: codexSubscriptionFetch(globalThis.fetch)
|
|
1812
|
+
fetch: codexSubscriptionFetch(instrumentedModelFetch(provider.id, globalThis.fetch))
|
|
1693
1813
|
}) : new OpenAI({
|
|
1694
1814
|
...provider.apiKey ? { apiKey: provider.apiKey } : {},
|
|
1695
1815
|
...provider.baseUrl ? { baseURL: provider.baseUrl } : {},
|
|
1696
1816
|
maxRetries: settings.openaiMaxRetries,
|
|
1697
1817
|
...provider.defaultQuery ? { defaultQuery: provider.defaultQuery } : {},
|
|
1698
|
-
...provider.defaultHeaders ? { defaultHeaders: provider.defaultHeaders } : {}
|
|
1818
|
+
...provider.defaultHeaders ? { defaultHeaders: provider.defaultHeaders } : {},
|
|
1819
|
+
fetch: instrumentedModelFetch(provider.id, globalThis.fetch)
|
|
1699
1820
|
});
|
|
1700
1821
|
providerClientCache.set(provider.id, client);
|
|
1701
1822
|
return client;
|
|
@@ -1724,7 +1845,7 @@ var MultiProviderModelProvider = class {
|
|
|
1724
1845
|
fallback;
|
|
1725
1846
|
async getModel(modelName) {
|
|
1726
1847
|
if (modelName) {
|
|
1727
|
-
const resolved = resolveTurnModel(this.settings, modelName);
|
|
1848
|
+
const resolved = resolveTurnModel(settingsForRunScopedModelResolution(this.settings, modelName), modelName);
|
|
1728
1849
|
if (resolved) {
|
|
1729
1850
|
if (modelName.startsWith(CODEX_MODEL_ID_PREFIX) && resolved.provider.kind !== "codex-subscription") {
|
|
1730
1851
|
throw new CodexSubscriptionUnavailableError(modelName);
|
|
@@ -1739,6 +1860,20 @@ var MultiProviderModelProvider = class {
|
|
|
1739
1860
|
return this.fallback.getModel(modelName);
|
|
1740
1861
|
}
|
|
1741
1862
|
};
|
|
1863
|
+
function settingsForRunScopedModelResolution(settings, modelName) {
|
|
1864
|
+
if (modelName !== settings.openaiModel) {
|
|
1865
|
+
return settings;
|
|
1866
|
+
}
|
|
1867
|
+
const builtinAllowed = splitOpenaiAllowedModels(settings.openaiAllowedModels);
|
|
1868
|
+
const fallbackBuiltin = builtinAllowed.find((id) => id !== modelName);
|
|
1869
|
+
if (!fallbackBuiltin) {
|
|
1870
|
+
return settings;
|
|
1871
|
+
}
|
|
1872
|
+
return builtinAllowed.includes(modelName) ? settings : { ...settings, openaiModel: fallbackBuiltin };
|
|
1873
|
+
}
|
|
1874
|
+
function splitOpenaiAllowedModels(value) {
|
|
1875
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
1876
|
+
}
|
|
1742
1877
|
var CodexSubscriptionUnavailableError = class extends Error {
|
|
1743
1878
|
constructor(modelName) {
|
|
1744
1879
|
super(
|
|
@@ -1749,6 +1884,7 @@ var CodexSubscriptionUnavailableError = class extends Error {
|
|
|
1749
1884
|
};
|
|
1750
1885
|
function configureOpenAI(settings) {
|
|
1751
1886
|
setOpenAIResponsesTransport(settings.openaiResponsesTransport);
|
|
1887
|
+
setTracingDisabled(settings.disableOpenaiTracing || !settings.observabilityOtlpEndpoint);
|
|
1752
1888
|
const router = new MultiProviderModelProvider(settings);
|
|
1753
1889
|
if (settings.openaiProvider === "azure") {
|
|
1754
1890
|
setDefaultOpenAIClient(buildOpenAIClientFromSettings(settings));
|
|
@@ -1763,6 +1899,41 @@ function configureOpenAI(settings) {
|
|
|
1763
1899
|
}
|
|
1764
1900
|
setDefaultModelProvider(router);
|
|
1765
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
|
+
}
|
|
1766
1937
|
async function summarizeForCompaction(settings, input, options = {}) {
|
|
1767
1938
|
const client = options.client ?? buildOpenAIClientFromSettings(settings);
|
|
1768
1939
|
const api = options.api ?? "responses";
|
|
@@ -1858,6 +2029,13 @@ function composeAgentInstructions(template, workspaceEnvironment) {
|
|
|
1858
2029
|
}
|
|
1859
2030
|
return core ? `${template} ${core}` : template;
|
|
1860
2031
|
}
|
|
2032
|
+
function appendSessionInstructions(composed, sessionInstructions) {
|
|
2033
|
+
const trimmed = sessionInstructions?.trim();
|
|
2034
|
+
return trimmed ? `${composed} ${trimmed}` : composed;
|
|
2035
|
+
}
|
|
2036
|
+
function appendGenesisTitleDirective(instructions, genesisTitleHint) {
|
|
2037
|
+
return genesisTitleHint ? `${instructions} ${GENESIS_TITLE_DIRECTIVE}` : instructions;
|
|
2038
|
+
}
|
|
1861
2039
|
var agentFileDownloads = /* @__PURE__ */ new WeakMap();
|
|
1862
2040
|
var agentRepositoryCloneHooks = /* @__PURE__ */ new WeakMap();
|
|
1863
2041
|
var agentGitTokenSeed = /* @__PURE__ */ new WeakMap();
|
|
@@ -1879,7 +2057,21 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
|
1879
2057
|
// ownership + workspace-environment block) at the {{core}} marker, or
|
|
1880
2058
|
// appends it when the template omits the marker. With the default template
|
|
1881
2059
|
// and no environment this is byte-identical to the historical preamble.
|
|
1882
|
-
|
|
2060
|
+
// Persona composition order (all one system-level instructions string):
|
|
2061
|
+
// 1. workspace instructionsTemplate (or deployment default) with the
|
|
2062
|
+
// non-bypassable CORE substituted at {{core}} — composeAgentInstructions,
|
|
2063
|
+
// 2. + the per-session persona instructions (session-specific, LAST so it
|
|
2064
|
+
// refines the workspace persona),
|
|
2065
|
+
// 3. + the one-shot genesis title directive (genesis turn only).
|
|
2066
|
+
// With no session instructions and no genesis hint this is byte-identical to
|
|
2067
|
+
// the historical composed instructions.
|
|
2068
|
+
instructions: appendGenesisTitleDirective(
|
|
2069
|
+
appendSessionInstructions(
|
|
2070
|
+
composeAgentInstructions(options.instructionsTemplate ?? settings.agentInstructionsTemplate, options.workspaceEnvironment),
|
|
2071
|
+
options.sessionInstructions
|
|
2072
|
+
),
|
|
2073
|
+
options.genesisTitleHint
|
|
2074
|
+
),
|
|
1883
2075
|
modelSettings: {
|
|
1884
2076
|
reasoning: { effort: options.reasoningEffort ?? settings.openaiReasoningEffort, summary: "detailed" },
|
|
1885
2077
|
// Server-side compaction (OpenAI platform) requires store=false: the
|
|
@@ -2513,7 +2705,6 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
|
|
|
2513
2705
|
// every mid-turn follow-up.
|
|
2514
2706
|
callModelInputFilter
|
|
2515
2707
|
};
|
|
2516
|
-
void settings.disableOpenaiTracing;
|
|
2517
2708
|
if (client) {
|
|
2518
2709
|
runOptions.sandbox = {
|
|
2519
2710
|
client,
|
|
@@ -3738,6 +3929,8 @@ export {
|
|
|
3738
3929
|
USER_MESSAGE_TRUNCATION_MARKER,
|
|
3739
3930
|
agentErrorToControlError,
|
|
3740
3931
|
agentsErrorRunState,
|
|
3932
|
+
appendGenesisTitleDirective,
|
|
3933
|
+
appendSessionInstructions,
|
|
3741
3934
|
applyMissingManifestEntries,
|
|
3742
3935
|
assertDescriptorRegistryInvariants,
|
|
3743
3936
|
assertProviderRegistryInvariants,
|
|
@@ -3764,6 +3957,7 @@ export {
|
|
|
3764
3957
|
composeAgentInstructions,
|
|
3765
3958
|
computerUse,
|
|
3766
3959
|
configureOpenAI,
|
|
3960
|
+
configureRuntimeMetricsHooks,
|
|
3767
3961
|
contentTypeForCodec,
|
|
3768
3962
|
contextRobustnessFilterForSettings,
|
|
3769
3963
|
coreInstructions,
|
|
@@ -3800,6 +3994,8 @@ export {
|
|
|
3800
3994
|
materializeSandboxFileDownloads,
|
|
3801
3995
|
maxTurnsExceededRunState,
|
|
3802
3996
|
mintStreamToken,
|
|
3997
|
+
modalSandboxAttributionEnvironment,
|
|
3998
|
+
modalSandboxAttributionTags,
|
|
3803
3999
|
modelResponseUsageFromSdkEvent,
|
|
3804
4000
|
negotiateCapabilities,
|
|
3805
4001
|
negotiateSelfhostedCapabilities,
|
|
@@ -3850,8 +4046,11 @@ export {
|
|
|
3850
4046
|
stripReasoningIdentityFromSerializedRunState,
|
|
3851
4047
|
subjectFor,
|
|
3852
4048
|
summarizeForCompaction,
|
|
4049
|
+
sweepModalOrphanSandboxes,
|
|
4050
|
+
tagModalSandbox,
|
|
3853
4051
|
tearDownDisplayStack,
|
|
3854
4052
|
tearDownTerminalServer,
|
|
4053
|
+
terminateModalSandboxById,
|
|
3855
4054
|
timeoutAgentError,
|
|
3856
4055
|
timeoutControlResponse,
|
|
3857
4056
|
verifyStreamToken,
|