@opengeni/runtime 0.11.0 → 0.13.3
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-YUAFQEFY.js → chunk-JGUQSAG5.js} +2605 -279
- package/dist/chunk-JGUQSAG5.js.map +1 -0
- package/dist/chunk-SSB7VOLE.js +301 -0
- package/dist/chunk-SSB7VOLE.js.map +1 -0
- package/dist/{index-D6yi-JcU.d.ts → index-DU-KXVlx.d.ts} +364 -31
- package/dist/index.d.ts +103 -10
- package/dist/index.js +756 -761
- package/dist/index.js.map +1 -1
- package/dist/mcp-network.d.ts +80 -0
- package/dist/mcp-network.js +66 -0
- package/dist/mcp-network.js.map +1 -0
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +39 -1
- package/package.json +9 -4
- package/src/codex-tool-search.ts +20 -1
- package/src/index.ts +502 -85
- package/src/mcp-network.ts +343 -0
- package/src/sandbox/channel-a.ts +92 -71
- package/src/sandbox/display-stack.ts +860 -23
- package/src/sandbox/exec-banner.ts +82 -0
- package/src/sandbox/index.ts +367 -145
- package/src/sandbox/provider-errors.ts +175 -0
- package/src/sandbox/providers/modal.ts +29 -2
- package/src/sandbox/routing/backend-resolver.ts +15 -0
- package/src/sandbox/routing/routing-session.ts +730 -36
- package/src/sandbox/select.ts +8 -0
- package/src/sandbox/turn-tool-cancellation.ts +366 -92
- package/src/sandbox/workspace-archive.ts +289 -0
- package/src/sandbox-computer.ts +3 -1
- package/src/usage-telemetry.ts +495 -51
- package/dist/chunk-YUAFQEFY.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -29,6 +29,9 @@ import {
|
|
|
29
29
|
REPOSITORY_DISCOVERY_LIMIT,
|
|
30
30
|
RecordingError,
|
|
31
31
|
RecordingUnavailableError,
|
|
32
|
+
RoutingBackendRecoveryRequiredError,
|
|
33
|
+
RoutingMutationOutcomeUnknownError,
|
|
34
|
+
RoutingRetainedProcessNotFoundError,
|
|
32
35
|
RoutingSandboxSession,
|
|
33
36
|
RoutingUnsupportedError,
|
|
34
37
|
RunCredentialValidationError,
|
|
@@ -48,7 +51,9 @@ import {
|
|
|
48
51
|
STREAM_TOKEN_DEFAULT_TTL_SECONDS,
|
|
49
52
|
SandboxChannelAService,
|
|
50
53
|
SandboxConfigError,
|
|
54
|
+
SandboxExecReadinessError,
|
|
51
55
|
SandboxProviderUnavailableError,
|
|
56
|
+
SandboxReplacementProviderStateError,
|
|
52
57
|
SandboxResumeStateUnavailableError,
|
|
53
58
|
SelfhostedControlError,
|
|
54
59
|
SelfhostedSandboxClient,
|
|
@@ -60,6 +65,9 @@ import {
|
|
|
60
65
|
TerminalServerError,
|
|
61
66
|
TerminalServerUnsupportedError,
|
|
62
67
|
ToolspaceTokenPathError,
|
|
68
|
+
TurnSandboxCommandCancelledError,
|
|
69
|
+
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
70
|
+
WorkspaceArchiveIntegrityError,
|
|
63
71
|
agentErrorToControlError,
|
|
64
72
|
assertDescriptorRegistryInvariants,
|
|
65
73
|
assertProviderRegistryInvariants,
|
|
@@ -69,12 +77,15 @@ import {
|
|
|
69
77
|
buildSelfhostedBackendSession,
|
|
70
78
|
buildStreamUrl,
|
|
71
79
|
buildTerminalServerScript,
|
|
80
|
+
captureVerifiedWorkspaceArchive,
|
|
81
|
+
classifyProviderSandboxFailure,
|
|
72
82
|
clearRunCredentials,
|
|
73
83
|
clearRunCredentialsForAttempt,
|
|
74
84
|
collectSandboxEnvironment,
|
|
75
85
|
contentTypeForCodec,
|
|
76
86
|
createSandboxClient,
|
|
77
87
|
createSandboxClientForBackend,
|
|
88
|
+
createTurnToolCancellationController,
|
|
78
89
|
decideSelfhostedRetry,
|
|
79
90
|
decodeModalSnapshotId,
|
|
80
91
|
defaultSelfhostedRetryClock,
|
|
@@ -91,9 +102,13 @@ import {
|
|
|
91
102
|
execDeadlineHint,
|
|
92
103
|
exposeStreamPort,
|
|
93
104
|
extForCodec,
|
|
105
|
+
fingerprintSandboxWorkspace,
|
|
106
|
+
hasPersistableSandboxProviderIdentity,
|
|
94
107
|
inspectRecordingArtifact,
|
|
95
108
|
isExecSessionLostBanner,
|
|
109
|
+
isProviderSandboxGoneDuringRoutedOperation,
|
|
96
110
|
isProviderSandboxNotFoundError,
|
|
111
|
+
isProviderSandboxTransientError,
|
|
97
112
|
isSelfhostedProviderNotFoundError,
|
|
98
113
|
localDirLazySkillSource,
|
|
99
114
|
makeActiveBackendResolver,
|
|
@@ -115,10 +130,13 @@ import {
|
|
|
115
130
|
parseNumstatZ,
|
|
116
131
|
parsePorcelainV2,
|
|
117
132
|
parseUnifiedPatch,
|
|
133
|
+
parseWorkspaceArchiveDescriptor,
|
|
118
134
|
payloadTooLargeMessage,
|
|
135
|
+
readVerifiedWorkspaceArchive,
|
|
119
136
|
readWorkspaceArchiveFromEnvelopeSessionState,
|
|
120
137
|
recordingStorageKey,
|
|
121
138
|
renderSelfhostedFault,
|
|
139
|
+
requirePersistableReplacementSandboxEnvelope,
|
|
122
140
|
restoredSandboxSessionStateFromEntry,
|
|
123
141
|
runCredentialPointerFile,
|
|
124
142
|
runCredentialRoot,
|
|
@@ -130,6 +148,7 @@ import {
|
|
|
130
148
|
selfhostedLiveness,
|
|
131
149
|
selfhostedRetryBackoffMs,
|
|
132
150
|
serializeEstablishedSandboxEnvelope,
|
|
151
|
+
serializeReplacementSandboxEnvelope,
|
|
133
152
|
setSelfhostedApplyDiff,
|
|
134
153
|
startRecording,
|
|
135
154
|
stopRecording,
|
|
@@ -146,20 +165,39 @@ import {
|
|
|
146
165
|
toolspaceTokenFileForSession,
|
|
147
166
|
toolspaceTokenFileFromEnvironment,
|
|
148
167
|
uploadRecordingArtifact,
|
|
168
|
+
verifyRestoredWorkspace,
|
|
169
|
+
verifySandboxExecReadiness,
|
|
149
170
|
verifyStreamToken,
|
|
150
171
|
withRunCredentialEnvironment,
|
|
151
172
|
withRunCredentialsClient,
|
|
152
173
|
withRunCredentialsSession,
|
|
153
174
|
withToolspaceTokenClient,
|
|
154
175
|
withToolspaceTokenEnvironment,
|
|
155
|
-
withToolspaceTokenSession
|
|
156
|
-
|
|
176
|
+
withToolspaceTokenSession,
|
|
177
|
+
wrapCapabilityToolsForTurnCancellation
|
|
178
|
+
} from "./chunk-JGUQSAG5.js";
|
|
157
179
|
import {
|
|
158
180
|
getSkillLibraryEntry,
|
|
159
181
|
isSkillLibraryEntryId,
|
|
160
182
|
listSkillLibraryEntries,
|
|
161
183
|
loadSkillLibrarySkill
|
|
162
184
|
} from "./chunk-DPULLAJG.js";
|
|
185
|
+
import {
|
|
186
|
+
MCP_MAX_CONCURRENT_SERVER_OPERATIONS,
|
|
187
|
+
MCP_MAX_TOOL_DEFINITION_BYTES,
|
|
188
|
+
MCP_MAX_TOOL_RESULT_BYTES,
|
|
189
|
+
MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES,
|
|
190
|
+
McpAggregateToolListBudget,
|
|
191
|
+
assertMcpPayloadWithinBytes,
|
|
192
|
+
assertMcpServerSelectionWithinBounds,
|
|
193
|
+
assertMcpToolListWithinBounds,
|
|
194
|
+
boundedParallelMap,
|
|
195
|
+
cancelMcpResponseBody,
|
|
196
|
+
guardedMcpFetch,
|
|
197
|
+
mcpOuterConnectTimeoutMs,
|
|
198
|
+
mcpSerializedSizeBytes,
|
|
199
|
+
undiciFetch
|
|
200
|
+
} from "./chunk-SSB7VOLE.js";
|
|
163
201
|
import {
|
|
164
202
|
MemorySession,
|
|
165
203
|
connectMcpServers
|
|
@@ -225,6 +263,7 @@ import {
|
|
|
225
263
|
import {
|
|
226
264
|
approvalIdentifier,
|
|
227
265
|
CAPABILITY_DESCRIPTORS as CAPABILITY_DESCRIPTORS2,
|
|
266
|
+
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
228
267
|
assertUniqueResourceMountPaths,
|
|
229
268
|
gitCredentialBindingIdForRepository,
|
|
230
269
|
gitCredentialProviderForRepository,
|
|
@@ -5094,7 +5133,7 @@ var OpenAITracingExporter = class {
|
|
|
5094
5133
|
const payloadItems = groupedItems.map((entry) => entry.toJSON()).filter((item) => !!item).map((item) => isRecord5(item) ? sanitizePayloadItemForTracesIngest(item) : item);
|
|
5095
5134
|
const payload = { data: payloadItems };
|
|
5096
5135
|
let attempts = 0;
|
|
5097
|
-
let
|
|
5136
|
+
let delay = this.#options.baseDelay;
|
|
5098
5137
|
while (attempts < this.#options.maxRetries) {
|
|
5099
5138
|
try {
|
|
5100
5139
|
const response = await fetch(this.#options.endpoint, {
|
|
@@ -5128,13 +5167,13 @@ var OpenAITracingExporter = class {
|
|
|
5128
5167
|
if (attempts >= this.#options.maxRetries) {
|
|
5129
5168
|
break;
|
|
5130
5169
|
}
|
|
5131
|
-
const sleepTime =
|
|
5170
|
+
const sleepTime = delay + Math.random() * 0.1 * delay;
|
|
5132
5171
|
const shouldContinue = await sleepWithAbort(sleepTime, signal);
|
|
5133
5172
|
if (!shouldContinue) {
|
|
5134
5173
|
logger_default.error("Tracing: request aborted");
|
|
5135
5174
|
break;
|
|
5136
5175
|
}
|
|
5137
|
-
|
|
5176
|
+
delay = Math.min(delay * 2, this.#options.maxDelay);
|
|
5138
5177
|
}
|
|
5139
5178
|
if (attempts >= this.#options.maxRetries) {
|
|
5140
5179
|
logger_default.error(`Tracing: failed to export traces after ${this.#options.maxRetries} attempts`);
|
|
@@ -6372,6 +6411,7 @@ import {
|
|
|
6372
6411
|
CODEX_APPS_MCP_SERVER_ID,
|
|
6373
6412
|
CODEX_MODEL_ID_PREFIX,
|
|
6374
6413
|
CODEX_ORIGINATOR,
|
|
6414
|
+
CODEX_RESPONSE_SDK_OUTER_TIMEOUT_MS,
|
|
6375
6415
|
boundModelToolOutputItems as boundModelToolOutputItems2,
|
|
6376
6416
|
codexAppsSanitizingFetch,
|
|
6377
6417
|
codexRequestStorage,
|
|
@@ -6972,7 +7012,21 @@ function codexToolSearchExecutor(args) {
|
|
|
6972
7012
|
const deferred = (args.availableTools ?? []).filter(isCodexAppsFunctionTool);
|
|
6973
7013
|
if (deferred.length === 0) return [];
|
|
6974
7014
|
const { query, limit } = parseSearchArgs(args.toolCall?.arguments);
|
|
6975
|
-
|
|
7015
|
+
const ranked = bm25RankTools(deferred, query, limit);
|
|
7016
|
+
const bounded = [];
|
|
7017
|
+
let disclosedBytes = 0;
|
|
7018
|
+
for (const tool2 of ranked) {
|
|
7019
|
+
const toolBytes = mcpSerializedSizeBytes(tool2);
|
|
7020
|
+
if (toolBytes > MCP_MAX_TOOL_DEFINITION_BYTES) {
|
|
7021
|
+
continue;
|
|
7022
|
+
}
|
|
7023
|
+
if (disclosedBytes + toolBytes > MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES) {
|
|
7024
|
+
break;
|
|
7025
|
+
}
|
|
7026
|
+
disclosedBytes += toolBytes;
|
|
7027
|
+
bounded.push(tool2);
|
|
7028
|
+
}
|
|
7029
|
+
return bounded;
|
|
6976
7030
|
}
|
|
6977
7031
|
var NO_NAMESPACES = /* @__PURE__ */ new Set();
|
|
6978
7032
|
function hasConnectorSources(connectorNamespaces) {
|
|
@@ -7570,668 +7624,6 @@ function safeStringify(value) {
|
|
|
7570
7624
|
}
|
|
7571
7625
|
}
|
|
7572
7626
|
|
|
7573
|
-
// src/sandbox/turn-tool-cancellation.ts
|
|
7574
|
-
var TURN_EXEC_YIELD_MS = 250;
|
|
7575
|
-
var TURN_WRITE_YIELD_MS = 250;
|
|
7576
|
-
var SHELL_HELPER_YIELD_MS = 1e3;
|
|
7577
|
-
var SHELL_GRACEFUL_POLLS = 2;
|
|
7578
|
-
var SHELL_POLL_MS = 100;
|
|
7579
|
-
var SHELL_MARKER_DIR = "/tmp/opengeni-turn-shell";
|
|
7580
|
-
var delay = async (milliseconds) => await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
7581
|
-
var TurnSandboxCommandCancelledError = class extends Error {
|
|
7582
|
-
name = "TurnSandboxCommandCancelledError";
|
|
7583
|
-
constructor(reason) {
|
|
7584
|
-
super(
|
|
7585
|
-
reason instanceof Error ? reason.message : String(reason ?? "Turn sandbox tools were cancelled"),
|
|
7586
|
-
{
|
|
7587
|
-
...reason instanceof Error ? { cause: reason } : {}
|
|
7588
|
-
}
|
|
7589
|
-
);
|
|
7590
|
-
}
|
|
7591
|
-
};
|
|
7592
|
-
function cancellationError(reason) {
|
|
7593
|
-
return new TurnSandboxCommandCancelledError(reason);
|
|
7594
|
-
}
|
|
7595
|
-
function parsedObject(input) {
|
|
7596
|
-
try {
|
|
7597
|
-
const parsed = JSON.parse(input);
|
|
7598
|
-
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
7599
|
-
} catch {
|
|
7600
|
-
return null;
|
|
7601
|
-
}
|
|
7602
|
-
}
|
|
7603
|
-
function cappedYield(value, cap) {
|
|
7604
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? Math.min(value, cap) : cap;
|
|
7605
|
-
}
|
|
7606
|
-
function execOutput(raw) {
|
|
7607
|
-
const marker = "\nOutput:\n";
|
|
7608
|
-
const index = raw.indexOf(marker);
|
|
7609
|
-
return index >= 0 ? raw.slice(index + marker.length) : "";
|
|
7610
|
-
}
|
|
7611
|
-
function nativeCommandBanner(result) {
|
|
7612
|
-
if (typeof result === "string") return result;
|
|
7613
|
-
if (!result || typeof result !== "object") {
|
|
7614
|
-
throw new Error("Sandbox command returned an invalid result");
|
|
7615
|
-
}
|
|
7616
|
-
const value = result;
|
|
7617
|
-
const sessionId = typeof value.sessionId === "number" ? value.sessionId : typeof value.session_id === "number" ? value.session_id : null;
|
|
7618
|
-
const exitCode = typeof value.exitCode === "number" ? value.exitCode : typeof value.exit_code === "number" ? value.exit_code : null;
|
|
7619
|
-
const output = [value.output, value.stderr, value.stdout].filter(
|
|
7620
|
-
(candidate) => typeof candidate === "string" && candidate.length > 0
|
|
7621
|
-
).join("\n");
|
|
7622
|
-
if (sessionId !== null) {
|
|
7623
|
-
return `Process running with session ID ${sessionId}
|
|
7624
|
-
|
|
7625
|
-
Output:
|
|
7626
|
-
${output}`;
|
|
7627
|
-
}
|
|
7628
|
-
if (exitCode !== null) {
|
|
7629
|
-
return `Process exited with code ${exitCode}
|
|
7630
|
-
|
|
7631
|
-
Output:
|
|
7632
|
-
${output}`;
|
|
7633
|
-
}
|
|
7634
|
-
throw new Error("Sandbox command did not report a session id or exit code");
|
|
7635
|
-
}
|
|
7636
|
-
function completedCommandBanner(exitCode, output) {
|
|
7637
|
-
return `Process exited with code ${exitCode}
|
|
7638
|
-
|
|
7639
|
-
Output:
|
|
7640
|
-
${output}`;
|
|
7641
|
-
}
|
|
7642
|
-
function appendBoundedOutput(current, chunk, maxOutputTokens) {
|
|
7643
|
-
const maxChars = Math.max(512, maxOutputTokens * 4);
|
|
7644
|
-
const combined = current + chunk;
|
|
7645
|
-
return combined.length <= maxChars ? combined : combined.slice(-maxChars);
|
|
7646
|
-
}
|
|
7647
|
-
function singleQuote(value) {
|
|
7648
|
-
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
7649
|
-
}
|
|
7650
|
-
function shellMarkerPath(token) {
|
|
7651
|
-
return `${SHELL_MARKER_DIR}/${token}`;
|
|
7652
|
-
}
|
|
7653
|
-
function cancellableGroupLeaderCommand(command, markerPath) {
|
|
7654
|
-
const marker = singleQuote(markerPath);
|
|
7655
|
-
const markerDir = singleQuote(SHELL_MARKER_DIR);
|
|
7656
|
-
return [
|
|
7657
|
-
`__opengeni_marker=${marker}`,
|
|
7658
|
-
"umask 077",
|
|
7659
|
-
`command mkdir -p ${markerDir} || exit 125`,
|
|
7660
|
-
'__opengeni_pid="$$"',
|
|
7661
|
-
`__opengeni_pgid="$(command ps -o pgid= -p "$__opengeni_pid" 2>/dev/null | command tr -d '[:space:]')"`,
|
|
7662
|
-
'case "$__opengeni_pid:$__opengeni_pgid" in *[!0-9:]*|*:|:*) exit 125 ;; esac',
|
|
7663
|
-
'[ "$__opengeni_pid" -gt 1 ] && [ "$__opengeni_pgid" -gt 1 ] || exit 125',
|
|
7664
|
-
// Never signal a provider/container-wide process group. A cancellable PTY
|
|
7665
|
-
// command must be its group's leader; fail the command closed otherwise.
|
|
7666
|
-
'[ "$__opengeni_pid" = "$__opengeni_pgid" ] || exit 125',
|
|
7667
|
-
`command printf '%s %s\\n' "$__opengeni_pid" "$__opengeni_pgid" > "$__opengeni_marker" || exit 125`,
|
|
7668
|
-
`trap 'command rm -f "$__opengeni_marker"' EXIT`,
|
|
7669
|
-
"(",
|
|
7670
|
-
command,
|
|
7671
|
-
")",
|
|
7672
|
-
"__opengeni_status=$?",
|
|
7673
|
-
'exit "$__opengeni_status"'
|
|
7674
|
-
].join("\n");
|
|
7675
|
-
}
|
|
7676
|
-
function cancellableShellCommand(command, markerPath) {
|
|
7677
|
-
const groupLeaderCommand = cancellableGroupLeaderCommand(command, markerPath);
|
|
7678
|
-
return [
|
|
7679
|
-
'__opengeni_outer_pid="$$"',
|
|
7680
|
-
`__opengeni_outer_pgid="$(command ps -o pgid= -p "$__opengeni_outer_pid" 2>/dev/null | command tr -d '[:space:]')"`,
|
|
7681
|
-
'case "$__opengeni_outer_pid:$__opengeni_outer_pgid" in *[!0-9:]*|*:|:*) exit 125 ;; esac',
|
|
7682
|
-
'if [ "$__opengeni_outer_pid" != "$__opengeni_outer_pgid" ]; then',
|
|
7683
|
-
' __opengeni_setsid="$(command -v setsid 2>/dev/null)"',
|
|
7684
|
-
' [ -n "$__opengeni_setsid" ] || exit 125',
|
|
7685
|
-
` exec "$__opengeni_setsid" /bin/sh -c ${singleQuote(groupLeaderCommand)}`,
|
|
7686
|
-
"fi",
|
|
7687
|
-
groupLeaderCommand
|
|
7688
|
-
].join("\n");
|
|
7689
|
-
}
|
|
7690
|
-
function shellHelperInput(command) {
|
|
7691
|
-
return JSON.stringify({
|
|
7692
|
-
cmd: command,
|
|
7693
|
-
login: false,
|
|
7694
|
-
tty: false,
|
|
7695
|
-
yield_time_ms: SHELL_HELPER_YIELD_MS,
|
|
7696
|
-
max_output_tokens: 128
|
|
7697
|
-
});
|
|
7698
|
-
}
|
|
7699
|
-
function safeProcessIdentity(raw) {
|
|
7700
|
-
if (parseExecBannerExitCode(raw) !== 0) return null;
|
|
7701
|
-
const match = execOutput(raw).trim().match(/^(\d+)\s+(\d+)$/);
|
|
7702
|
-
if (!match) return null;
|
|
7703
|
-
const pid = Number.parseInt(match[1], 10);
|
|
7704
|
-
const processGroupId = Number.parseInt(match[2], 10);
|
|
7705
|
-
return Number.isSafeInteger(pid) && Number.isSafeInteger(processGroupId) && pid > 1 && processGroupId > 1 ? { pid, processGroupId } : null;
|
|
7706
|
-
}
|
|
7707
|
-
function identityGuardScript(state, body, missingIdentityExitCode) {
|
|
7708
|
-
const identity = state.identity;
|
|
7709
|
-
if (!identity || !state.token) return `exit ${missingIdentityExitCode}`;
|
|
7710
|
-
const token = singleQuote(state.token);
|
|
7711
|
-
return [
|
|
7712
|
-
`__opengeni_pid=${identity.pid}`,
|
|
7713
|
-
`__opengeni_pgid=${identity.processGroupId}`,
|
|
7714
|
-
`__opengeni_token=${token}`,
|
|
7715
|
-
// The randomized token lands late in the wrapped command line. Procps
|
|
7716
|
-
// otherwise truncates `args` to the terminal width, which can make a live
|
|
7717
|
-
// group look stale and open the quiescence fence without signalling it.
|
|
7718
|
-
'__opengeni_args="$(command ps -ww -o args= -p "$__opengeni_pid" 2>/dev/null)"',
|
|
7719
|
-
'case "$__opengeni_args" in *"$__opengeni_token"*) ;; *) exit 0 ;; esac',
|
|
7720
|
-
`__opengeni_live_pgid="$(command ps -o pgid= -p "$__opengeni_pid" 2>/dev/null | command tr -d '[:space:]')"`,
|
|
7721
|
-
'[ "$__opengeni_live_pgid" = "$__opengeni_pgid" ] || exit 0',
|
|
7722
|
-
body
|
|
7723
|
-
].join("\n");
|
|
7724
|
-
}
|
|
7725
|
-
function wrapComputer(computer, track) {
|
|
7726
|
-
const wrapped = Object.create(Object.getPrototypeOf(computer));
|
|
7727
|
-
Object.assign(wrapped, computer);
|
|
7728
|
-
for (const method of [
|
|
7729
|
-
"initRun",
|
|
7730
|
-
"screenshot",
|
|
7731
|
-
"click",
|
|
7732
|
-
"doubleClick",
|
|
7733
|
-
"scroll",
|
|
7734
|
-
"type",
|
|
7735
|
-
"wait",
|
|
7736
|
-
"move",
|
|
7737
|
-
"keypress",
|
|
7738
|
-
"drag"
|
|
7739
|
-
]) {
|
|
7740
|
-
const original = computer[method];
|
|
7741
|
-
if (typeof original !== "function") continue;
|
|
7742
|
-
wrapped[method] = (...args) => track(async () => await original.apply(computer, args));
|
|
7743
|
-
}
|
|
7744
|
-
return wrapped;
|
|
7745
|
-
}
|
|
7746
|
-
var TurnToolCancellationControllerImpl = class {
|
|
7747
|
-
cancelled = false;
|
|
7748
|
-
reason;
|
|
7749
|
-
inFlight = /* @__PURE__ */ new Set();
|
|
7750
|
-
shellSessions = /* @__PURE__ */ new Map();
|
|
7751
|
-
remoteExecs = /* @__PURE__ */ new Set();
|
|
7752
|
-
rawExecInvoke = null;
|
|
7753
|
-
rawWriteInvoke = null;
|
|
7754
|
-
drainPromise = null;
|
|
7755
|
-
signal;
|
|
7756
|
-
onAbort = () => this.cancel(this.signal?.reason);
|
|
7757
|
-
constructor(signal) {
|
|
7758
|
-
this.signal = signal;
|
|
7759
|
-
if (signal?.aborted) {
|
|
7760
|
-
this.cancel(signal.reason);
|
|
7761
|
-
} else {
|
|
7762
|
-
signal?.addEventListener("abort", this.onAbort, { once: true });
|
|
7763
|
-
}
|
|
7764
|
-
}
|
|
7765
|
-
cancel(reason) {
|
|
7766
|
-
if (!this.cancelled) {
|
|
7767
|
-
this.cancelled = true;
|
|
7768
|
-
this.reason = reason;
|
|
7769
|
-
this.signal?.removeEventListener("abort", this.onAbort);
|
|
7770
|
-
}
|
|
7771
|
-
void this.ensureDrain().catch(() => void 0);
|
|
7772
|
-
}
|
|
7773
|
-
async waitForQuiescence() {
|
|
7774
|
-
this.cancel(this.reason);
|
|
7775
|
-
await this.ensureDrain();
|
|
7776
|
-
}
|
|
7777
|
-
runSandboxCommand(session, args) {
|
|
7778
|
-
return this.track(async () => {
|
|
7779
|
-
if (!session.exec && !session.execCommand) {
|
|
7780
|
-
throw new Error("Sandbox session does not support command execution");
|
|
7781
|
-
}
|
|
7782
|
-
const lifecycleRunContext = {};
|
|
7783
|
-
const invokeExec = async (_runContext, input) => {
|
|
7784
|
-
const parsed = parsedObject(input);
|
|
7785
|
-
if (!parsed || typeof parsed.cmd !== "string") {
|
|
7786
|
-
throw new Error("Sandbox lifecycle command input was invalid");
|
|
7787
|
-
}
|
|
7788
|
-
const commandArgs = {
|
|
7789
|
-
cmd: parsed.cmd,
|
|
7790
|
-
...typeof parsed.workdir === "string" ? { workdir: parsed.workdir } : {},
|
|
7791
|
-
...typeof parsed.shell === "string" ? { shell: parsed.shell } : {},
|
|
7792
|
-
...typeof parsed.login === "boolean" ? { login: parsed.login } : {},
|
|
7793
|
-
...typeof parsed.tty === "boolean" ? { tty: parsed.tty } : {},
|
|
7794
|
-
...typeof parsed.yield_time_ms === "number" ? { yieldTimeMs: parsed.yield_time_ms } : {},
|
|
7795
|
-
...typeof parsed.max_output_tokens === "number" ? { maxOutputTokens: parsed.max_output_tokens } : {},
|
|
7796
|
-
...typeof parsed.run_as === "string" ? { runAs: parsed.run_as } : {}
|
|
7797
|
-
};
|
|
7798
|
-
const result = session.supportsPty?.() !== false && session.execCommand ? await session.execCommand(commandArgs) : session.exec ? await session.exec(commandArgs) : await session.execCommand(commandArgs);
|
|
7799
|
-
return nativeCommandBanner(result);
|
|
7800
|
-
};
|
|
7801
|
-
const invokeWrite = session.writeStdin ? async (_runContext, input) => {
|
|
7802
|
-
const parsed = parsedObject(input);
|
|
7803
|
-
if (!parsed || typeof parsed.session_id !== "number") {
|
|
7804
|
-
throw new Error("Sandbox lifecycle stdin input was invalid");
|
|
7805
|
-
}
|
|
7806
|
-
return await session.writeStdin({
|
|
7807
|
-
sessionId: parsed.session_id,
|
|
7808
|
-
...typeof parsed.chars === "string" ? { chars: parsed.chars } : {},
|
|
7809
|
-
...typeof parsed.yield_time_ms === "number" ? { yieldTimeMs: parsed.yield_time_ms } : {},
|
|
7810
|
-
...typeof parsed.max_output_tokens === "number" ? { maxOutputTokens: parsed.max_output_tokens } : {}
|
|
7811
|
-
});
|
|
7812
|
-
} : null;
|
|
7813
|
-
const correlationId = `turn_lifecycle_${crypto.randomUUID()}`;
|
|
7814
|
-
const useRemoteOpCancellation = Boolean(session.cancelExecCommand) && session.supportsPty?.() === false;
|
|
7815
|
-
const remoteExec = session.cancelExecCommand && useRemoteOpCancellation ? this.registerRemoteExec(
|
|
7816
|
-
{ cancelExecCommand: session.cancelExecCommand.bind(session) },
|
|
7817
|
-
`${sanitizeOpIdToken(correlationId)}:0`
|
|
7818
|
-
) : null;
|
|
7819
|
-
const markerPath = shellMarkerPath(crypto.randomUUID());
|
|
7820
|
-
const commandInput = JSON.stringify({
|
|
7821
|
-
cmd: useRemoteOpCancellation ? args.cmd : cancellableShellCommand(args.cmd, markerPath),
|
|
7822
|
-
...args.workdir ? { workdir: args.workdir } : {},
|
|
7823
|
-
...args.shell ? { shell: args.shell } : {},
|
|
7824
|
-
...args.login !== void 0 ? { login: args.login } : {},
|
|
7825
|
-
...args.runAs ? { run_as: args.runAs } : {},
|
|
7826
|
-
tty: useRemoteOpCancellation ? args.tty : true,
|
|
7827
|
-
yield_time_ms: useRemoteOpCancellation ? args.yieldTimeMs : cappedYield(args.yieldTimeMs, TURN_EXEC_YIELD_MS),
|
|
7828
|
-
...args.maxOutputTokens !== void 0 ? { max_output_tokens: args.maxOutputTokens } : {}
|
|
7829
|
-
});
|
|
7830
|
-
let initial;
|
|
7831
|
-
try {
|
|
7832
|
-
initial = await runWithToolCallCorrelation(
|
|
7833
|
-
correlationId,
|
|
7834
|
-
async () => await invokeExec(lifecycleRunContext, commandInput, void 0)
|
|
7835
|
-
);
|
|
7836
|
-
} finally {
|
|
7837
|
-
remoteExec?.settle();
|
|
7838
|
-
}
|
|
7839
|
-
if (typeof initial !== "string" || useRemoteOpCancellation) return initial;
|
|
7840
|
-
const sessionId = parseExecBannerSessionId(initial);
|
|
7841
|
-
if (sessionId === null) return initial;
|
|
7842
|
-
if (!invokeWrite) {
|
|
7843
|
-
throw new Error("Sandbox lifecycle command yielded without stdin support");
|
|
7844
|
-
}
|
|
7845
|
-
const token = markerPath.slice(markerPath.lastIndexOf("/") + 1);
|
|
7846
|
-
const state = {
|
|
7847
|
-
sessionId,
|
|
7848
|
-
markerPath,
|
|
7849
|
-
token,
|
|
7850
|
-
runContext: lifecycleRunContext,
|
|
7851
|
-
execInvoke: invokeExec,
|
|
7852
|
-
writeInvoke: invokeWrite,
|
|
7853
|
-
identity: null,
|
|
7854
|
-
identityValidated: false,
|
|
7855
|
-
cancellation: null
|
|
7856
|
-
};
|
|
7857
|
-
this.shellSessions.set(sessionId, state);
|
|
7858
|
-
const maxOutputTokens = args.maxOutputTokens ?? 2e4;
|
|
7859
|
-
const initialOutput = execOutput(initial);
|
|
7860
|
-
let output = initialOutput ? appendBoundedOutput("", initialOutput, maxOutputTokens) : "";
|
|
7861
|
-
while (true) {
|
|
7862
|
-
if (this.cancelled) throw cancellationError(this.reason);
|
|
7863
|
-
const next = await invokeWrite(
|
|
7864
|
-
lifecycleRunContext,
|
|
7865
|
-
JSON.stringify({
|
|
7866
|
-
session_id: sessionId,
|
|
7867
|
-
chars: "",
|
|
7868
|
-
yield_time_ms: TURN_WRITE_YIELD_MS,
|
|
7869
|
-
max_output_tokens: maxOutputTokens
|
|
7870
|
-
}),
|
|
7871
|
-
void 0
|
|
7872
|
-
);
|
|
7873
|
-
if (typeof next !== "string") {
|
|
7874
|
-
throw new Error("Sandbox lifecycle stdin returned an invalid result");
|
|
7875
|
-
}
|
|
7876
|
-
const nextOutput = execOutput(next);
|
|
7877
|
-
if (nextOutput) output = appendBoundedOutput(output, nextOutput, maxOutputTokens);
|
|
7878
|
-
const exitCode = parseExecBannerExitCode(next);
|
|
7879
|
-
if (exitCode !== null) {
|
|
7880
|
-
this.shellSessions.delete(sessionId);
|
|
7881
|
-
return completedCommandBanner(exitCode, output);
|
|
7882
|
-
}
|
|
7883
|
-
await delay(SHELL_POLL_MS);
|
|
7884
|
-
}
|
|
7885
|
-
});
|
|
7886
|
-
}
|
|
7887
|
-
wrapTools(tools, session) {
|
|
7888
|
-
for (const tool2 of tools) {
|
|
7889
|
-
if (tool2.type !== "function") continue;
|
|
7890
|
-
if (tool2.name === "exec_command") this.rawExecInvoke = tool2.invoke;
|
|
7891
|
-
if (tool2.name === "write_stdin") this.rawWriteInvoke = tool2.invoke;
|
|
7892
|
-
}
|
|
7893
|
-
return tools.map((tool2) => {
|
|
7894
|
-
if (tool2.type === "function") return this.wrapFunctionTool(tool2, session);
|
|
7895
|
-
if (tool2.type === "apply_patch") return this.wrapApplyPatchTool(tool2);
|
|
7896
|
-
if (tool2.type === "computer") return this.wrapComputerTool(tool2);
|
|
7897
|
-
return tool2;
|
|
7898
|
-
});
|
|
7899
|
-
}
|
|
7900
|
-
wrapFunctionTool(tool2, cancellationSession) {
|
|
7901
|
-
if (tool2.name === "exec_command") {
|
|
7902
|
-
return {
|
|
7903
|
-
...tool2,
|
|
7904
|
-
invoke: (runContext, input, details) => this.track(async () => {
|
|
7905
|
-
const parsed = parsedObject(input);
|
|
7906
|
-
if (!parsed || typeof parsed.cmd !== "string") {
|
|
7907
|
-
return await this.correlatedInvoke(tool2.invoke, runContext, input, details);
|
|
7908
|
-
}
|
|
7909
|
-
const token = crypto.randomUUID();
|
|
7910
|
-
const markerPath = shellMarkerPath(token);
|
|
7911
|
-
const correlationId = details?.toolCall?.callId ?? `turn_exec_${token}`;
|
|
7912
|
-
const cancelExecCommand = cancellationSession?.cancelExecCommand;
|
|
7913
|
-
const useRemoteOpCancellation = Boolean(cancelExecCommand) && cancellationSession?.supportsPty?.() === false;
|
|
7914
|
-
const remoteExec = cancelExecCommand && useRemoteOpCancellation ? this.registerRemoteExec(
|
|
7915
|
-
{ cancelExecCommand: cancelExecCommand.bind(cancellationSession) },
|
|
7916
|
-
`${sanitizeOpIdToken(correlationId)}:0`
|
|
7917
|
-
) : null;
|
|
7918
|
-
const cancellableInput = useRemoteOpCancellation ? input : JSON.stringify({
|
|
7919
|
-
...parsed,
|
|
7920
|
-
cmd: cancellableShellCommand(parsed.cmd, markerPath),
|
|
7921
|
-
// The SDK's only provider-neutral live-process interrupt is a PTY.
|
|
7922
|
-
// The process marker provides TERM/KILL escalation when Ctrl-C is
|
|
7923
|
-
// ignored; the short yield exposes the provider session promptly.
|
|
7924
|
-
tty: true,
|
|
7925
|
-
yield_time_ms: cappedYield(parsed.yield_time_ms, TURN_EXEC_YIELD_MS)
|
|
7926
|
-
});
|
|
7927
|
-
let output;
|
|
7928
|
-
try {
|
|
7929
|
-
output = await runWithToolCallCorrelation(
|
|
7930
|
-
correlationId,
|
|
7931
|
-
async () => await tool2.invoke(runContext, cancellableInput, details)
|
|
7932
|
-
);
|
|
7933
|
-
} finally {
|
|
7934
|
-
remoteExec?.settle();
|
|
7935
|
-
}
|
|
7936
|
-
if (typeof output !== "string") return output;
|
|
7937
|
-
const sessionId = useRemoteOpCancellation ? null : parseExecBannerSessionId(output);
|
|
7938
|
-
if (sessionId !== null) {
|
|
7939
|
-
this.shellSessions.set(sessionId, {
|
|
7940
|
-
sessionId,
|
|
7941
|
-
markerPath,
|
|
7942
|
-
token,
|
|
7943
|
-
runContext,
|
|
7944
|
-
execInvoke: tool2.invoke,
|
|
7945
|
-
writeInvoke: this.rawWriteInvoke,
|
|
7946
|
-
identity: null,
|
|
7947
|
-
identityValidated: false,
|
|
7948
|
-
cancellation: null
|
|
7949
|
-
});
|
|
7950
|
-
}
|
|
7951
|
-
return output;
|
|
7952
|
-
})
|
|
7953
|
-
};
|
|
7954
|
-
}
|
|
7955
|
-
if (tool2.name === "write_stdin") {
|
|
7956
|
-
return {
|
|
7957
|
-
...tool2,
|
|
7958
|
-
invoke: (runContext, input, details) => this.track(async () => {
|
|
7959
|
-
const parsed = parsedObject(input);
|
|
7960
|
-
const sessionId = parsed && typeof parsed.session_id === "number" && Number.isSafeInteger(parsed.session_id) ? parsed.session_id : null;
|
|
7961
|
-
const cappedInput = parsed ? JSON.stringify({
|
|
7962
|
-
...parsed,
|
|
7963
|
-
yield_time_ms: cappedYield(parsed.yield_time_ms, TURN_WRITE_YIELD_MS)
|
|
7964
|
-
}) : input;
|
|
7965
|
-
const output = await tool2.invoke(runContext, cappedInput, details);
|
|
7966
|
-
if (sessionId !== null && typeof output === "string") {
|
|
7967
|
-
if (isExecSessionLostBanner(output, sessionId)) {
|
|
7968
|
-
this.shellSessions.delete(sessionId);
|
|
7969
|
-
} else if (parseExecBannerSessionId(output) === sessionId) {
|
|
7970
|
-
if (!this.shellSessions.has(sessionId)) {
|
|
7971
|
-
this.shellSessions.set(sessionId, {
|
|
7972
|
-
sessionId,
|
|
7973
|
-
markerPath: null,
|
|
7974
|
-
token: null,
|
|
7975
|
-
runContext,
|
|
7976
|
-
execInvoke: this.rawExecInvoke ?? tool2.invoke,
|
|
7977
|
-
writeInvoke: tool2.invoke,
|
|
7978
|
-
identity: null,
|
|
7979
|
-
identityValidated: false,
|
|
7980
|
-
cancellation: null
|
|
7981
|
-
});
|
|
7982
|
-
}
|
|
7983
|
-
} else if (parseExecBannerExitCode(output) !== null) {
|
|
7984
|
-
this.shellSessions.delete(sessionId);
|
|
7985
|
-
}
|
|
7986
|
-
}
|
|
7987
|
-
return output;
|
|
7988
|
-
})
|
|
7989
|
-
};
|
|
7990
|
-
}
|
|
7991
|
-
return {
|
|
7992
|
-
...tool2,
|
|
7993
|
-
invoke: (runContext, input, details) => this.track(async () => await tool2.invoke(runContext, input, details))
|
|
7994
|
-
};
|
|
7995
|
-
}
|
|
7996
|
-
wrapApplyPatchTool(tool2) {
|
|
7997
|
-
const editor = tool2.editor;
|
|
7998
|
-
const wrappedEditor = {
|
|
7999
|
-
createFile: (operation, context) => this.track(async () => await editor.createFile(operation, context)),
|
|
8000
|
-
updateFile: (operation, context) => this.track(async () => await editor.updateFile(operation, context)),
|
|
8001
|
-
deleteFile: (operation, context) => this.track(async () => await editor.deleteFile(operation, context))
|
|
8002
|
-
};
|
|
8003
|
-
return { ...tool2, editor: wrappedEditor };
|
|
8004
|
-
}
|
|
8005
|
-
wrapComputerTool(tool2) {
|
|
8006
|
-
const computer = tool2.computer;
|
|
8007
|
-
if (typeof computer === "function") {
|
|
8008
|
-
return {
|
|
8009
|
-
...tool2,
|
|
8010
|
-
computer: async (...args) => wrapComputer(
|
|
8011
|
-
await this.track(async () => await computer(...args)),
|
|
8012
|
-
(operation) => this.track(operation)
|
|
8013
|
-
)
|
|
8014
|
-
};
|
|
8015
|
-
}
|
|
8016
|
-
if ("create" in computer && typeof computer.create === "function") {
|
|
8017
|
-
return {
|
|
8018
|
-
...tool2,
|
|
8019
|
-
computer: {
|
|
8020
|
-
...computer,
|
|
8021
|
-
create: async (...args) => wrapComputer(
|
|
8022
|
-
await this.track(async () => await computer.create(...args)),
|
|
8023
|
-
(operation) => this.track(operation)
|
|
8024
|
-
)
|
|
8025
|
-
}
|
|
8026
|
-
};
|
|
8027
|
-
}
|
|
8028
|
-
return {
|
|
8029
|
-
...tool2,
|
|
8030
|
-
computer: wrapComputer(computer, (operation) => this.track(operation))
|
|
8031
|
-
};
|
|
8032
|
-
}
|
|
8033
|
-
async correlatedInvoke(invoke, runContext, input, details) {
|
|
8034
|
-
const callId = details?.toolCall?.callId;
|
|
8035
|
-
return callId ? await runWithToolCallCorrelation(
|
|
8036
|
-
callId,
|
|
8037
|
-
async () => await invoke(runContext, input, details)
|
|
8038
|
-
) : await invoke(runContext, input, details);
|
|
8039
|
-
}
|
|
8040
|
-
track(operation) {
|
|
8041
|
-
if (this.cancelled) return Promise.reject(cancellationError(this.reason));
|
|
8042
|
-
const promise = Promise.resolve().then(async () => {
|
|
8043
|
-
if (this.cancelled) throw cancellationError(this.reason);
|
|
8044
|
-
return await operation();
|
|
8045
|
-
});
|
|
8046
|
-
this.inFlight.add(promise);
|
|
8047
|
-
void promise.finally(() => {
|
|
8048
|
-
this.inFlight.delete(promise);
|
|
8049
|
-
}).catch(() => void 0);
|
|
8050
|
-
return promise;
|
|
8051
|
-
}
|
|
8052
|
-
ensureDrain() {
|
|
8053
|
-
this.drainPromise ??= this.drain();
|
|
8054
|
-
return this.drainPromise;
|
|
8055
|
-
}
|
|
8056
|
-
async drain() {
|
|
8057
|
-
while (true) {
|
|
8058
|
-
const remoteCancellations = [...this.remoteExecs].map(async (exec) => await exec.cancel());
|
|
8059
|
-
const inFlight = [...this.inFlight];
|
|
8060
|
-
if (inFlight.length > 0 || remoteCancellations.length > 0) {
|
|
8061
|
-
await Promise.allSettled([...inFlight, ...remoteCancellations]);
|
|
8062
|
-
}
|
|
8063
|
-
const sessions = [...this.shellSessions.values()];
|
|
8064
|
-
if (sessions.length > 0) {
|
|
8065
|
-
await Promise.all(sessions.map(async (session) => await this.cancelShellSession(session)));
|
|
8066
|
-
}
|
|
8067
|
-
if (this.inFlight.size === 0 && this.shellSessions.size === 0 && this.remoteExecs.size === 0)
|
|
8068
|
-
return;
|
|
8069
|
-
}
|
|
8070
|
-
}
|
|
8071
|
-
registerRemoteExec(session, opId) {
|
|
8072
|
-
let resolveSettled;
|
|
8073
|
-
const settledPromise = new Promise((resolve) => {
|
|
8074
|
-
resolveSettled = resolve;
|
|
8075
|
-
});
|
|
8076
|
-
let cancellation = null;
|
|
8077
|
-
const entry = {
|
|
8078
|
-
settled: false,
|
|
8079
|
-
settledPromise,
|
|
8080
|
-
settle: () => {
|
|
8081
|
-
if (entry.settled) return;
|
|
8082
|
-
entry.settled = true;
|
|
8083
|
-
resolveSettled();
|
|
8084
|
-
this.remoteExecs.delete(entry);
|
|
8085
|
-
},
|
|
8086
|
-
cancel: () => {
|
|
8087
|
-
cancellation ??= (async () => {
|
|
8088
|
-
while (!entry.settled) {
|
|
8089
|
-
const attempt = session.cancelExecCommand(opId).catch(() => false);
|
|
8090
|
-
await Promise.race([attempt, entry.settledPromise]);
|
|
8091
|
-
await Promise.race([entry.settledPromise, delay(SHELL_POLL_MS)]);
|
|
8092
|
-
}
|
|
8093
|
-
})();
|
|
8094
|
-
return cancellation;
|
|
8095
|
-
}
|
|
8096
|
-
};
|
|
8097
|
-
this.remoteExecs.add(entry);
|
|
8098
|
-
return entry;
|
|
8099
|
-
}
|
|
8100
|
-
cancelShellSession(state) {
|
|
8101
|
-
state.cancellation ??= this.cancelShellSessionOnce(state).finally(() => {
|
|
8102
|
-
state.cancellation = null;
|
|
8103
|
-
});
|
|
8104
|
-
return state.cancellation;
|
|
8105
|
-
}
|
|
8106
|
-
async cancelShellSessionOnce(state) {
|
|
8107
|
-
if (!state.markerPath) {
|
|
8108
|
-
while (true) {
|
|
8109
|
-
if (state.writeInvoke && await this.rawWrite(state, "", SHELL_POLL_MS)) {
|
|
8110
|
-
this.shellSessions.delete(state.sessionId);
|
|
8111
|
-
return;
|
|
8112
|
-
}
|
|
8113
|
-
await delay(SHELL_POLL_MS);
|
|
8114
|
-
}
|
|
8115
|
-
}
|
|
8116
|
-
while (!state.identity) {
|
|
8117
|
-
state.identity = await this.readIdentity(state);
|
|
8118
|
-
if (state.identity) break;
|
|
8119
|
-
if (state.writeInvoke) {
|
|
8120
|
-
const completed = await this.rawWrite(state, "", SHELL_POLL_MS);
|
|
8121
|
-
if (completed) {
|
|
8122
|
-
this.shellSessions.delete(state.sessionId);
|
|
8123
|
-
return;
|
|
8124
|
-
}
|
|
8125
|
-
}
|
|
8126
|
-
await delay(SHELL_POLL_MS);
|
|
8127
|
-
}
|
|
8128
|
-
if (!await this.identityAlive(state)) {
|
|
8129
|
-
this.shellSessions.delete(state.sessionId);
|
|
8130
|
-
return;
|
|
8131
|
-
}
|
|
8132
|
-
if (state.writeInvoke) {
|
|
8133
|
-
await this.rawWrite(state, "", SHELL_POLL_MS);
|
|
8134
|
-
if (!await this.identityAlive(state)) {
|
|
8135
|
-
this.shellSessions.delete(state.sessionId);
|
|
8136
|
-
return;
|
|
8137
|
-
}
|
|
8138
|
-
}
|
|
8139
|
-
await this.signalIdentity(state, "TERM");
|
|
8140
|
-
for (let attempt = 0; attempt < SHELL_GRACEFUL_POLLS; attempt++) {
|
|
8141
|
-
if (state.writeInvoke) await this.rawWrite(state, "", SHELL_POLL_MS);
|
|
8142
|
-
if (!await this.identityAlive(state)) {
|
|
8143
|
-
this.shellSessions.delete(state.sessionId);
|
|
8144
|
-
return;
|
|
8145
|
-
}
|
|
8146
|
-
}
|
|
8147
|
-
await this.signalIdentity(state, "KILL");
|
|
8148
|
-
while (await this.identityAlive(state)) {
|
|
8149
|
-
if (state.writeInvoke) await this.rawWrite(state, "", SHELL_POLL_MS);
|
|
8150
|
-
await this.signalIdentity(state, "KILL");
|
|
8151
|
-
await delay(SHELL_POLL_MS);
|
|
8152
|
-
}
|
|
8153
|
-
this.shellSessions.delete(state.sessionId);
|
|
8154
|
-
}
|
|
8155
|
-
async rawWrite(state, chars, yieldTimeMs) {
|
|
8156
|
-
if (!state.writeInvoke) return false;
|
|
8157
|
-
try {
|
|
8158
|
-
const output = await state.writeInvoke(
|
|
8159
|
-
state.runContext,
|
|
8160
|
-
JSON.stringify({
|
|
8161
|
-
session_id: state.sessionId,
|
|
8162
|
-
chars,
|
|
8163
|
-
yield_time_ms: yieldTimeMs,
|
|
8164
|
-
max_output_tokens: 128
|
|
8165
|
-
}),
|
|
8166
|
-
void 0
|
|
8167
|
-
);
|
|
8168
|
-
if (typeof output !== "string") return false;
|
|
8169
|
-
if (isExecSessionLostBanner(output, state.sessionId)) return true;
|
|
8170
|
-
if (parseExecBannerSessionId(output) === state.sessionId) return false;
|
|
8171
|
-
if (parseExecBannerExitCode(output) !== null) return true;
|
|
8172
|
-
} catch {
|
|
8173
|
-
}
|
|
8174
|
-
return false;
|
|
8175
|
-
}
|
|
8176
|
-
async readIdentity(state) {
|
|
8177
|
-
if (!state.markerPath) return null;
|
|
8178
|
-
try {
|
|
8179
|
-
const output = await state.execInvoke(
|
|
8180
|
-
state.runContext,
|
|
8181
|
-
shellHelperInput(`command cat ${singleQuote(state.markerPath)} 2>/dev/null`),
|
|
8182
|
-
void 0
|
|
8183
|
-
);
|
|
8184
|
-
return typeof output === "string" ? safeProcessIdentity(output) : null;
|
|
8185
|
-
} catch {
|
|
8186
|
-
return null;
|
|
8187
|
-
}
|
|
8188
|
-
}
|
|
8189
|
-
async identityAlive(state) {
|
|
8190
|
-
const script = state.identityValidated ? [
|
|
8191
|
-
`__opengeni_pgid=${state.identity?.processGroupId ?? 0}`,
|
|
8192
|
-
'command kill -0 "-$__opengeni_pgid" 2>/dev/null && exit 75',
|
|
8193
|
-
"exit 0"
|
|
8194
|
-
].join("\n") : identityGuardScript(
|
|
8195
|
-
state,
|
|
8196
|
-
'command kill -0 "-$__opengeni_pgid" 2>/dev/null && exit 75\nexit 0',
|
|
8197
|
-
76
|
|
8198
|
-
);
|
|
8199
|
-
try {
|
|
8200
|
-
const output = await state.execInvoke(state.runContext, shellHelperInput(script), void 0);
|
|
8201
|
-
if (typeof output !== "string") return true;
|
|
8202
|
-
const exitCode = parseExecBannerExitCode(output);
|
|
8203
|
-
if (exitCode === 75) {
|
|
8204
|
-
state.identityValidated = true;
|
|
8205
|
-
return true;
|
|
8206
|
-
}
|
|
8207
|
-
return exitCode !== 0;
|
|
8208
|
-
} catch {
|
|
8209
|
-
return true;
|
|
8210
|
-
}
|
|
8211
|
-
}
|
|
8212
|
-
async signalIdentity(state, signal) {
|
|
8213
|
-
const script = state.identityValidated ? `command kill -${signal} "-${state.identity?.processGroupId ?? 0}" 2>/dev/null || exit 76` : identityGuardScript(
|
|
8214
|
-
state,
|
|
8215
|
-
`command kill -${signal} "-$__opengeni_pgid" 2>/dev/null || exit 76
|
|
8216
|
-
exit 0`,
|
|
8217
|
-
76
|
|
8218
|
-
);
|
|
8219
|
-
try {
|
|
8220
|
-
await state.execInvoke(state.runContext, shellHelperInput(script), void 0);
|
|
8221
|
-
} catch {
|
|
8222
|
-
}
|
|
8223
|
-
}
|
|
8224
|
-
};
|
|
8225
|
-
function createTurnToolCancellationController(signal) {
|
|
8226
|
-
return new TurnToolCancellationControllerImpl(signal);
|
|
8227
|
-
}
|
|
8228
|
-
function wrapCapabilityToolsForTurnCancellation(capability, controller) {
|
|
8229
|
-
const originalTools = capability.tools;
|
|
8230
|
-
capability.tools = function() {
|
|
8231
|
-
return controller.wrapTools(originalTools.call(this), this._session);
|
|
8232
|
-
};
|
|
8233
|
-
}
|
|
8234
|
-
|
|
8235
7627
|
// src/sandbox-computer.ts
|
|
8236
7628
|
import {
|
|
8237
7629
|
KeyAction,
|
|
@@ -8963,7 +8355,9 @@ var ComputerUseCapability = class extends Capability {
|
|
|
8963
8355
|
// any computer-use-only recording. One SandboxComputer instance caches
|
|
8964
8356
|
// this for the rest of the turn.
|
|
8965
8357
|
prepare: async (preparedSession) => {
|
|
8966
|
-
await ensureDisplayStack(preparedSession
|
|
8358
|
+
await ensureDisplayStack(preparedSession, {
|
|
8359
|
+
telemetryContext: { callerKind: "computer" }
|
|
8360
|
+
});
|
|
8967
8361
|
await this.args.onReady?.(preparedSession);
|
|
8968
8362
|
}
|
|
8969
8363
|
});
|
|
@@ -9008,43 +8402,351 @@ var ComputerUseCapability = class extends Capability {
|
|
|
9008
8402
|
};
|
|
9009
8403
|
|
|
9010
8404
|
// src/usage-telemetry.ts
|
|
9011
|
-
|
|
8405
|
+
var MAX_MODEL_USAGE_TOKEN_COUNT = 1e9;
|
|
8406
|
+
function modelUsageTokenCountOrNull(value) {
|
|
8407
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= MAX_MODEL_USAGE_TOKEN_COUNT ? value : null;
|
|
8408
|
+
}
|
|
8409
|
+
function normalizeModelCallUsage(usage) {
|
|
8410
|
+
const rejectedFields = /* @__PURE__ */ new Set();
|
|
8411
|
+
if (!usage) {
|
|
8412
|
+
return {
|
|
8413
|
+
telemetry: {
|
|
8414
|
+
inputTokens: null,
|
|
8415
|
+
outputTokens: null,
|
|
8416
|
+
cachedTokens: null,
|
|
8417
|
+
cacheWriteTokens: null,
|
|
8418
|
+
reasoningTokens: null
|
|
8419
|
+
},
|
|
8420
|
+
totalTokens: null,
|
|
8421
|
+
rejectedFields: []
|
|
8422
|
+
};
|
|
8423
|
+
}
|
|
8424
|
+
const requestEntries = requestUsageEntries(usage.requestUsageEntries, rejectedFields);
|
|
8425
|
+
const topLevelInputTokens = reportedTokenCount(usage.inputTokens, "inputTokens", rejectedFields);
|
|
8426
|
+
const topLevelOutputTokens = reportedTokenCount(
|
|
8427
|
+
usage.outputTokens,
|
|
8428
|
+
"outputTokens",
|
|
8429
|
+
rejectedFields
|
|
8430
|
+
);
|
|
8431
|
+
const topLevelTotalTokens = reportedTokenCount(usage.totalTokens, "totalTokens", rejectedFields);
|
|
8432
|
+
const requestInputTokens = completeRequestTokenAggregate(
|
|
8433
|
+
requestEntries,
|
|
8434
|
+
["inputTokens", "input_tokens"],
|
|
8435
|
+
"inputTokens.requestUsageEntries",
|
|
8436
|
+
rejectedFields
|
|
8437
|
+
);
|
|
8438
|
+
const requestOutputTokens = completeRequestTokenAggregate(
|
|
8439
|
+
requestEntries,
|
|
8440
|
+
["outputTokens", "output_tokens"],
|
|
8441
|
+
"outputTokens.requestUsageEntries",
|
|
8442
|
+
rejectedFields
|
|
8443
|
+
);
|
|
8444
|
+
let requestTotalTokens = completeRequestTokenAggregate(
|
|
8445
|
+
requestEntries,
|
|
8446
|
+
["totalTokens", "total_tokens"],
|
|
8447
|
+
"totalTokens.requestUsageEntries",
|
|
8448
|
+
rejectedFields
|
|
8449
|
+
);
|
|
8450
|
+
if (rejectInconsistentRequestTotals(requestEntries, rejectedFields)) {
|
|
8451
|
+
requestTotalTokens = { ...requestTotalTokens, status: "invalid", value: null };
|
|
8452
|
+
}
|
|
8453
|
+
const inputTokens = canonicalTokenDimension({
|
|
8454
|
+
topLevel: topLevelInputTokens,
|
|
8455
|
+
topLevelReported: isReported(usage.inputTokens),
|
|
8456
|
+
topLevelPath: "inputTokens",
|
|
8457
|
+
requestAggregate: requestInputTokens,
|
|
8458
|
+
rejectedFields
|
|
8459
|
+
});
|
|
8460
|
+
const outputTokens = canonicalTokenDimension({
|
|
8461
|
+
topLevel: topLevelOutputTokens,
|
|
8462
|
+
topLevelReported: isReported(usage.outputTokens),
|
|
8463
|
+
topLevelPath: "outputTokens",
|
|
8464
|
+
requestAggregate: requestOutputTokens,
|
|
8465
|
+
rejectedFields
|
|
8466
|
+
});
|
|
8467
|
+
const totalTokens = canonicalTotalTokens({
|
|
8468
|
+
inputTokens,
|
|
8469
|
+
outputTokens,
|
|
8470
|
+
topLevel: topLevelTotalTokens,
|
|
8471
|
+
topLevelReported: isReported(usage.totalTokens),
|
|
8472
|
+
requestAggregate: requestTotalTokens,
|
|
8473
|
+
rejectedFields
|
|
8474
|
+
});
|
|
8475
|
+
const inputDetailSource = preferredDetailSource(
|
|
8476
|
+
usage.inputTokensDetails,
|
|
8477
|
+
"inputTokensDetails",
|
|
8478
|
+
requestEntries,
|
|
8479
|
+
["inputTokensDetails", "input_tokens_details"]
|
|
8480
|
+
);
|
|
8481
|
+
const outputDetailSource = preferredDetailSource(
|
|
8482
|
+
usage.outputTokensDetails,
|
|
8483
|
+
"outputTokensDetails",
|
|
8484
|
+
requestEntries,
|
|
8485
|
+
["outputTokensDetails", "output_tokens_details"]
|
|
8486
|
+
);
|
|
9012
8487
|
return {
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
8488
|
+
telemetry: {
|
|
8489
|
+
inputTokens,
|
|
8490
|
+
outputTokens,
|
|
8491
|
+
cachedTokens: aggregateDetailTokenCount(
|
|
8492
|
+
inputDetailSource,
|
|
8493
|
+
["cached_tokens", "cachedInputTokens", "cached_input_tokens"],
|
|
8494
|
+
"cachedTokens",
|
|
8495
|
+
rejectedFields
|
|
8496
|
+
),
|
|
8497
|
+
cacheWriteTokens: aggregateDetailTokenCount(
|
|
8498
|
+
inputDetailSource,
|
|
8499
|
+
["cache_write_tokens", "cacheWriteTokens"],
|
|
8500
|
+
"cacheWriteTokens",
|
|
8501
|
+
rejectedFields
|
|
8502
|
+
),
|
|
8503
|
+
reasoningTokens: aggregateDetailTokenCount(
|
|
8504
|
+
outputDetailSource,
|
|
8505
|
+
["reasoning_tokens", "reasoningTokens", "reasoning_output_tokens"],
|
|
8506
|
+
"reasoningTokens",
|
|
8507
|
+
rejectedFields
|
|
8508
|
+
)
|
|
8509
|
+
},
|
|
8510
|
+
totalTokens,
|
|
8511
|
+
rejectedFields: [...rejectedFields].slice(0, 32)
|
|
9025
8512
|
};
|
|
9026
8513
|
}
|
|
9027
|
-
function
|
|
9028
|
-
|
|
8514
|
+
function modelCallUsageTelemetry(usage) {
|
|
8515
|
+
return normalizeModelCallUsage(usage).telemetry;
|
|
8516
|
+
}
|
|
8517
|
+
function requestUsageEntries(value, rejectedFields) {
|
|
8518
|
+
if (value === void 0) {
|
|
8519
|
+
return [];
|
|
8520
|
+
}
|
|
8521
|
+
if (!Array.isArray(value)) {
|
|
8522
|
+
rejectField(rejectedFields, "requestUsageEntries");
|
|
8523
|
+
return [];
|
|
8524
|
+
}
|
|
8525
|
+
const entries = [];
|
|
8526
|
+
for (const [index, entry] of value.entries()) {
|
|
8527
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
8528
|
+
rejectField(rejectedFields, `requestUsageEntries[${index}]`);
|
|
8529
|
+
entries.push({});
|
|
8530
|
+
continue;
|
|
8531
|
+
}
|
|
8532
|
+
entries.push(entry);
|
|
8533
|
+
}
|
|
8534
|
+
return entries;
|
|
8535
|
+
}
|
|
8536
|
+
function completeRequestTokenAggregate(requestEntries, requestKeys, aggregatePath, rejectedFields) {
|
|
8537
|
+
if (requestEntries.length === 0) {
|
|
8538
|
+
return { status: "absent", value: null };
|
|
8539
|
+
}
|
|
8540
|
+
const values = [];
|
|
8541
|
+
let incomplete = false;
|
|
8542
|
+
let invalid = false;
|
|
8543
|
+
for (const [index, entry] of requestEntries.entries()) {
|
|
8544
|
+
const selected = firstPresentEntry(entry, requestKeys);
|
|
8545
|
+
if (!selected || selected.value === null) {
|
|
8546
|
+
incomplete = true;
|
|
8547
|
+
continue;
|
|
8548
|
+
}
|
|
8549
|
+
const parsed = reportedTokenCount(
|
|
8550
|
+
selected.value,
|
|
8551
|
+
`requestUsageEntries[${index}].${selected.key}`,
|
|
8552
|
+
rejectedFields
|
|
8553
|
+
);
|
|
8554
|
+
if (parsed === null) invalid = true;
|
|
8555
|
+
values.push(parsed);
|
|
8556
|
+
}
|
|
8557
|
+
if (invalid) {
|
|
8558
|
+
return { status: "invalid", value: null };
|
|
8559
|
+
}
|
|
8560
|
+
if (incomplete) {
|
|
8561
|
+
return { status: "incomplete", value: null };
|
|
8562
|
+
}
|
|
8563
|
+
const value = boundedTokenSum(values, aggregatePath, rejectedFields);
|
|
8564
|
+
return value === null ? { status: "invalid", value: null } : { status: "complete", value };
|
|
8565
|
+
}
|
|
8566
|
+
function canonicalTokenDimension(input) {
|
|
8567
|
+
if (input.requestAggregate.status === "complete") {
|
|
8568
|
+
if (input.topLevelReported && input.topLevel !== null && input.topLevel !== input.requestAggregate.value) {
|
|
8569
|
+
rejectField(input.rejectedFields, input.topLevelPath);
|
|
8570
|
+
}
|
|
8571
|
+
return input.requestAggregate.value;
|
|
8572
|
+
}
|
|
8573
|
+
if (input.requestAggregate.status === "invalid") {
|
|
8574
|
+
if (input.topLevelReported) {
|
|
8575
|
+
rejectField(input.rejectedFields, input.topLevelPath);
|
|
8576
|
+
}
|
|
9029
8577
|
return null;
|
|
9030
8578
|
}
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
8579
|
+
return input.topLevel;
|
|
8580
|
+
}
|
|
8581
|
+
function canonicalTotalTokens(input) {
|
|
8582
|
+
if (input.inputTokens !== null && input.outputTokens !== null) {
|
|
8583
|
+
const derived = boundedTokenSum(
|
|
8584
|
+
[input.inputTokens, input.outputTokens],
|
|
8585
|
+
"totalTokens.aggregate",
|
|
8586
|
+
input.rejectedFields
|
|
8587
|
+
);
|
|
8588
|
+
if (derived === null) {
|
|
8589
|
+
if (input.topLevelReported) rejectField(input.rejectedFields, "totalTokens");
|
|
8590
|
+
if (input.requestAggregate.status === "complete") {
|
|
8591
|
+
rejectField(input.rejectedFields, "totalTokens.requestUsageEntries");
|
|
9038
8592
|
}
|
|
9039
|
-
|
|
9040
|
-
|
|
8593
|
+
return null;
|
|
8594
|
+
}
|
|
8595
|
+
if (input.topLevelReported && input.topLevel !== null && input.topLevel !== derived) {
|
|
8596
|
+
rejectField(input.rejectedFields, "totalTokens");
|
|
8597
|
+
}
|
|
8598
|
+
if (input.requestAggregate.status === "complete" && input.requestAggregate.value !== derived) {
|
|
8599
|
+
rejectField(input.rejectedFields, "totalTokens.requestUsageEntries");
|
|
8600
|
+
}
|
|
8601
|
+
return derived;
|
|
8602
|
+
}
|
|
8603
|
+
if (input.requestAggregate.status === "complete") {
|
|
8604
|
+
const requestTotal = input.requestAggregate.value;
|
|
8605
|
+
if (requestTotal === null || !totalCoversKnownComponents(requestTotal, input.inputTokens, input.outputTokens)) {
|
|
8606
|
+
rejectField(input.rejectedFields, "totalTokens.requestUsageEntries");
|
|
8607
|
+
if (input.topLevelReported) rejectField(input.rejectedFields, "totalTokens");
|
|
8608
|
+
return null;
|
|
8609
|
+
}
|
|
8610
|
+
if (input.topLevelReported && input.topLevel !== null && input.topLevel !== requestTotal) {
|
|
8611
|
+
rejectField(input.rejectedFields, "totalTokens");
|
|
8612
|
+
}
|
|
8613
|
+
return requestTotal;
|
|
8614
|
+
}
|
|
8615
|
+
if (input.requestAggregate.status === "invalid") {
|
|
8616
|
+
if (input.topLevelReported) rejectField(input.rejectedFields, "totalTokens");
|
|
8617
|
+
return null;
|
|
8618
|
+
}
|
|
8619
|
+
if (input.topLevel !== null && !totalCoversKnownComponents(input.topLevel, input.inputTokens, input.outputTokens)) {
|
|
8620
|
+
rejectField(input.rejectedFields, "totalTokens");
|
|
8621
|
+
return null;
|
|
8622
|
+
}
|
|
8623
|
+
return input.topLevel;
|
|
8624
|
+
}
|
|
8625
|
+
function totalCoversKnownComponents(total, inputTokens, outputTokens) {
|
|
8626
|
+
return (inputTokens === null || total >= inputTokens) && (outputTokens === null || total >= outputTokens);
|
|
8627
|
+
}
|
|
8628
|
+
function rejectInconsistentRequestTotals(requestEntries, rejectedFields) {
|
|
8629
|
+
let inconsistent = false;
|
|
8630
|
+
for (const [index, entry] of requestEntries.entries()) {
|
|
8631
|
+
const record = entry;
|
|
8632
|
+
const selectedInput = firstPresentEntry(record, ["inputTokens", "input_tokens"]);
|
|
8633
|
+
const selectedOutput = firstPresentEntry(record, ["outputTokens", "output_tokens"]);
|
|
8634
|
+
const selectedTotal = firstPresentEntry(record, ["totalTokens", "total_tokens"]);
|
|
8635
|
+
if (!selectedInput || !selectedOutput || !selectedTotal) continue;
|
|
8636
|
+
const inputTokens = modelUsageTokenCountOrNull(selectedInput.value);
|
|
8637
|
+
const outputTokens = modelUsageTokenCountOrNull(selectedOutput.value);
|
|
8638
|
+
const totalTokens = modelUsageTokenCountOrNull(selectedTotal.value);
|
|
8639
|
+
if (inputTokens === null || outputTokens === null || totalTokens === null) continue;
|
|
8640
|
+
const derived = inputTokens <= MAX_MODEL_USAGE_TOKEN_COUNT - outputTokens ? inputTokens + outputTokens : null;
|
|
8641
|
+
if (derived === null || totalTokens !== derived) {
|
|
8642
|
+
rejectField(rejectedFields, `requestUsageEntries[${index}].${selectedTotal.key}`);
|
|
8643
|
+
inconsistent = true;
|
|
8644
|
+
}
|
|
8645
|
+
}
|
|
8646
|
+
return inconsistent;
|
|
8647
|
+
}
|
|
8648
|
+
function isReported(value) {
|
|
8649
|
+
return value !== void 0 && value !== null;
|
|
8650
|
+
}
|
|
8651
|
+
function preferredDetailSource(aggregateDetails, aggregatePath, requestEntries, requestKeys) {
|
|
8652
|
+
const requestDetails = [];
|
|
8653
|
+
let sawRequestDetails = false;
|
|
8654
|
+
for (const [index, entry] of requestEntries.entries()) {
|
|
8655
|
+
const selected = firstPresentEntry(entry, requestKeys);
|
|
8656
|
+
if (!selected) {
|
|
8657
|
+
requestDetails.push({
|
|
8658
|
+
details: void 0,
|
|
8659
|
+
path: `requestUsageEntries[${index}].${requestKeys[0]}`,
|
|
8660
|
+
missing: true
|
|
8661
|
+
});
|
|
8662
|
+
continue;
|
|
8663
|
+
}
|
|
8664
|
+
sawRequestDetails = true;
|
|
8665
|
+
requestDetails.push({
|
|
8666
|
+
details: selected.value,
|
|
8667
|
+
path: `requestUsageEntries[${index}].${selected.key}`
|
|
8668
|
+
});
|
|
8669
|
+
}
|
|
8670
|
+
return sawRequestDetails ? requestDetails : aggregateDetails === void 0 ? [] : [{ details: aggregateDetails, path: aggregatePath }];
|
|
8671
|
+
}
|
|
8672
|
+
function aggregateDetailTokenCount(sources, keys, field, rejectedFields) {
|
|
8673
|
+
const values = [];
|
|
8674
|
+
let sawReportedValue = false;
|
|
8675
|
+
let sawMissingValue = false;
|
|
8676
|
+
for (const source of sources) {
|
|
8677
|
+
if (source.missing) {
|
|
8678
|
+
sawMissingValue = true;
|
|
8679
|
+
continue;
|
|
8680
|
+
}
|
|
8681
|
+
const details = detailRecords(source.details, source.path, rejectedFields);
|
|
8682
|
+
if (!details.complete) {
|
|
8683
|
+
sawMissingValue = true;
|
|
8684
|
+
}
|
|
8685
|
+
for (const detail of details.records) {
|
|
8686
|
+
const selected = firstPresentEntry(detail.record, keys);
|
|
8687
|
+
if (!selected) {
|
|
8688
|
+
sawMissingValue = true;
|
|
8689
|
+
continue;
|
|
9041
8690
|
}
|
|
8691
|
+
sawReportedValue = true;
|
|
8692
|
+
values.push(
|
|
8693
|
+
reportedTokenCount(selected.value, `${detail.path}.${selected.key}`, rejectedFields)
|
|
8694
|
+
);
|
|
8695
|
+
}
|
|
8696
|
+
}
|
|
8697
|
+
return sawReportedValue && !sawMissingValue ? boundedTokenSum(values, `${field}.aggregate`, rejectedFields) : null;
|
|
8698
|
+
}
|
|
8699
|
+
function detailRecords(details, path, rejectedFields) {
|
|
8700
|
+
const entries = Array.isArray(details) ? details : [details];
|
|
8701
|
+
const records = [];
|
|
8702
|
+
let complete = true;
|
|
8703
|
+
for (const [index, entry] of entries.entries()) {
|
|
8704
|
+
const entryPath = Array.isArray(details) ? `${path}[${index}]` : path;
|
|
8705
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
8706
|
+
rejectField(rejectedFields, entryPath);
|
|
8707
|
+
complete = false;
|
|
8708
|
+
continue;
|
|
8709
|
+
}
|
|
8710
|
+
records.push({ record: entry, path: entryPath });
|
|
8711
|
+
}
|
|
8712
|
+
return { records, complete };
|
|
8713
|
+
}
|
|
8714
|
+
function firstPresentEntry(record, keys) {
|
|
8715
|
+
for (const key of keys) {
|
|
8716
|
+
if (Object.prototype.hasOwnProperty.call(record, key) && record[key] !== void 0) {
|
|
8717
|
+
return { key, value: record[key] };
|
|
8718
|
+
}
|
|
8719
|
+
}
|
|
8720
|
+
return null;
|
|
8721
|
+
}
|
|
8722
|
+
function reportedTokenCount(value, field, rejectedFields) {
|
|
8723
|
+
if (value === void 0 || value === null) {
|
|
8724
|
+
return null;
|
|
8725
|
+
}
|
|
8726
|
+
const normalized = modelUsageTokenCountOrNull(value);
|
|
8727
|
+
if (normalized === null) {
|
|
8728
|
+
rejectField(rejectedFields, field);
|
|
8729
|
+
}
|
|
8730
|
+
return normalized;
|
|
8731
|
+
}
|
|
8732
|
+
function boundedTokenSum(values, field, rejectedFields) {
|
|
8733
|
+
if (values.length === 0 || values.some((value) => value === null)) {
|
|
8734
|
+
return null;
|
|
8735
|
+
}
|
|
8736
|
+
let total = 0;
|
|
8737
|
+
for (const value of values) {
|
|
8738
|
+
if (value > MAX_MODEL_USAGE_TOKEN_COUNT - total) {
|
|
8739
|
+
rejectField(rejectedFields, field);
|
|
8740
|
+
return null;
|
|
9042
8741
|
}
|
|
8742
|
+
total += value;
|
|
9043
8743
|
}
|
|
9044
|
-
return
|
|
8744
|
+
return total;
|
|
9045
8745
|
}
|
|
9046
|
-
function
|
|
9047
|
-
|
|
8746
|
+
function rejectField(rejectedFields, field) {
|
|
8747
|
+
if (rejectedFields.size < 32) {
|
|
8748
|
+
rejectedFields.add(field);
|
|
8749
|
+
}
|
|
9048
8750
|
}
|
|
9049
8751
|
|
|
9050
8752
|
// src/index.ts
|
|
@@ -9154,6 +8856,10 @@ function buildProviderClient(provider, settings) {
|
|
|
9154
8856
|
// SDK retries on network/5xx/partial streams can replay provider work
|
|
9155
8857
|
// or external tool side effects without a durable checkpoint.
|
|
9156
8858
|
maxRetries: 0,
|
|
8859
|
+
// The Codex transport owns finer headers/idle/whole deadlines and
|
|
8860
|
+
// emits typed durable evidence. Keep the SDK's opaque envelope beyond
|
|
8861
|
+
// that whole-response budget so `Request timed out.` cannot win first.
|
|
8862
|
+
timeout: CODEX_RESPONSE_SDK_OUTER_TIMEOUT_MS,
|
|
9157
8863
|
fetch: codexSubscriptionFetch(instrumentedModelFetch(provider.id, globalThis.fetch))
|
|
9158
8864
|
})
|
|
9159
8865
|
) : (
|
|
@@ -9184,7 +8890,7 @@ function resolveTurnModel(settings, modelId) {
|
|
|
9184
8890
|
return {
|
|
9185
8891
|
provider: resolved.provider,
|
|
9186
8892
|
client,
|
|
9187
|
-
model: buildModelInstance(resolved.provider, client, resolved.model.
|
|
8893
|
+
model: buildModelInstance(resolved.provider, client, resolved.model.upstreamModelId),
|
|
9188
8894
|
configured: resolved.model
|
|
9189
8895
|
};
|
|
9190
8896
|
}
|
|
@@ -9834,7 +9540,7 @@ function maybeInstallCodexToolSearch(agent, settings, options) {
|
|
|
9834
9540
|
}
|
|
9835
9541
|
}
|
|
9836
9542
|
function mcpToolRequiresApproval(policy, unprefixedName) {
|
|
9837
|
-
return policy === true ||
|
|
9543
|
+
return policy === true || policy !== false && policy.has(unprefixedName);
|
|
9838
9544
|
}
|
|
9839
9545
|
function installMcpApprovalPolicy(agent, policies) {
|
|
9840
9546
|
const listMcpTools = agent.getMcpTools.bind(agent);
|
|
@@ -9866,7 +9572,7 @@ function applyMcpApprovalPolicy(agent, settings) {
|
|
|
9866
9572
|
(server) => server.requireApproval === true || Array.isArray(server.requireApproval) && server.requireApproval.length > 0
|
|
9867
9573
|
).map((server) => ({
|
|
9868
9574
|
prefix: prefixedMcpToolName(server.id, ""),
|
|
9869
|
-
requireApproval: server.requireApproval
|
|
9575
|
+
requireApproval: server.requireApproval === true ? true : new Set(server.requireApproval)
|
|
9870
9576
|
})).sort((a, b) => b.prefix.length - a.prefix.length);
|
|
9871
9577
|
if (policies.length === 0) {
|
|
9872
9578
|
return;
|
|
@@ -9966,22 +9672,77 @@ function buildAgentCapabilities(settings, packSkills, options = {}) {
|
|
|
9966
9672
|
function sandboxRunAs(_settings) {
|
|
9967
9673
|
return void 0;
|
|
9968
9674
|
}
|
|
9675
|
+
async function connectMcpServersInBatches(servers, options) {
|
|
9676
|
+
assertMcpServerSelectionWithinBounds(servers);
|
|
9677
|
+
const batches = [];
|
|
9678
|
+
try {
|
|
9679
|
+
for (let offset = 0; offset < servers.length; offset += MCP_MAX_CONCURRENT_SERVER_OPERATIONS) {
|
|
9680
|
+
batches.push(
|
|
9681
|
+
await connectMcpServers(
|
|
9682
|
+
servers.slice(offset, offset + MCP_MAX_CONCURRENT_SERVER_OPERATIONS),
|
|
9683
|
+
{
|
|
9684
|
+
...options.connectTimeoutMs === void 0 ? {} : { connectTimeoutMs: options.connectTimeoutMs },
|
|
9685
|
+
connectInParallel: true,
|
|
9686
|
+
strict: options.strict
|
|
9687
|
+
}
|
|
9688
|
+
)
|
|
9689
|
+
);
|
|
9690
|
+
}
|
|
9691
|
+
} catch (error) {
|
|
9692
|
+
await closeMcpServerBatches(batches).catch(() => void 0);
|
|
9693
|
+
throw error;
|
|
9694
|
+
}
|
|
9695
|
+
const errors = /* @__PURE__ */ new Map();
|
|
9696
|
+
for (const batch of batches) {
|
|
9697
|
+
for (const [server, error] of batch.errors) errors.set(server, error);
|
|
9698
|
+
}
|
|
9699
|
+
return {
|
|
9700
|
+
active: batches.flatMap((batch) => batch.active),
|
|
9701
|
+
failed: batches.flatMap((batch) => batch.failed),
|
|
9702
|
+
errors,
|
|
9703
|
+
close: async () => {
|
|
9704
|
+
await closeMcpServerBatches(batches);
|
|
9705
|
+
}
|
|
9706
|
+
};
|
|
9707
|
+
}
|
|
9708
|
+
async function closeMcpServerBatches(batches) {
|
|
9709
|
+
let firstError;
|
|
9710
|
+
for (const batch of [...batches].reverse()) {
|
|
9711
|
+
try {
|
|
9712
|
+
await batch.close();
|
|
9713
|
+
} catch (error) {
|
|
9714
|
+
firstError ??= error;
|
|
9715
|
+
}
|
|
9716
|
+
}
|
|
9717
|
+
if (firstError !== void 0) throw firstError;
|
|
9718
|
+
}
|
|
9969
9719
|
async function prepareAgentTools(settings, tools, options = {}) {
|
|
9970
9720
|
const codexConnectorNamespaces = /* @__PURE__ */ new Set();
|
|
9721
|
+
assertMcpServerSelectionWithinBounds(tools);
|
|
9971
9722
|
if (tools.length === 0) {
|
|
9972
9723
|
return { mcpServers: [], close: async () => {
|
|
9973
9724
|
}, codexConnectorNamespaces };
|
|
9974
9725
|
}
|
|
9975
9726
|
const registry = new Map(settings.mcpServers.map((server) => [server.id, server]));
|
|
9976
|
-
const
|
|
9977
|
-
|
|
9727
|
+
const aggregateToolBudget = new McpAggregateToolListBudget();
|
|
9728
|
+
const mcpFetchImpl = options.mcpFetchImpl ?? undiciFetch;
|
|
9729
|
+
const servers = await boundedParallelMap(
|
|
9730
|
+
tools,
|
|
9731
|
+
MCP_MAX_CONCURRENT_SERVER_OPERATIONS,
|
|
9732
|
+
async (tool2, index) => {
|
|
9978
9733
|
const config = registry.get(tool2.id);
|
|
9979
9734
|
if (!config) {
|
|
9980
9735
|
throw new Error(`Unknown MCP server id: ${tool2.id}`);
|
|
9981
9736
|
}
|
|
9982
9737
|
const url = firstPartyMcpServerUrlForRun(settings, config, options.workspaceId) ?? config.url;
|
|
9983
|
-
const
|
|
9984
|
-
const
|
|
9738
|
+
const firstParty = isFirstPartyMcpServer(settings, config);
|
|
9739
|
+
const baseFetch = isCodexAppsMcpServer(config) ? codexAppsSanitizingFetch(mcpFetchImpl, codexConnectorNamespaces) : mcpFetchImpl;
|
|
9740
|
+
const guardedFetch = guardedMcpFetch(
|
|
9741
|
+
firstParty ? { ...settings, integrationsAllowPrivateNetworkTargets: true } : settings,
|
|
9742
|
+
baseFetch,
|
|
9743
|
+
firstParty ? { requireHttpsOutsideLocalTest: false } : {}
|
|
9744
|
+
);
|
|
9745
|
+
const fetchImpl = config.connectionRef ? connectionBrokerFetch(guardedFetch, config, options) : firstParty ? firstPartyAuthFetch(guardedFetch, settings, options) : guardedFetch;
|
|
9985
9746
|
const optional = tool2.optional === true;
|
|
9986
9747
|
const bestEffort = isCodexAppsMcpServer(config) || optional || !!config.connectionRef;
|
|
9987
9748
|
const server = new PrefixedMcpServer(
|
|
@@ -9993,7 +9754,7 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
9993
9754
|
// MCP SDK's strict Tool schema rejects (fails the turn during tools/list);
|
|
9994
9755
|
// sanitize the response on the wire before validation. The namespace Set
|
|
9995
9756
|
// also captures each tool's original connector namespace (P4 Part B.1).
|
|
9996
|
-
|
|
9757
|
+
fetch: fetchImpl,
|
|
9997
9758
|
...await mcpServerRequestInit(settings, config),
|
|
9998
9759
|
...config.timeoutMs ? {
|
|
9999
9760
|
timeout: config.timeoutMs,
|
|
@@ -10002,30 +9763,46 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
10002
9763
|
}),
|
|
10003
9764
|
config.id,
|
|
10004
9765
|
config.allowedTools,
|
|
10005
|
-
bestEffort
|
|
9766
|
+
bestEffort,
|
|
9767
|
+
aggregateToolBudget,
|
|
9768
|
+
`${config.id}:${index}`
|
|
10006
9769
|
);
|
|
10007
9770
|
return {
|
|
10008
9771
|
server,
|
|
10009
9772
|
bestEffort,
|
|
10010
|
-
optional
|
|
9773
|
+
optional,
|
|
9774
|
+
timeoutMs: config.timeoutMs
|
|
10011
9775
|
};
|
|
10012
|
-
}
|
|
9776
|
+
}
|
|
10013
9777
|
);
|
|
10014
|
-
const
|
|
10015
|
-
const
|
|
9778
|
+
const requiredEntries = servers.filter((entry) => !entry.bestEffort);
|
|
9779
|
+
const bestEffortEntries = servers.filter((entry) => entry.bestEffort);
|
|
9780
|
+
const requiredServers = requiredEntries.map((entry) => entry.server);
|
|
9781
|
+
const bestEffortServers = bestEffortEntries.map((entry) => entry.server);
|
|
10016
9782
|
const optionalServerNames = new Set(
|
|
10017
9783
|
servers.filter((entry) => entry.optional).map((entry) => entry.server.name)
|
|
10018
9784
|
);
|
|
10019
|
-
const connectedRequired = await
|
|
10020
|
-
|
|
10021
|
-
|
|
9785
|
+
const connectedRequired = await connectMcpServersInBatches(requiredServers, {
|
|
9786
|
+
strict: true,
|
|
9787
|
+
connectTimeoutMs: mcpOuterConnectTimeoutMs(requiredEntries.map((entry) => entry.timeoutMs))
|
|
10022
9788
|
});
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
9789
|
+
let connectedBestEffort = null;
|
|
9790
|
+
try {
|
|
9791
|
+
connectedBestEffort = bestEffortServers.length ? await connectMcpServersInBatches(bestEffortServers, {
|
|
9792
|
+
strict: false,
|
|
9793
|
+
connectTimeoutMs: mcpOuterConnectTimeoutMs(
|
|
9794
|
+
bestEffortEntries.map((entry) => entry.timeoutMs)
|
|
9795
|
+
)
|
|
9796
|
+
}) : null;
|
|
9797
|
+
} catch (error) {
|
|
9798
|
+
await connectedRequired.close().catch(() => void 0);
|
|
9799
|
+
throw error;
|
|
9800
|
+
}
|
|
10027
9801
|
if (connectedBestEffort) {
|
|
10028
9802
|
for (const failed of connectedBestEffort.failed) {
|
|
9803
|
+
if (failed instanceof PrefixedMcpServer) {
|
|
9804
|
+
failed.releaseAggregateBudget();
|
|
9805
|
+
}
|
|
10029
9806
|
if (!optionalServerNames.has(failed.name)) {
|
|
10030
9807
|
continue;
|
|
10031
9808
|
}
|
|
@@ -10039,10 +9816,20 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
10039
9816
|
return {
|
|
10040
9817
|
mcpServers: [...connectedRequired.active, ...connectedBestEffort?.active ?? []],
|
|
10041
9818
|
close: async () => {
|
|
10042
|
-
|
|
9819
|
+
let firstError;
|
|
10043
9820
|
if (connectedBestEffort) {
|
|
10044
|
-
|
|
9821
|
+
try {
|
|
9822
|
+
await connectedBestEffort.close();
|
|
9823
|
+
} catch (error) {
|
|
9824
|
+
firstError ??= error;
|
|
9825
|
+
}
|
|
9826
|
+
}
|
|
9827
|
+
try {
|
|
9828
|
+
await connectedRequired.close();
|
|
9829
|
+
} catch (error) {
|
|
9830
|
+
firstError ??= error;
|
|
10045
9831
|
}
|
|
9832
|
+
if (firstError !== void 0) throw firstError;
|
|
10046
9833
|
},
|
|
10047
9834
|
codexConnectorNamespaces
|
|
10048
9835
|
};
|
|
@@ -10054,10 +9841,12 @@ function connectionBrokerFetch(baseFetch, config, options) {
|
|
|
10054
9841
|
}
|
|
10055
9842
|
return async (input, init) => {
|
|
10056
9843
|
const request = await mcpRequestInfo(input, init);
|
|
9844
|
+
const destinationUrl = mcpRequestDestinationUrl(input);
|
|
10057
9845
|
const first = await resolveConnectionForRequest(
|
|
10058
9846
|
options,
|
|
10059
9847
|
config.id,
|
|
10060
9848
|
connectionRef,
|
|
9849
|
+
destinationUrl,
|
|
10061
9850
|
request.toolName,
|
|
10062
9851
|
false
|
|
10063
9852
|
);
|
|
@@ -10069,10 +9858,12 @@ function connectionBrokerFetch(baseFetch, config, options) {
|
|
|
10069
9858
|
withConnectionHeaders(input, init, first.headers)
|
|
10070
9859
|
);
|
|
10071
9860
|
if (response.status === 401) {
|
|
9861
|
+
await cancelMcpResponseBody(response);
|
|
10072
9862
|
const refreshed = await resolveConnectionForRequest(
|
|
10073
9863
|
options,
|
|
10074
9864
|
config.id,
|
|
10075
9865
|
connectionRef,
|
|
9866
|
+
destinationUrl,
|
|
10076
9867
|
request.toolName,
|
|
10077
9868
|
true
|
|
10078
9869
|
);
|
|
@@ -10085,9 +9876,14 @@ function connectionBrokerFetch(baseFetch, config, options) {
|
|
|
10085
9876
|
);
|
|
10086
9877
|
if (retry.status === 403) {
|
|
10087
9878
|
const auth = insufficientScopeAuth(retry.headers, connectionRef, refreshed.connectionId);
|
|
10088
|
-
|
|
9879
|
+
if (auth) {
|
|
9880
|
+
await cancelMcpResponseBody(retry);
|
|
9881
|
+
return await authNeededFetchResponse(options, config.id, request, auth, connectionRef);
|
|
9882
|
+
}
|
|
9883
|
+
return retry;
|
|
10089
9884
|
}
|
|
10090
9885
|
if (retry.status === 401) {
|
|
9886
|
+
await cancelMcpResponseBody(retry);
|
|
10091
9887
|
return await authNeededFetchResponse(
|
|
10092
9888
|
options,
|
|
10093
9889
|
config.id,
|
|
@@ -10109,12 +9905,16 @@ function connectionBrokerFetch(baseFetch, config, options) {
|
|
|
10109
9905
|
}
|
|
10110
9906
|
if (response.status === 403) {
|
|
10111
9907
|
const auth = insufficientScopeAuth(response.headers, connectionRef, first.connectionId);
|
|
10112
|
-
|
|
9908
|
+
if (auth) {
|
|
9909
|
+
await cancelMcpResponseBody(response);
|
|
9910
|
+
return await authNeededFetchResponse(options, config.id, request, auth, connectionRef);
|
|
9911
|
+
}
|
|
9912
|
+
return response;
|
|
10113
9913
|
}
|
|
10114
9914
|
return response;
|
|
10115
9915
|
};
|
|
10116
9916
|
}
|
|
10117
|
-
async function resolveConnectionForRequest(options, serverId, connectionRef, toolName, forceRefresh) {
|
|
9917
|
+
async function resolveConnectionForRequest(options, serverId, connectionRef, destinationUrl, toolName, forceRefresh) {
|
|
10118
9918
|
if (!options.workspaceId || !options.resolveCredential) {
|
|
10119
9919
|
return {
|
|
10120
9920
|
status: "auth_needed",
|
|
@@ -10131,6 +9931,7 @@ async function resolveConnectionForRequest(options, serverId, connectionRef, too
|
|
|
10131
9931
|
workspaceId: options.workspaceId,
|
|
10132
9932
|
serverId,
|
|
10133
9933
|
connectionRef,
|
|
9934
|
+
destinationUrl,
|
|
10134
9935
|
forceRefresh,
|
|
10135
9936
|
...toolName ? { toolName } : {},
|
|
10136
9937
|
...options.subjectId ? { subjectId: options.subjectId } : {}
|
|
@@ -10194,6 +9995,9 @@ async function publishAuthNeeded(options, payload) {
|
|
|
10194
9995
|
} catch {
|
|
10195
9996
|
}
|
|
10196
9997
|
}
|
|
9998
|
+
function mcpRequestDestinationUrl(input) {
|
|
9999
|
+
return new URL(input instanceof Request ? input.url : input.toString()).toString();
|
|
10000
|
+
}
|
|
10197
10001
|
async function mcpRequestInfo(input, init) {
|
|
10198
10002
|
const body = typeof init?.body === "string" ? init.body : input instanceof Request && (init?.method ?? input.method).toUpperCase() === "POST" ? await input.clone().text().catch(() => "") : "";
|
|
10199
10003
|
if (!body) {
|
|
@@ -10326,7 +10130,7 @@ async function signFirstPartyDelegatedBearer(settings, options) {
|
|
|
10326
10130
|
workspaceId: options.workspaceId,
|
|
10327
10131
|
subjectId: options.subjectId ?? "worker:first-party-mcp",
|
|
10328
10132
|
...options.subjectLabel ? { subjectLabel: options.subjectLabel } : {},
|
|
10329
|
-
permissions: options.firstPartyPermissions ??
|
|
10133
|
+
permissions: options.firstPartyPermissions ?? [...DEFAULT_FIRST_PARTY_MCP_PERMISSIONS],
|
|
10330
10134
|
...options.sessionId ? { sessionId: options.sessionId } : {},
|
|
10331
10135
|
...options.turnId ? { turnId: options.turnId } : {},
|
|
10332
10136
|
...options.attemptId ? { attemptId: options.attemptId } : {},
|
|
@@ -10375,21 +10179,6 @@ async function codexAppsMcpRequestInit(settings) {
|
|
|
10375
10179
|
}
|
|
10376
10180
|
return { requestInit: { headers } };
|
|
10377
10181
|
}
|
|
10378
|
-
var firstPartyMcpPermissions = [
|
|
10379
|
-
"workspace:read",
|
|
10380
|
-
"files:read",
|
|
10381
|
-
"documents:search",
|
|
10382
|
-
"scheduled_tasks:manage",
|
|
10383
|
-
"scheduled_tasks:run",
|
|
10384
|
-
"goals:manage",
|
|
10385
|
-
"sessions:read",
|
|
10386
|
-
"sessions:create",
|
|
10387
|
-
"sessions:control",
|
|
10388
|
-
"variable-sets:use",
|
|
10389
|
-
"variable-sets:manage",
|
|
10390
|
-
"rigs:use",
|
|
10391
|
-
"github:use"
|
|
10392
|
-
];
|
|
10393
10182
|
function isCodexAppsMcpServer(config) {
|
|
10394
10183
|
return config.id === CODEX_APPS_MCP_SERVER_ID;
|
|
10395
10184
|
}
|
|
@@ -10457,8 +10246,10 @@ function prefixedMcpToolName(registryId, toolName) {
|
|
|
10457
10246
|
return sharedPrefixedMcpToolName(registryId, toolName);
|
|
10458
10247
|
}
|
|
10459
10248
|
var PrefixedMcpServer = class {
|
|
10460
|
-
constructor(inner, registryId, allowedTools, bestEffort = false) {
|
|
10249
|
+
constructor(inner, registryId, allowedTools, bestEffort = false, aggregateToolBudget, aggregateSourceId = registryId) {
|
|
10461
10250
|
this.inner = inner;
|
|
10251
|
+
this.aggregateToolBudget = aggregateToolBudget;
|
|
10252
|
+
this.aggregateSourceId = aggregateSourceId;
|
|
10462
10253
|
this.name = registryId;
|
|
10463
10254
|
this.prefix = prefixedMcpToolName(registryId, "");
|
|
10464
10255
|
this.cacheToolsList = inner.cacheToolsList;
|
|
@@ -10480,12 +10271,22 @@ var PrefixedMcpServer = class {
|
|
|
10480
10271
|
return this.inner.connect();
|
|
10481
10272
|
}
|
|
10482
10273
|
close() {
|
|
10274
|
+
this.releaseAggregateBudget();
|
|
10483
10275
|
return this.inner.close();
|
|
10484
10276
|
}
|
|
10277
|
+
releaseAggregateBudget() {
|
|
10278
|
+
this.aggregateToolBudget?.remove(this.aggregateSourceId);
|
|
10279
|
+
}
|
|
10485
10280
|
async listTools() {
|
|
10486
|
-
let tools;
|
|
10487
10281
|
try {
|
|
10488
|
-
tools = await this.inner.listTools();
|
|
10282
|
+
const tools = assertMcpToolListWithinBounds(await this.inner.listTools());
|
|
10283
|
+
const exposed = tools.filter((tool2) => this.isAllowed(tool2.name)).map((tool2) => ({
|
|
10284
|
+
...tool2,
|
|
10285
|
+
name: prefixedMcpToolName(this.name, tool2.name)
|
|
10286
|
+
}));
|
|
10287
|
+
const bounded = this.aggregateToolBudget?.replace(this.aggregateSourceId, exposed) ?? assertMcpToolListWithinBounds(exposed);
|
|
10288
|
+
this.listedToolSchemaTokens = estimateSerializedValueTokens(bounded);
|
|
10289
|
+
return bounded;
|
|
10489
10290
|
} catch (error) {
|
|
10490
10291
|
if (!this.bestEffort) {
|
|
10491
10292
|
throw error;
|
|
@@ -10499,14 +10300,9 @@ var PrefixedMcpServer = class {
|
|
|
10499
10300
|
{ serverId: this.name, ...safeMcpErrorFields(error) }
|
|
10500
10301
|
);
|
|
10501
10302
|
}
|
|
10303
|
+
this.releaseAggregateBudget();
|
|
10502
10304
|
return [];
|
|
10503
10305
|
}
|
|
10504
|
-
const exposed = tools.filter((tool2) => this.isAllowed(tool2.name)).map((tool2) => ({
|
|
10505
|
-
...tool2,
|
|
10506
|
-
name: prefixedMcpToolName(this.name, tool2.name)
|
|
10507
|
-
}));
|
|
10508
|
-
this.listedToolSchemaTokens = estimateSerializedValueTokens(exposed);
|
|
10509
|
-
return exposed;
|
|
10510
10306
|
}
|
|
10511
10307
|
/** Latest exact tools/list projection used to build the model request. */
|
|
10512
10308
|
modelToolSchemaTokens() {
|
|
@@ -10518,7 +10314,9 @@ var PrefixedMcpServer = class {
|
|
|
10518
10314
|
throw new Error(`MCP tool ${unprefixed} is not allowed for server ${this.name}`);
|
|
10519
10315
|
}
|
|
10520
10316
|
try {
|
|
10521
|
-
|
|
10317
|
+
const output = await this.inner.callTool(unprefixed, args, meta);
|
|
10318
|
+
assertMcpPayloadWithinBytes(output, MCP_MAX_TOOL_RESULT_BYTES, "MCP tool result");
|
|
10319
|
+
return output;
|
|
10522
10320
|
} catch (error) {
|
|
10523
10321
|
if (isAuthNeededMcpError(error)) {
|
|
10524
10322
|
return {
|
|
@@ -11590,17 +11388,18 @@ function usageFromResponse(response) {
|
|
|
11590
11388
|
),
|
|
11591
11389
|
...numberProp(record, "totalTokens", "totalTokens", "total_tokens"),
|
|
11592
11390
|
...inputTokenDetailsProp(record),
|
|
11593
|
-
...outputTokenDetailsProp(record)
|
|
11391
|
+
...outputTokenDetailsProp(record),
|
|
11392
|
+
...requestUsageEntriesProp(record)
|
|
11594
11393
|
};
|
|
11595
11394
|
return Object.keys(usage).length > 0 ? usage : null;
|
|
11596
11395
|
}
|
|
11597
11396
|
function numberProp(raw, outputKey, ...keys) {
|
|
11598
11397
|
const value = keys.map((key) => raw[key]).find((candidate) => candidate !== void 0);
|
|
11599
|
-
return typeof value === "number"
|
|
11398
|
+
return typeof value === "number" ? { [outputKey]: value } : {};
|
|
11600
11399
|
}
|
|
11601
11400
|
function inputTokenDetailsProp(raw) {
|
|
11602
11401
|
const details = raw.inputTokensDetails ?? raw.input_tokens_details ?? raw.promptTokensDetails ?? raw.prompt_tokens_details;
|
|
11603
|
-
if (
|
|
11402
|
+
if (details === void 0 || details === null) {
|
|
11604
11403
|
return {};
|
|
11605
11404
|
}
|
|
11606
11405
|
return {
|
|
@@ -11610,13 +11409,25 @@ function inputTokenDetailsProp(raw) {
|
|
|
11610
11409
|
function outputTokenDetailsProp(raw) {
|
|
11611
11410
|
const details = raw.outputTokensDetails ?? raw.output_tokens_details;
|
|
11612
11411
|
const normalized = details ?? raw.completionTokensDetails ?? raw.completion_tokens_details;
|
|
11613
|
-
if (
|
|
11412
|
+
if (normalized === void 0 || normalized === null) {
|
|
11614
11413
|
return {};
|
|
11615
11414
|
}
|
|
11616
11415
|
return {
|
|
11617
11416
|
outputTokensDetails: normalized
|
|
11618
11417
|
};
|
|
11619
11418
|
}
|
|
11419
|
+
function requestUsageEntriesProp(raw) {
|
|
11420
|
+
const entries = raw.requestUsageEntries ?? raw.request_usage_entries;
|
|
11421
|
+
if (entries === void 0 || entries === null) {
|
|
11422
|
+
return {};
|
|
11423
|
+
}
|
|
11424
|
+
return {
|
|
11425
|
+
// The normalizer validates every entry and all supported field aliases.
|
|
11426
|
+
// Preserve the SDK objects rather than rebuilding them and accidentally
|
|
11427
|
+
// dropping provider detail fields such as cache_write_tokens.
|
|
11428
|
+
requestUsageEntries: entries
|
|
11429
|
+
};
|
|
11430
|
+
}
|
|
11620
11431
|
function serializeApprovals(interruptions) {
|
|
11621
11432
|
return interruptions.filter((item) => interruptionToolName(item) !== HUMAN_INPUT_TOOL_NAME).map((item) => {
|
|
11622
11433
|
if (typeof item?.toJSON === "function") {
|
|
@@ -12085,13 +11896,95 @@ function runtimeGitBindingDescriptors(resources) {
|
|
|
12085
11896
|
};
|
|
12086
11897
|
});
|
|
12087
11898
|
}
|
|
11899
|
+
function gitCredentialBindingKey(provider, credentialBindingId) {
|
|
11900
|
+
return `${provider}\0${credentialBindingId}`;
|
|
11901
|
+
}
|
|
11902
|
+
function brokeredGitCredentialBindingKeys(bindings) {
|
|
11903
|
+
return new Set(
|
|
11904
|
+
bindings.filter((binding) => binding.transport?.kind === "http_broker").map((binding) => gitCredentialBindingKey(binding.provider, binding.credentialBindingId))
|
|
11905
|
+
);
|
|
11906
|
+
}
|
|
11907
|
+
function runtimeGitHttpBrokerRouteDescriptors(resources, bindings) {
|
|
11908
|
+
const resourceDescriptors = runtimeGitBindingDescriptors(resources);
|
|
11909
|
+
const byBindingAndUri = /* @__PURE__ */ new Map();
|
|
11910
|
+
for (const descriptor of resourceDescriptors) {
|
|
11911
|
+
byBindingAndUri.set(
|
|
11912
|
+
`${gitCredentialBindingKey(descriptor.provider, descriptor.credentialBindingId)}\0${descriptor.uri}`,
|
|
11913
|
+
descriptor
|
|
11914
|
+
);
|
|
11915
|
+
}
|
|
11916
|
+
const routes = [];
|
|
11917
|
+
const claimedRepositoryUris = /* @__PURE__ */ new Set();
|
|
11918
|
+
const claimedBrokerUris = /* @__PURE__ */ new Set();
|
|
11919
|
+
for (const binding of bindings) {
|
|
11920
|
+
if (!binding.transport) continue;
|
|
11921
|
+
if (typeof binding.transport !== "object" || binding.transport.kind !== "http_broker" || !Array.isArray(binding.transport.repositories)) {
|
|
11922
|
+
throw new Error(
|
|
11923
|
+
`Git credential binding ${binding.credentialBindingId} uses an unsupported transport`
|
|
11924
|
+
);
|
|
11925
|
+
}
|
|
11926
|
+
const bindingKey = gitCredentialBindingKey(binding.provider, binding.credentialBindingId);
|
|
11927
|
+
const expected = resourceDescriptors.filter(
|
|
11928
|
+
(descriptor) => gitCredentialBindingKey(descriptor.provider, descriptor.credentialBindingId) === bindingKey
|
|
11929
|
+
);
|
|
11930
|
+
if (expected.length === 0 || binding.transport.repositories.length !== expected.length) {
|
|
11931
|
+
throw new Error(
|
|
11932
|
+
`Git HTTP broker binding ${binding.credentialBindingId} does not cover its exact repository set`
|
|
11933
|
+
);
|
|
11934
|
+
}
|
|
11935
|
+
for (const route of binding.transport.repositories) {
|
|
11936
|
+
if (!route || typeof route !== "object" || typeof route.repositoryUri !== "string" || typeof route.brokerUri !== "string") {
|
|
11937
|
+
throw new Error(
|
|
11938
|
+
`Git HTTP broker binding ${binding.credentialBindingId} contains an invalid repository route`
|
|
11939
|
+
);
|
|
11940
|
+
}
|
|
11941
|
+
const descriptor = byBindingAndUri.get(`${bindingKey}\0${route.repositoryUri}`);
|
|
11942
|
+
if (!descriptor || claimedRepositoryUris.has(route.repositoryUri)) {
|
|
11943
|
+
throw new Error(
|
|
11944
|
+
`Git HTTP broker binding ${binding.credentialBindingId} contains an unexpected repository route`
|
|
11945
|
+
);
|
|
11946
|
+
}
|
|
11947
|
+
let brokerUrl;
|
|
11948
|
+
try {
|
|
11949
|
+
brokerUrl = new URL(route.brokerUri);
|
|
11950
|
+
} catch {
|
|
11951
|
+
throw new Error(
|
|
11952
|
+
`Git HTTP broker binding ${binding.credentialBindingId} contains an invalid broker URI`
|
|
11953
|
+
);
|
|
11954
|
+
}
|
|
11955
|
+
if (brokerUrl.protocol !== "https:" || brokerUrl.username || brokerUrl.password || brokerUrl.search || brokerUrl.hash || brokerUrl.href !== route.brokerUri || claimedBrokerUris.has(brokerUrl.href)) {
|
|
11956
|
+
throw new Error(
|
|
11957
|
+
`Git HTTP broker binding ${binding.credentialBindingId} contains an unsafe broker URI`
|
|
11958
|
+
);
|
|
11959
|
+
}
|
|
11960
|
+
claimedRepositoryUris.add(route.repositoryUri);
|
|
11961
|
+
claimedBrokerUris.add(brokerUrl.href);
|
|
11962
|
+
routes.push({
|
|
11963
|
+
provider: binding.provider,
|
|
11964
|
+
credentialBindingId: binding.credentialBindingId,
|
|
11965
|
+
bindingHash: gitCredentialBindingHash(binding.credentialBindingId),
|
|
11966
|
+
repositoryUri: route.repositoryUri,
|
|
11967
|
+
brokerUri: route.brokerUri,
|
|
11968
|
+
protocol: "https",
|
|
11969
|
+
host: brokerUrl.host.toLowerCase(),
|
|
11970
|
+
path: brokerUrl.pathname.replace(/^\/+|\/+$/g, "")
|
|
11971
|
+
});
|
|
11972
|
+
}
|
|
11973
|
+
}
|
|
11974
|
+
return routes;
|
|
11975
|
+
}
|
|
12088
11976
|
function gitUsernameForProvider(provider) {
|
|
12089
11977
|
if (provider === "github") return "x-access-token";
|
|
12090
11978
|
if (provider === "gitlab") return "oauth2";
|
|
12091
11979
|
return "opengeni";
|
|
12092
11980
|
}
|
|
12093
|
-
function gitCredentialHelperBindingCaseLines(resources) {
|
|
12094
|
-
|
|
11981
|
+
function gitCredentialHelperBindingCaseLines(resources, bindings) {
|
|
11982
|
+
const brokeredBindings = brokeredGitCredentialBindingKeys(bindings);
|
|
11983
|
+
return runtimeGitBindingDescriptors(resources).filter(
|
|
11984
|
+
(descriptor) => !brokeredBindings.has(
|
|
11985
|
+
gitCredentialBindingKey(descriptor.provider, descriptor.credentialBindingId)
|
|
11986
|
+
)
|
|
11987
|
+
).flatMap((descriptor) => {
|
|
12095
11988
|
const paths = /* @__PURE__ */ new Set([
|
|
12096
11989
|
descriptor.path,
|
|
12097
11990
|
descriptor.path.replace(/\.git$/, ""),
|
|
@@ -12102,7 +11995,19 @@ function gitCredentialHelperBindingCaseLines(resources) {
|
|
|
12102
11995
|
);
|
|
12103
11996
|
});
|
|
12104
11997
|
}
|
|
12105
|
-
function
|
|
11998
|
+
function gitCredentialHelperBrokerCaseLines(routes) {
|
|
11999
|
+
return routes.flatMap((route) => {
|
|
12000
|
+
const paths = /* @__PURE__ */ new Set([
|
|
12001
|
+
route.path,
|
|
12002
|
+
route.path.replace(/\.git$/, ""),
|
|
12003
|
+
`${route.path.replace(/\.git$/, "")}.git`
|
|
12004
|
+
]);
|
|
12005
|
+
return [...paths].map(
|
|
12006
|
+
(path) => ` ${shellQuote(`${route.protocol}|${route.host}|${path}`)}) username=opengeni; token_file="$credential_dir/${route.bindingHash}-token" ;;`
|
|
12007
|
+
);
|
|
12008
|
+
});
|
|
12009
|
+
}
|
|
12010
|
+
function gitAskpassHostProviderCaseLines(resources, brokerRoutes) {
|
|
12106
12011
|
const hosts = /* @__PURE__ */ new Map();
|
|
12107
12012
|
for (const descriptor of runtimeGitBindingDescriptors(resources)) {
|
|
12108
12013
|
const entry = hosts.get(descriptor.host) ?? {
|
|
@@ -12112,9 +12017,13 @@ function gitAskpassHostProviderCaseLines(resources) {
|
|
|
12112
12017
|
entry.bindings.add(`${descriptor.provider}\0${descriptor.credentialBindingId}`);
|
|
12113
12018
|
hosts.set(descriptor.host, entry);
|
|
12114
12019
|
}
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12020
|
+
const brokerHosts = [...new Set(brokerRoutes.map((route) => route.host))].sort((a, b) => a.localeCompare(b)).map((hostname) => ` ${shellQuote(hostname)}) printf '\\n'; return 0 ;;`);
|
|
12021
|
+
return [
|
|
12022
|
+
...brokerHosts,
|
|
12023
|
+
...[...hosts.entries()].filter(([, entry]) => entry.bindings.size === 1).sort(([a], [b]) => a.localeCompare(b)).map(
|
|
12024
|
+
([hostname, entry]) => ` ${shellQuote(hostname)}) printf '%s\\n' ${entry.provider}; return 0 ;;`
|
|
12025
|
+
)
|
|
12026
|
+
];
|
|
12118
12027
|
}
|
|
12119
12028
|
function gitCredentialTokenWriterCommandLines(bindings = []) {
|
|
12120
12029
|
const bindingWrites = bindings.flatMap((binding) => {
|
|
@@ -12123,7 +12032,7 @@ function gitCredentialTokenWriterCommandLines(bindings = []) {
|
|
|
12123
12032
|
const count = Math.max(1, binding.providerBindingCount ?? 1);
|
|
12124
12033
|
const provider = binding.provider;
|
|
12125
12034
|
const lines = [`write_git_binding_token ${shellQuote(hash)} "\${${seedEnv}:-}"`];
|
|
12126
|
-
if (count === 1) {
|
|
12035
|
+
if (count === 1 && binding.transport?.kind !== "http_broker") {
|
|
12127
12036
|
lines.push(`write_git_provider_token ${shellQuote(provider)} "\${${seedEnv}:-}"`);
|
|
12128
12037
|
} else {
|
|
12129
12038
|
lines.push(`remove_git_provider_token ${shellQuote(provider)}`);
|
|
@@ -12184,11 +12093,36 @@ function gitCredentialTokenWriterCommandLines(bindings = []) {
|
|
|
12184
12093
|
'umask "$seed_umask"'
|
|
12185
12094
|
];
|
|
12186
12095
|
}
|
|
12096
|
+
function gitHttpBrokerConfigCommandLines(routes) {
|
|
12097
|
+
return [
|
|
12098
|
+
'git_http_broker_config="${OPENGENI_GIT_CREDENTIALS_DIR:-$HOME/.opengeni/git-credentials}/http-broker.gitconfig"',
|
|
12099
|
+
'mkdir -p "$(dirname "$git_http_broker_config")"',
|
|
12100
|
+
'broker_umask="$(umask)"',
|
|
12101
|
+
"umask 077",
|
|
12102
|
+
': > "$git_http_broker_config.tmp.$$"',
|
|
12103
|
+
...routes.map(
|
|
12104
|
+
(route) => `git config --file "$git_http_broker_config.tmp.$$" --add ${shellQuote(`url.${route.brokerUri}.insteadOf`)} ${shellQuote(route.repositoryUri)}`
|
|
12105
|
+
),
|
|
12106
|
+
'mv -f "$git_http_broker_config.tmp.$$" "$git_http_broker_config"',
|
|
12107
|
+
'umask "$broker_umask"',
|
|
12108
|
+
'git config --global --unset-all include.path "$git_http_broker_config" >/dev/null 2>&1 || true',
|
|
12109
|
+
'git config --global --add include.path "$git_http_broker_config"'
|
|
12110
|
+
];
|
|
12111
|
+
}
|
|
12187
12112
|
function gitCredentialHelperCommandLines(resources = [], bindings = []) {
|
|
12188
|
-
const
|
|
12189
|
-
const
|
|
12113
|
+
const brokerRoutes = runtimeGitHttpBrokerRouteDescriptors(resources, bindings);
|
|
12114
|
+
const hostProviderCases = gitAskpassHostProviderCaseLines(resources, brokerRoutes);
|
|
12115
|
+
const bindingCases = [
|
|
12116
|
+
...gitCredentialHelperBindingCaseLines(resources, bindings),
|
|
12117
|
+
...gitCredentialHelperBrokerCaseLines(brokerRoutes)
|
|
12118
|
+
];
|
|
12190
12119
|
const descriptors = runtimeGitBindingDescriptors(resources);
|
|
12191
|
-
const
|
|
12120
|
+
const brokeredBindings = brokeredGitCredentialBindingKeys(bindings);
|
|
12121
|
+
const wrapperDescriptors = bindings.length > 0 ? descriptors.filter(
|
|
12122
|
+
(descriptor) => !brokeredBindings.has(
|
|
12123
|
+
gitCredentialBindingKey(descriptor.provider, descriptor.credentialBindingId)
|
|
12124
|
+
)
|
|
12125
|
+
) : [];
|
|
12192
12126
|
const bindingProviders = /* @__PURE__ */ new Map();
|
|
12193
12127
|
for (const descriptor of runtimeGitBindingDescriptors(resources)) {
|
|
12194
12128
|
const ids = bindingProviders.get(descriptor.provider) ?? /* @__PURE__ */ new Set();
|
|
@@ -12213,6 +12147,23 @@ function gitCredentialHelperCommandLines(resources = [], bindings = []) {
|
|
|
12213
12147
|
] : [];
|
|
12214
12148
|
});
|
|
12215
12149
|
const multiWrapperProviders = bindings.length > 0 ? [...bindingProviders.entries()].filter(([, ids]) => ids.size > 1).map(([provider]) => provider) : [];
|
|
12150
|
+
const brokeredOriginCases = brokerRoutes.flatMap((route) => {
|
|
12151
|
+
const base = route.repositoryUri.replace(/\.git$/, "");
|
|
12152
|
+
return [.../* @__PURE__ */ new Set([route.repositoryUri, base, `${base}.git`])].map(
|
|
12153
|
+
(uri) => ` ${shellQuote(`${route.provider}|${uri}`)}) return 0 ;;`
|
|
12154
|
+
);
|
|
12155
|
+
});
|
|
12156
|
+
const brokeredBindingHashCases = bindings.filter((binding) => binding.transport?.kind === "http_broker").map(
|
|
12157
|
+
(binding) => ` ${shellQuote(`${binding.provider}|${gitCredentialBindingHash(binding.credentialBindingId)}`)}) return 0 ;;`
|
|
12158
|
+
);
|
|
12159
|
+
const providerBindingKinds = /* @__PURE__ */ new Map();
|
|
12160
|
+
for (const binding of bindings) {
|
|
12161
|
+
const counts = providerBindingKinds.get(binding.provider) ?? { direct: 0, brokered: 0 };
|
|
12162
|
+
if (binding.transport?.kind === "http_broker") counts.brokered += 1;
|
|
12163
|
+
else counts.direct += 1;
|
|
12164
|
+
providerBindingKinds.set(binding.provider, counts);
|
|
12165
|
+
}
|
|
12166
|
+
const brokerOnlyProviders = [...providerBindingKinds.entries()].filter(([, counts]) => counts.brokered > 0 && counts.direct === 0).map(([provider]) => provider);
|
|
12216
12167
|
return [
|
|
12217
12168
|
...gitCredentialTokenWriterCommandLines(bindings),
|
|
12218
12169
|
// Provision git/provider-CLI helpers at SETUP (runtime) before any clone
|
|
@@ -12304,6 +12255,7 @@ function gitCredentialHelperCommandLines(resources = [], bindings = []) {
|
|
|
12304
12255
|
"git config --global --add credential.helper ''",
|
|
12305
12256
|
'git config --global --add credential.helper "$git_credential_helper"',
|
|
12306
12257
|
"git config --global credential.useHttpPath true",
|
|
12258
|
+
...gitHttpBrokerConfigCommandLines(brokerRoutes),
|
|
12307
12259
|
'wrapper_dir="${OPENGENI_GIT_CLI_WRAPPER_DIR:-$HOME/.opengeni/bin}"',
|
|
12308
12260
|
'mkdir -p "$wrapper_dir"',
|
|
12309
12261
|
"for opengeni_git_cli_tool in gh glab az; do",
|
|
@@ -12331,12 +12283,24 @@ function gitCredentialHelperCommandLines(resources = [], bindings = []) {
|
|
|
12331
12283
|
" *) return 1 ;;",
|
|
12332
12284
|
" esac",
|
|
12333
12285
|
"}",
|
|
12286
|
+
"binding_hash_is_brokered() {",
|
|
12287
|
+
' case "$provider|$1" in',
|
|
12288
|
+
...brokeredBindingHashCases,
|
|
12289
|
+
" *) return 1 ;;",
|
|
12290
|
+
" esac",
|
|
12291
|
+
"}",
|
|
12334
12292
|
"binding_hash_for_origin() {",
|
|
12335
12293
|
' case "$provider|$1" in',
|
|
12336
12294
|
...originWrapperHashes,
|
|
12337
12295
|
" *) return 1 ;;",
|
|
12338
12296
|
" esac",
|
|
12339
12297
|
"}",
|
|
12298
|
+
"origin_is_brokered() {",
|
|
12299
|
+
' case "$provider|$1" in',
|
|
12300
|
+
...brokeredOriginCases,
|
|
12301
|
+
" *) return 1 ;;",
|
|
12302
|
+
" esac",
|
|
12303
|
+
"}",
|
|
12340
12304
|
"sole_binding_hash() {",
|
|
12341
12305
|
' case "$provider" in',
|
|
12342
12306
|
...soleWrapperHashes,
|
|
@@ -12344,19 +12308,25 @@ function gitCredentialHelperCommandLines(resources = [], bindings = []) {
|
|
|
12344
12308
|
" esac",
|
|
12345
12309
|
"}",
|
|
12346
12310
|
`multi_binding_providers=${shellQuote(multiWrapperProviders.join(" "))}`,
|
|
12311
|
+
`broker_only_providers=${shellQuote(brokerOnlyProviders.join(" "))}`,
|
|
12347
12312
|
'if [ -n "$provider" ]; then',
|
|
12348
12313
|
" binding_hash=",
|
|
12349
12314
|
' if [ -n "${OPENGENI_GIT_BINDING:-}" ]; then',
|
|
12350
12315
|
' binding_hash="$(hash_binding_id "$OPENGENI_GIT_BINDING")"',
|
|
12316
|
+
` binding_hash_is_brokered "$binding_hash" && { printf '%s\\n' "$tool provider API authentication is host-brokered for OPENGENI_GIT_BINDING; use the configured provider MCP tools" >&2; exit 2; }`,
|
|
12351
12317
|
` binding_hash_allowed "$binding_hash" || { printf '%s\\n' "OPENGENI_GIT_BINDING does not select a $provider credential attached to this session" >&2; exit 2; }`,
|
|
12352
12318
|
" elif command -v git >/dev/null 2>&1; then",
|
|
12353
12319
|
' origin="$(git config --get remote.origin.url 2>/dev/null || true)"',
|
|
12320
|
+
` [ -z "$origin" ] || ! origin_is_brokered "$origin" || { printf '%s\\n' "$tool provider API authentication is host-brokered for this repository; use the configured provider MCP tools" >&2; exit 2; }`,
|
|
12354
12321
|
' [ -z "$origin" ] || binding_hash="$(binding_hash_for_origin "$origin" 2>/dev/null || true)"',
|
|
12355
12322
|
" fi",
|
|
12356
12323
|
' [ -n "$binding_hash" ] || binding_hash="$(sole_binding_hash 2>/dev/null || true)"',
|
|
12357
12324
|
' if [ -n "$binding_hash" ]; then',
|
|
12358
12325
|
' token_file="${OPENGENI_GIT_CREDENTIALS_DIR:-$HOME/.opengeni/git-credentials}/$binding_hash-token"',
|
|
12359
12326
|
" else",
|
|
12327
|
+
' case " $broker_only_providers " in',
|
|
12328
|
+
` *" $provider "*) printf '%s\\n' "$tool provider API authentication is host-brokered for this session; use the configured provider MCP tools" >&2; exit 2 ;;`,
|
|
12329
|
+
" esac",
|
|
12360
12330
|
' case " $multi_binding_providers " in',
|
|
12361
12331
|
` *" $provider "*) printf '%s\\n' "Unable to select one of multiple $provider credentials; run inside an attached repository or set OPENGENI_GIT_BINDING" >&2; exit 2 ;;`,
|
|
12362
12332
|
" esac",
|
|
@@ -13194,6 +13164,7 @@ export {
|
|
|
13194
13164
|
GENESIS_TITLE_DIRECTIVE,
|
|
13195
13165
|
HUMAN_INPUT_TOOL_NAME,
|
|
13196
13166
|
MAX_COMPACTION_THRESHOLD_RATIO,
|
|
13167
|
+
MAX_MODEL_USAGE_TOKEN_COUNT,
|
|
13197
13168
|
MIN_COMPACTION_THRESHOLD_RATIO,
|
|
13198
13169
|
MaxTurnsExceededError,
|
|
13199
13170
|
MockAgentResponder,
|
|
@@ -13212,6 +13183,9 @@ export {
|
|
|
13212
13183
|
REPOSITORY_DISCOVERY_LIMIT,
|
|
13213
13184
|
RecordingError,
|
|
13214
13185
|
RecordingUnavailableError,
|
|
13186
|
+
RoutingBackendRecoveryRequiredError,
|
|
13187
|
+
RoutingMutationOutcomeUnknownError,
|
|
13188
|
+
RoutingRetainedProcessNotFoundError,
|
|
13215
13189
|
RoutingSandboxSession,
|
|
13216
13190
|
RoutingUnsupportedError,
|
|
13217
13191
|
RunCredentialValidationError,
|
|
@@ -13234,7 +13208,9 @@ export {
|
|
|
13234
13208
|
SandboxChannelAService,
|
|
13235
13209
|
SandboxComputer,
|
|
13236
13210
|
SandboxConfigError,
|
|
13211
|
+
SandboxExecReadinessError,
|
|
13237
13212
|
SandboxProviderUnavailableError,
|
|
13213
|
+
SandboxReplacementProviderStateError,
|
|
13238
13214
|
SandboxResumeStateUnavailableError,
|
|
13239
13215
|
SelfhostedControlError,
|
|
13240
13216
|
SelfhostedSandboxClient,
|
|
@@ -13247,7 +13223,10 @@ export {
|
|
|
13247
13223
|
TerminalServerError,
|
|
13248
13224
|
TerminalServerUnsupportedError,
|
|
13249
13225
|
ToolspaceTokenPathError,
|
|
13226
|
+
TurnSandboxCommandCancelledError,
|
|
13250
13227
|
USER_MESSAGE_TRUNCATION_MARKER,
|
|
13228
|
+
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
13229
|
+
WorkspaceArchiveIntegrityError,
|
|
13251
13230
|
WorkspaceModelPolicyBlockedError,
|
|
13252
13231
|
agentErrorToControlError,
|
|
13253
13232
|
agentsErrorRunState,
|
|
@@ -13279,7 +13258,9 @@ export {
|
|
|
13279
13258
|
buildSummaryItem,
|
|
13280
13259
|
buildTerminalServerScript,
|
|
13281
13260
|
callModelInputFilterForSettings,
|
|
13261
|
+
captureVerifiedWorkspaceArchive,
|
|
13282
13262
|
clampCompactionThresholdRatio,
|
|
13263
|
+
classifyProviderSandboxFailure,
|
|
13283
13264
|
clearRunCredentials,
|
|
13284
13265
|
clearRunCredentialsForAttempt,
|
|
13285
13266
|
collectSandboxEnvironment,
|
|
@@ -13291,12 +13272,14 @@ export {
|
|
|
13291
13272
|
computerUse,
|
|
13292
13273
|
configureOpenAI,
|
|
13293
13274
|
configureRuntimeMetricsHooks,
|
|
13275
|
+
connectMcpServersInBatches,
|
|
13294
13276
|
contentTypeForCodec,
|
|
13295
13277
|
contextRobustnessFilterForSettings,
|
|
13296
13278
|
coreInstructions,
|
|
13297
13279
|
createProductionAgentRuntime,
|
|
13298
13280
|
createSandboxClient,
|
|
13299
13281
|
createSandboxClientForBackend,
|
|
13282
|
+
createTurnToolCancellationController,
|
|
13300
13283
|
decideCompaction,
|
|
13301
13284
|
decideSelfhostedRetry,
|
|
13302
13285
|
decodeModalSnapshotId,
|
|
@@ -13324,16 +13307,20 @@ export {
|
|
|
13324
13307
|
extForCodec,
|
|
13325
13308
|
extractResponseOutputText,
|
|
13326
13309
|
findCompactionNeededError,
|
|
13310
|
+
fingerprintSandboxWorkspace,
|
|
13327
13311
|
getSkillLibraryEntry,
|
|
13328
13312
|
gitCredentialBindingHash,
|
|
13329
13313
|
gitCredentialBindingTokenRefreshCommand,
|
|
13330
13314
|
gitProviderTokenRefreshCommand,
|
|
13331
13315
|
hasModelGeneratedItem,
|
|
13316
|
+
hasPersistableSandboxProviderIdentity,
|
|
13332
13317
|
inspectRecordingArtifact,
|
|
13333
13318
|
isCompactionSummary,
|
|
13334
13319
|
isEphemeralInternalContext,
|
|
13335
13320
|
isExecSessionLostBanner,
|
|
13321
|
+
isProviderSandboxGoneDuringRoutedOperation,
|
|
13336
13322
|
isProviderSandboxNotFoundError,
|
|
13323
|
+
isProviderSandboxTransientError,
|
|
13337
13324
|
isSelfhostedProviderNotFoundError,
|
|
13338
13325
|
isSkillLibraryEntryId,
|
|
13339
13326
|
isUserMessage,
|
|
@@ -13353,11 +13340,13 @@ export {
|
|
|
13353
13340
|
modelCallUsageTelemetry,
|
|
13354
13341
|
modelResponseUsageFromResponse,
|
|
13355
13342
|
modelResponseUsageFromSdkEvent,
|
|
13343
|
+
modelUsageTokenCountOrNull,
|
|
13356
13344
|
negotiateCapabilities,
|
|
13357
13345
|
negotiateSelfhostedCapabilities,
|
|
13358
13346
|
neutralizeToolSearchItemsInSerializedRunState,
|
|
13359
13347
|
nextDurableOpId,
|
|
13360
13348
|
normalizeComputerCallsFilter,
|
|
13349
|
+
normalizeModelCallUsage,
|
|
13361
13350
|
normalizeRunCredentialsResolution,
|
|
13362
13351
|
normalizeSdkEvent,
|
|
13363
13352
|
normalizeToolOutputForEvent,
|
|
@@ -13372,12 +13361,14 @@ export {
|
|
|
13372
13361
|
parseNumstatZ,
|
|
13373
13362
|
parsePorcelainV2,
|
|
13374
13363
|
parseUnifiedPatch,
|
|
13364
|
+
parseWorkspaceArchiveDescriptor,
|
|
13375
13365
|
payloadTooLargeMessage,
|
|
13376
13366
|
pinProvidedSessionManifestEnvironment,
|
|
13377
13367
|
prefixedMcpToolName,
|
|
13378
13368
|
prepareAgentTools,
|
|
13379
13369
|
prepareCompactionPromptInput,
|
|
13380
13370
|
prepareRunInput,
|
|
13371
|
+
readVerifiedWorkspaceArchive,
|
|
13381
13372
|
readWorkspaceArchiveFromEnvelopeSessionState,
|
|
13382
13373
|
recordingStorageKey,
|
|
13383
13374
|
refreshGitCredentialBindingTokenFiles,
|
|
@@ -13387,6 +13378,7 @@ export {
|
|
|
13387
13378
|
renderSelfhostedFault,
|
|
13388
13379
|
repositoryCloneCommand,
|
|
13389
13380
|
repositoryUsesSandboxClone,
|
|
13381
|
+
requirePersistableReplacementSandboxEnvelope,
|
|
13390
13382
|
resolveTurnModel,
|
|
13391
13383
|
restoredSandboxSessionStateFromEntry,
|
|
13392
13384
|
rigInstructions,
|
|
@@ -13418,6 +13410,7 @@ export {
|
|
|
13418
13410
|
serializeApprovals,
|
|
13419
13411
|
serializeEstablishedSandboxEnvelope,
|
|
13420
13412
|
serializeHumanInputRequests,
|
|
13413
|
+
serializeReplacementSandboxEnvelope,
|
|
13421
13414
|
setSelfhostedApplyDiff,
|
|
13422
13415
|
startRecording,
|
|
13423
13416
|
stopRecording,
|
|
@@ -13439,6 +13432,8 @@ export {
|
|
|
13439
13432
|
toolspaceTokenFileFromEnvironment,
|
|
13440
13433
|
toolspaceTokenSeedCommand,
|
|
13441
13434
|
uploadRecordingArtifact,
|
|
13435
|
+
verifyRestoredWorkspace,
|
|
13436
|
+
verifySandboxExecReadiness,
|
|
13442
13437
|
verifyStreamToken,
|
|
13443
13438
|
withManifestRefreshOnResume,
|
|
13444
13439
|
withRunCredentialEnvironment,
|