@opengeni/runtime 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/dist/index.d.ts +87 -7
- package/dist/index.js +458 -29
- package/dist/index.js.map +1 -1
- package/package.json +6 -8
- package/src/context-compaction.ts +164 -16
- package/src/history-sanitizer.ts +2 -1
- package/src/index.ts +519 -13
package/dist/index.js
CHANGED
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
|
|
100
100
|
// src/index.ts
|
|
101
101
|
import { AGENT_INSTRUCTIONS_CORE_PLACEHOLDER, collectSandboxEnvironment as collectSandboxEnvironment2, contextInputBudgetTokens, contextServerCompactThreshold, firstPartyMcpBaseUrl, resolveContextCompactionMode, resolveModelProvider, sandboxLifecycleHookIds } from "@opengeni/config";
|
|
102
|
-
import { CAPABILITY_DESCRIPTORS as CAPABILITY_DESCRIPTORS2, isClearedRunStateBlob, signDelegatedAccessToken } from "@opengeni/contracts";
|
|
102
|
+
import { CAPABILITY_DESCRIPTORS as CAPABILITY_DESCRIPTORS2, isClearedRunStateBlob, prefixedMcpToolName as sharedPrefixedMcpToolName, signDelegatedAccessToken } from "@opengeni/contracts";
|
|
103
103
|
import {
|
|
104
104
|
Agent,
|
|
105
105
|
AgentsError,
|
|
@@ -150,7 +150,7 @@ import { fileURLToPath } from "url";
|
|
|
150
150
|
var SCREENSHOT_FAILURE_CARD_IMAGE_URL = "data:image/png;base64,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";
|
|
151
151
|
|
|
152
152
|
// src/history-sanitizer.ts
|
|
153
|
-
var
|
|
153
|
+
var TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE = {
|
|
154
154
|
function_call: "function_call_result",
|
|
155
155
|
computer_call: "computer_call_result",
|
|
156
156
|
shell_call: "shell_call_output",
|
|
@@ -163,6 +163,7 @@ var RESULT_TYPE_BY_CALL_TYPE = {
|
|
|
163
163
|
// additionally ride providerData (see callIdOf).
|
|
164
164
|
tool_search_call: "tool_search_output"
|
|
165
165
|
};
|
|
166
|
+
var RESULT_TYPE_BY_CALL_TYPE = TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE;
|
|
166
167
|
var RESULT_TYPES = new Set(Object.values(RESULT_TYPE_BY_CALL_TYPE));
|
|
167
168
|
function itemType(item) {
|
|
168
169
|
if (!item || typeof item !== "object") {
|
|
@@ -795,7 +796,10 @@ function installCodexToolSearch(agent, connectorNamespaces = NO_NAMESPACES) {
|
|
|
795
796
|
var COMPACTION_SUMMARY_MARKER = "opengeni_context_summary";
|
|
796
797
|
var SUMMARY_BUFFER_TOKENS = 2e4;
|
|
797
798
|
var COMPACT_USER_MESSAGE_MAX_TOKENS = 2e4;
|
|
798
|
-
var
|
|
799
|
+
var DEFAULT_COMPACTION_THRESHOLD_RATIO = 0.6;
|
|
800
|
+
var MIN_COMPACTION_THRESHOLD_RATIO = 0.3;
|
|
801
|
+
var MAX_COMPACTION_THRESHOLD_RATIO = 0.9;
|
|
802
|
+
var COMPACTION_FALLBACK_TARGET_RATIO = 0.5;
|
|
799
803
|
var COMPACTION_PROMPT = [
|
|
800
804
|
"You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.",
|
|
801
805
|
"",
|
|
@@ -809,12 +813,7 @@ var COMPACTION_PROMPT = [
|
|
|
809
813
|
].join("\n");
|
|
810
814
|
var SUMMARY_PREFIX = "Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:";
|
|
811
815
|
var USER_MESSAGE_TRUNCATION_MARKER = "\n[... middle truncated for context compaction ...]\n";
|
|
812
|
-
var RESULT_TYPE_BY_CALL_TYPE2 =
|
|
813
|
-
function_call: "function_call_result",
|
|
814
|
-
computer_call: "computer_call_result",
|
|
815
|
-
shell_call: "shell_call_output",
|
|
816
|
-
apply_patch_call: "apply_patch_call_output"
|
|
817
|
-
};
|
|
816
|
+
var RESULT_TYPE_BY_CALL_TYPE2 = TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE;
|
|
818
817
|
var RESULT_TYPES2 = new Set(Object.values(RESULT_TYPE_BY_CALL_TYPE2));
|
|
819
818
|
function itemType2(item) {
|
|
820
819
|
if (!item || typeof item !== "object") {
|
|
@@ -852,12 +851,12 @@ function estimateTokens(items) {
|
|
|
852
851
|
}
|
|
853
852
|
return total;
|
|
854
853
|
}
|
|
854
|
+
function clampCompactionThresholdRatio(value) {
|
|
855
|
+
const numeric = typeof value === "number" && Number.isFinite(value) ? value : DEFAULT_COMPACTION_THRESHOLD_RATIO;
|
|
856
|
+
return Math.min(MAX_COMPACTION_THRESHOLD_RATIO, Math.max(MIN_COMPACTION_THRESHOLD_RATIO, numeric));
|
|
857
|
+
}
|
|
855
858
|
function clientCompactionThresholdTokens(input) {
|
|
856
|
-
|
|
857
|
-
0,
|
|
858
|
-
input.contextWindowTokens - input.contextReservedOutputTokens - SUMMARY_BUFFER_TOKENS
|
|
859
|
-
);
|
|
860
|
-
return Math.floor(available * CLIENT_COMPACTION_TRIGGER_FRACTION);
|
|
859
|
+
return Math.floor(Math.max(0, input.contextWindowTokens) * clampCompactionThresholdRatio(input.contextCompactionThresholdRatio));
|
|
861
860
|
}
|
|
862
861
|
function decideClientCompaction(input) {
|
|
863
862
|
const thresholdTokens = clientCompactionThresholdTokens(input);
|
|
@@ -959,6 +958,58 @@ function buildCompactionReplacementHistory(items, summaryBody) {
|
|
|
959
958
|
history.push(buildSummaryItem(summaryBody));
|
|
960
959
|
return history;
|
|
961
960
|
}
|
|
961
|
+
function buildDeterministicFallbackCompactionHistory(input) {
|
|
962
|
+
const sourceTokens = Math.max(1, estimateTokens(input.items));
|
|
963
|
+
const requestedTarget = typeof input.targetTokens === "number" && input.targetTokens > 0 ? Math.floor(input.targetTokens) : Math.floor(sourceTokens * COMPACTION_FALLBACK_TARGET_RATIO);
|
|
964
|
+
const targetTokens = Math.max(1, Math.min(requestedTarget, Math.max(1, sourceTokens - 1)));
|
|
965
|
+
const summaryItem = buildSummaryItem([
|
|
966
|
+
"Non-LLM context compaction fallback.",
|
|
967
|
+
input.cause ? `Summarizer failure: ${input.cause}` : "Summarizer failure: unavailable.",
|
|
968
|
+
"Older assistant, tool, reasoning, and image history was dropped deterministically.",
|
|
969
|
+
"Retained context above is limited to initial instructions and the most recent user messages that fit the fallback budget; oversized retained messages may be middle-truncated."
|
|
970
|
+
].join("\n"));
|
|
971
|
+
const summaryTokens = estimateItemTokens(summaryItem);
|
|
972
|
+
let remaining = Math.max(0, targetTokens - summaryTokens);
|
|
973
|
+
const retainedInstructions = [];
|
|
974
|
+
for (const item of input.items) {
|
|
975
|
+
if (!isInitialInstructionMessage(item)) {
|
|
976
|
+
if (isUserMessage(item)) {
|
|
977
|
+
break;
|
|
978
|
+
}
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
if (remaining <= 0) {
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
984
|
+
const capped = compactMessageToEstimatedItemBudget(item, Math.min(2e3, remaining));
|
|
985
|
+
if (!capped) {
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
const tokens = estimateItemTokens(capped);
|
|
989
|
+
if (tokens <= remaining) {
|
|
990
|
+
retainedInstructions.push(capped);
|
|
991
|
+
remaining -= tokens;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
const retainedUsers = [];
|
|
995
|
+
for (let index = input.items.length - 1; index >= 0 && remaining > 0; index -= 1) {
|
|
996
|
+
const item = input.items[index];
|
|
997
|
+
if (!isUserMessage(item) || isCompactionSummary(item)) {
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
const capped = compactMessageToEstimatedItemBudget(item, Math.min(COMPACT_USER_MESSAGE_MAX_TOKENS, remaining));
|
|
1001
|
+
if (!capped) {
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
const tokens = estimateItemTokens(capped);
|
|
1005
|
+
if (tokens <= remaining) {
|
|
1006
|
+
retainedUsers.push(capped);
|
|
1007
|
+
remaining -= tokens;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
retainedUsers.reverse();
|
|
1011
|
+
return [...retainedInstructions, ...retainedUsers, summaryItem];
|
|
1012
|
+
}
|
|
962
1013
|
function buildSummaryItem(summaryBody) {
|
|
963
1014
|
const trimmed = summaryBody.trim();
|
|
964
1015
|
return {
|
|
@@ -970,15 +1021,38 @@ ${trimmed}`,
|
|
|
970
1021
|
};
|
|
971
1022
|
}
|
|
972
1023
|
function compactUserMessage(item) {
|
|
1024
|
+
return compactMessageToTokenBudget(item, COMPACT_USER_MESSAGE_MAX_TOKENS);
|
|
1025
|
+
}
|
|
1026
|
+
function compactMessageToTokenBudget(item, maxTokens) {
|
|
973
1027
|
const text = messageText(item);
|
|
974
1028
|
const next = { ...item };
|
|
975
|
-
if (estimatedTextTokens(text) >
|
|
976
|
-
next.content = truncateMiddleByEstimatedTokens(text,
|
|
1029
|
+
if (estimatedTextTokens(text) > maxTokens) {
|
|
1030
|
+
next.content = truncateMiddleByEstimatedTokens(text, maxTokens);
|
|
977
1031
|
return next;
|
|
978
1032
|
}
|
|
979
1033
|
next.content = contentWithoutImages(item);
|
|
980
1034
|
return next;
|
|
981
1035
|
}
|
|
1036
|
+
function compactMessageToEstimatedItemBudget(item, maxItemTokens) {
|
|
1037
|
+
if (maxItemTokens <= 0) {
|
|
1038
|
+
return null;
|
|
1039
|
+
}
|
|
1040
|
+
const overheadTokens = estimateItemTokens({ ...item, content: "" });
|
|
1041
|
+
let contentBudget = Math.max(0, maxItemTokens - overheadTokens);
|
|
1042
|
+
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
1043
|
+
const capped = compactMessageToTokenBudget(item, contentBudget);
|
|
1044
|
+
const estimated = estimateItemTokens(capped);
|
|
1045
|
+
if (estimated <= maxItemTokens) {
|
|
1046
|
+
return capped;
|
|
1047
|
+
}
|
|
1048
|
+
const overage = estimated - maxItemTokens;
|
|
1049
|
+
if (contentBudget <= 0) {
|
|
1050
|
+
break;
|
|
1051
|
+
}
|
|
1052
|
+
contentBudget = Math.max(0, contentBudget - Math.max(1, overage));
|
|
1053
|
+
}
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
982
1056
|
function estimatedTextTokens(text) {
|
|
983
1057
|
return Math.ceil(text.length / 4);
|
|
984
1058
|
}
|
|
@@ -1029,8 +1103,29 @@ function messageText(item) {
|
|
|
1029
1103
|
}
|
|
1030
1104
|
return "";
|
|
1031
1105
|
}
|
|
1032
|
-
function
|
|
1033
|
-
|
|
1106
|
+
function isInitialInstructionMessage(item) {
|
|
1107
|
+
const type = itemType2(item);
|
|
1108
|
+
const role = itemRole(item);
|
|
1109
|
+
return type === "message" && (role === "system" || role === "developer");
|
|
1110
|
+
}
|
|
1111
|
+
function renderCompactionPromptInputForChat(input, options = {}) {
|
|
1112
|
+
const rendered = input.map(renderItem);
|
|
1113
|
+
if (typeof options.maxEstimatedTokens !== "number" || options.maxEstimatedTokens <= 0) {
|
|
1114
|
+
return rendered.join("\n");
|
|
1115
|
+
}
|
|
1116
|
+
const maxChars = Math.max(1, Math.floor(options.maxEstimatedTokens * 4));
|
|
1117
|
+
const last = rendered.at(-1);
|
|
1118
|
+
const prefix = rendered.slice(0, -1);
|
|
1119
|
+
let kept = prefix.slice();
|
|
1120
|
+
while (kept.length > 0 && transcriptLength([...kept, last].filter((line) => line !== void 0)) > maxChars) {
|
|
1121
|
+
kept.shift();
|
|
1122
|
+
}
|
|
1123
|
+
const lines = [...kept, last].filter((line) => line !== void 0);
|
|
1124
|
+
const joined = lines.join("\n");
|
|
1125
|
+
if (joined.length <= maxChars) {
|
|
1126
|
+
return joined;
|
|
1127
|
+
}
|
|
1128
|
+
return truncateMiddleByChars(joined, maxChars);
|
|
1034
1129
|
}
|
|
1035
1130
|
function renderItem(item) {
|
|
1036
1131
|
const type = itemType2(item) ?? "unknown";
|
|
@@ -1076,6 +1171,24 @@ function truncateForTranscript(text, max) {
|
|
|
1076
1171
|
}
|
|
1077
1172
|
return `${text.slice(0, max)}... (${text.length - max} more chars)`;
|
|
1078
1173
|
}
|
|
1174
|
+
function transcriptLength(lines) {
|
|
1175
|
+
if (lines.length === 0) {
|
|
1176
|
+
return 0;
|
|
1177
|
+
}
|
|
1178
|
+
return lines.reduce((sum, line) => sum + line.length, 0) + Math.max(0, lines.length - 1);
|
|
1179
|
+
}
|
|
1180
|
+
function truncateMiddleByChars(text, maxChars) {
|
|
1181
|
+
if (text.length <= maxChars) {
|
|
1182
|
+
return text;
|
|
1183
|
+
}
|
|
1184
|
+
if (maxChars <= USER_MESSAGE_TRUNCATION_MARKER.length) {
|
|
1185
|
+
return USER_MESSAGE_TRUNCATION_MARKER.slice(0, maxChars);
|
|
1186
|
+
}
|
|
1187
|
+
const keepChars = maxChars - USER_MESSAGE_TRUNCATION_MARKER.length;
|
|
1188
|
+
const headChars = Math.ceil(keepChars / 2);
|
|
1189
|
+
const tailChars = Math.floor(keepChars / 2);
|
|
1190
|
+
return `${text.slice(0, headChars)}${USER_MESSAGE_TRUNCATION_MARKER}${text.slice(text.length - tailChars)}`;
|
|
1191
|
+
}
|
|
1079
1192
|
|
|
1080
1193
|
// src/sandbox-computer.ts
|
|
1081
1194
|
import { computerTool, tool } from "@openai/agents";
|
|
@@ -1939,12 +2052,16 @@ async function summarizeForCompaction(settings, input, options = {}) {
|
|
|
1939
2052
|
const api = options.api ?? "responses";
|
|
1940
2053
|
const model = options.model ?? settings.openaiModel;
|
|
1941
2054
|
const maxTokens = options.maxOutputTokens ?? SUMMARY_BUFFER_TOKENS;
|
|
2055
|
+
const transcript = renderCompactionPromptInputForChat(
|
|
2056
|
+
input,
|
|
2057
|
+
typeof options.maxTranscriptTokens === "number" && options.maxTranscriptTokens > 0 ? { maxEstimatedTokens: options.maxTranscriptTokens } : {}
|
|
2058
|
+
);
|
|
1942
2059
|
try {
|
|
1943
2060
|
if (api === "chat") {
|
|
1944
2061
|
const completion = await client.chat.completions.create({
|
|
1945
2062
|
model,
|
|
1946
2063
|
max_tokens: maxTokens,
|
|
1947
|
-
messages: [{ role: "user", content:
|
|
2064
|
+
messages: [{ role: "user", content: transcript }]
|
|
1948
2065
|
});
|
|
1949
2066
|
const text2 = completion.choices?.[0]?.message?.content;
|
|
1950
2067
|
const trimmed2 = typeof text2 === "string" ? text2.trim() : "";
|
|
@@ -1957,13 +2074,13 @@ async function summarizeForCompaction(settings, input, options = {}) {
|
|
|
1957
2074
|
// built-in path (api "responses"), so gate it on the built-in provider.
|
|
1958
2075
|
...settings.openaiProvider === "azure" ? {} : { store: false },
|
|
1959
2076
|
max_output_tokens: maxTokens,
|
|
1960
|
-
input
|
|
2077
|
+
input: transcript
|
|
1961
2078
|
});
|
|
1962
2079
|
const text = extractResponseOutputText(response);
|
|
1963
2080
|
const trimmed = text.trim();
|
|
1964
2081
|
return trimmed.length > 0 ? trimmed : null;
|
|
1965
2082
|
} catch (error) {
|
|
1966
|
-
console.error("context compaction summarize failed
|
|
2083
|
+
console.error("context compaction summarize failed", error);
|
|
1967
2084
|
return null;
|
|
1968
2085
|
}
|
|
1969
2086
|
}
|
|
@@ -2039,7 +2156,13 @@ function appendGenesisTitleDirective(instructions, genesisTitleHint) {
|
|
|
2039
2156
|
var agentFileDownloads = /* @__PURE__ */ new WeakMap();
|
|
2040
2157
|
var agentRepositoryCloneHooks = /* @__PURE__ */ new WeakMap();
|
|
2041
2158
|
var agentGitTokenSeed = /* @__PURE__ */ new WeakMap();
|
|
2159
|
+
var agentToolspaceTokenSeed = /* @__PURE__ */ new WeakMap();
|
|
2042
2160
|
var agentActiveSandboxBackend = /* @__PURE__ */ new WeakMap();
|
|
2161
|
+
function mcpToolErrorOutput(error) {
|
|
2162
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
2163
|
+
return { isError: true, content: [{ type: "text", text: `An error occurred while running the tool. Please try again. Error: ${details}` }] };
|
|
2164
|
+
}
|
|
2165
|
+
var mcpToolErrorFunction = ({ error }) => mcpToolErrorOutput(error);
|
|
2043
2166
|
function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
2044
2167
|
const compactionMode = options.compactionMode ?? resolveContextCompactionMode(settings);
|
|
2045
2168
|
const hostedWebSearch = options.hostedWebSearch ?? settings.webSearchEnabled;
|
|
@@ -2098,11 +2221,19 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
|
2098
2221
|
// `new SandboxAgent({ ...baseConfig, ... })` path via the shared baseConfig
|
|
2099
2222
|
// spread; the SDK concatenates these with MCP and sandbox capability tools.
|
|
2100
2223
|
...hostedTools.length ? { tools: hostedTools } : {},
|
|
2101
|
-
...options.mcpServers?.length ? { mcpServers: options.mcpServers } : {}
|
|
2224
|
+
...options.mcpServers?.length ? { mcpServers: options.mcpServers } : {},
|
|
2225
|
+
// Surface FAILED MCP tool calls as `{ isError: true }` tool output (see
|
|
2226
|
+
// mcpToolErrorFunction / mcpToolErrorOutput) instead of the SDK's default
|
|
2227
|
+
// flat error string, so a thrown MCP failure (protocol error, auth, timeout,
|
|
2228
|
+
// tool-not-found) settles the timeline tool to "failed" rather than rendering
|
|
2229
|
+
// as success. Applies to every MCP server on this agent (session, first-party,
|
|
2230
|
+
// capability, codex_apps) since none set a server-level errorFunction.
|
|
2231
|
+
mcpConfig: { errorFunction: mcpToolErrorFunction }
|
|
2102
2232
|
};
|
|
2103
2233
|
if (settings.sandboxBackend === "none") {
|
|
2104
2234
|
const agent2 = new Agent(baseConfig);
|
|
2105
2235
|
maybeInstallCodexToolSearch(agent2, settings, options);
|
|
2236
|
+
applyMcpApprovalPolicy(agent2, settings);
|
|
2106
2237
|
return agent2;
|
|
2107
2238
|
}
|
|
2108
2239
|
const runAs = sandboxRunAs(settings);
|
|
@@ -2125,7 +2256,11 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
|
2125
2256
|
if (options.gitTokenSeed) {
|
|
2126
2257
|
agentGitTokenSeed.set(agent, options.gitTokenSeed);
|
|
2127
2258
|
}
|
|
2259
|
+
if (options.toolspaceTokenSeed) {
|
|
2260
|
+
agentToolspaceTokenSeed.set(agent, options.toolspaceTokenSeed);
|
|
2261
|
+
}
|
|
2128
2262
|
maybeInstallCodexToolSearch(agent, settings, options);
|
|
2263
|
+
applyMcpApprovalPolicy(agent, settings);
|
|
2129
2264
|
return agent;
|
|
2130
2265
|
}
|
|
2131
2266
|
function maybeInstallCodexToolSearch(agent, settings, options) {
|
|
@@ -2136,6 +2271,41 @@ function maybeInstallCodexToolSearch(agent, settings, options) {
|
|
|
2136
2271
|
);
|
|
2137
2272
|
}
|
|
2138
2273
|
}
|
|
2274
|
+
function mcpToolRequiresApproval(policy, unprefixedName) {
|
|
2275
|
+
return policy === true || Array.isArray(policy) && policy.includes(unprefixedName);
|
|
2276
|
+
}
|
|
2277
|
+
function installMcpApprovalPolicy(agent, policies) {
|
|
2278
|
+
const listMcpTools = agent.getMcpTools.bind(agent);
|
|
2279
|
+
agent.getMcpTools = async (runContext) => {
|
|
2280
|
+
const tools = await listMcpTools(runContext);
|
|
2281
|
+
return tools.map((tool2) => {
|
|
2282
|
+
if (tool2.type !== "function") {
|
|
2283
|
+
return tool2;
|
|
2284
|
+
}
|
|
2285
|
+
const policy = policies.find((entry) => tool2.name.startsWith(entry.prefix));
|
|
2286
|
+
if (!policy) {
|
|
2287
|
+
return tool2;
|
|
2288
|
+
}
|
|
2289
|
+
const unprefixed = tool2.name.slice(policy.prefix.length);
|
|
2290
|
+
return mcpToolRequiresApproval(policy.requireApproval, unprefixed) ? { ...tool2, needsApproval: async () => true } : tool2;
|
|
2291
|
+
});
|
|
2292
|
+
};
|
|
2293
|
+
const originalClone = agent.clone?.bind(agent);
|
|
2294
|
+
if (originalClone) {
|
|
2295
|
+
agent.clone = (config) => {
|
|
2296
|
+
const cloned = originalClone(config);
|
|
2297
|
+
installMcpApprovalPolicy(cloned, policies);
|
|
2298
|
+
return cloned;
|
|
2299
|
+
};
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
function applyMcpApprovalPolicy(agent, settings) {
|
|
2303
|
+
const policies = settings.mcpServers.filter((server) => server.requireApproval === true || Array.isArray(server.requireApproval) && server.requireApproval.length > 0).map((server) => ({ prefix: prefixedMcpToolName(server.id, ""), requireApproval: server.requireApproval })).sort((a, b) => b.prefix.length - a.prefix.length);
|
|
2304
|
+
if (policies.length === 0) {
|
|
2305
|
+
return;
|
|
2306
|
+
}
|
|
2307
|
+
installMcpApprovalPolicy(agent, policies);
|
|
2308
|
+
}
|
|
2139
2309
|
function neutralizeStructuredToolTransport(capability) {
|
|
2140
2310
|
const forceFunctionTransport = function() {
|
|
2141
2311
|
this._modelInstance = void 0;
|
|
@@ -2185,6 +2355,8 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2185
2355
|
throw new Error(`Unknown MCP server id: ${tool2.id}`);
|
|
2186
2356
|
}
|
|
2187
2357
|
const url = firstPartyMcpServerUrlForRun(settings, config, options.workspaceId) ?? config.url;
|
|
2358
|
+
const baseFetch = isCodexAppsMcpServer(config) ? codexAppsSanitizingFetch(globalThis.fetch, codexConnectorNamespaces) : globalThis.fetch;
|
|
2359
|
+
const fetchImpl = config.connectionRef ? connectionBrokerFetch(baseFetch, config, options) : baseFetch;
|
|
2188
2360
|
const server = new PrefixedMcpServer(new MCPServerStreamableHttp({
|
|
2189
2361
|
url,
|
|
2190
2362
|
name: config.name ?? config.id,
|
|
@@ -2193,7 +2365,7 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2193
2365
|
// MCP SDK's strict Tool schema rejects (fails the turn during tools/list);
|
|
2194
2366
|
// sanitize the response on the wire before validation. The namespace Set
|
|
2195
2367
|
// also captures each tool's original connector namespace (P4 Part B.1).
|
|
2196
|
-
...
|
|
2368
|
+
...fetchImpl !== globalThis.fetch ? { fetch: fetchImpl } : {},
|
|
2197
2369
|
...await mcpServerRequestInit(settings, config, options),
|
|
2198
2370
|
...config.timeoutMs ? {
|
|
2199
2371
|
timeout: config.timeoutMs,
|
|
@@ -2201,7 +2373,7 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2201
2373
|
} : {}
|
|
2202
2374
|
}), config.id, config.allowedTools);
|
|
2203
2375
|
const optional = tool2.optional === true;
|
|
2204
|
-
return { server, bestEffort: isCodexAppsMcpServer(config) || optional, optional };
|
|
2376
|
+
return { server, bestEffort: isCodexAppsMcpServer(config) || optional || !!config.connectionRef, optional };
|
|
2205
2377
|
}));
|
|
2206
2378
|
const requiredServers = servers.filter((entry) => !entry.bestEffort).map((entry) => entry.server);
|
|
2207
2379
|
const bestEffortServers = servers.filter((entry) => entry.bestEffort).map((entry) => entry.server);
|
|
@@ -2239,6 +2411,190 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2239
2411
|
codexConnectorNamespaces
|
|
2240
2412
|
};
|
|
2241
2413
|
}
|
|
2414
|
+
function connectionBrokerFetch(baseFetch, config, options) {
|
|
2415
|
+
const connectionRef = config.connectionRef;
|
|
2416
|
+
if (!connectionRef) {
|
|
2417
|
+
return baseFetch;
|
|
2418
|
+
}
|
|
2419
|
+
return async (input, init) => {
|
|
2420
|
+
const request = await mcpRequestInfo(input, init);
|
|
2421
|
+
const first = await resolveConnectionForRequest(options, config.id, connectionRef, request.toolName, false);
|
|
2422
|
+
if (first.status === "auth_needed") {
|
|
2423
|
+
return await authNeededFetchResponse(options, config.id, request, first, connectionRef);
|
|
2424
|
+
}
|
|
2425
|
+
const response = await baseFetch(fetchInputForAttempt(input), withConnectionHeaders(input, init, first.headers));
|
|
2426
|
+
if (response.status === 401) {
|
|
2427
|
+
const refreshed = await resolveConnectionForRequest(options, config.id, connectionRef, request.toolName, true);
|
|
2428
|
+
if (refreshed.status === "auth_needed") {
|
|
2429
|
+
return await authNeededFetchResponse(options, config.id, request, refreshed, connectionRef);
|
|
2430
|
+
}
|
|
2431
|
+
const retry = await baseFetch(fetchInputForAttempt(input), withConnectionHeaders(input, init, refreshed.headers));
|
|
2432
|
+
if (retry.status === 403) {
|
|
2433
|
+
const auth = insufficientScopeAuth(retry.headers, connectionRef, refreshed.connectionId);
|
|
2434
|
+
return auth ? await authNeededFetchResponse(options, config.id, request, auth, connectionRef) : retry;
|
|
2435
|
+
}
|
|
2436
|
+
if (retry.status === 401) {
|
|
2437
|
+
return await authNeededFetchResponse(options, config.id, request, {
|
|
2438
|
+
status: "auth_needed",
|
|
2439
|
+
reason: "expired",
|
|
2440
|
+
providerDomain: connectionRef.providerDomain,
|
|
2441
|
+
connectionId: refreshed.connectionId,
|
|
2442
|
+
...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2443
|
+
...connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2444
|
+
}, connectionRef);
|
|
2445
|
+
}
|
|
2446
|
+
return retry;
|
|
2447
|
+
}
|
|
2448
|
+
if (response.status === 403) {
|
|
2449
|
+
const auth = insufficientScopeAuth(response.headers, connectionRef, first.connectionId);
|
|
2450
|
+
return auth ? await authNeededFetchResponse(options, config.id, request, auth, connectionRef) : response;
|
|
2451
|
+
}
|
|
2452
|
+
return response;
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
async function resolveConnectionForRequest(options, serverId, connectionRef, toolName, forceRefresh) {
|
|
2456
|
+
if (!options.workspaceId || !options.resolveCredential) {
|
|
2457
|
+
return {
|
|
2458
|
+
status: "auth_needed",
|
|
2459
|
+
reason: "missing_connection",
|
|
2460
|
+
providerDomain: connectionRef.providerDomain,
|
|
2461
|
+
...connectionRef.connectionId ? { connectionId: connectionRef.connectionId } : {},
|
|
2462
|
+
...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2463
|
+
...connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
const request = {
|
|
2467
|
+
workspaceId: options.workspaceId,
|
|
2468
|
+
serverId,
|
|
2469
|
+
connectionRef,
|
|
2470
|
+
forceRefresh,
|
|
2471
|
+
...toolName ? { toolName } : {},
|
|
2472
|
+
...options.subjectId ? { subjectId: options.subjectId } : {}
|
|
2473
|
+
};
|
|
2474
|
+
try {
|
|
2475
|
+
return await options.resolveCredential(request);
|
|
2476
|
+
} catch {
|
|
2477
|
+
return {
|
|
2478
|
+
status: "auth_needed",
|
|
2479
|
+
reason: "refresh_failed",
|
|
2480
|
+
providerDomain: connectionRef.providerDomain,
|
|
2481
|
+
...connectionRef.connectionId ? { connectionId: connectionRef.connectionId } : {},
|
|
2482
|
+
...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2483
|
+
...connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2484
|
+
};
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
function insufficientScopeAuth(headers, connectionRef, connectionId) {
|
|
2488
|
+
const challenge = parseWwwAuthenticate(headers.get("www-authenticate"));
|
|
2489
|
+
if (challenge.error !== "insufficient_scope") {
|
|
2490
|
+
return null;
|
|
2491
|
+
}
|
|
2492
|
+
return {
|
|
2493
|
+
status: "auth_needed",
|
|
2494
|
+
reason: "insufficient_scope",
|
|
2495
|
+
providerDomain: connectionRef.providerDomain,
|
|
2496
|
+
connectionId,
|
|
2497
|
+
...challenge.scope?.length ? { scopes: challenge.scope } : connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2498
|
+
...challenge.resource ? { resource: challenge.resource } : connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
async function authNeededFetchResponse(options, serverId, request, auth, connectionRef) {
|
|
2502
|
+
const connectionId = auth.connectionId ?? connectionRef.connectionId;
|
|
2503
|
+
await publishAuthNeeded(options, {
|
|
2504
|
+
serverId,
|
|
2505
|
+
toolName: request.toolName ?? null,
|
|
2506
|
+
providerDomain: auth.providerDomain,
|
|
2507
|
+
reason: auth.reason,
|
|
2508
|
+
...connectionId ? { connectionId } : {},
|
|
2509
|
+
...auth.scopes ? { scopes: auth.scopes } : connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2510
|
+
...auth.resource ? { resource: auth.resource } : connectionRef.resource ? { resource: connectionRef.resource } : {},
|
|
2511
|
+
...auth.authorizationUrl ? { authorizationUrl: auth.authorizationUrl } : {},
|
|
2512
|
+
...options.subjectId ? { subjectId: options.subjectId } : {}
|
|
2513
|
+
});
|
|
2514
|
+
if (request.method === "tools/call") {
|
|
2515
|
+
return mcpToolAuthNeededResponse(request.id);
|
|
2516
|
+
}
|
|
2517
|
+
return new Response("Authentication required for MCP server connection", { status: 401 });
|
|
2518
|
+
}
|
|
2519
|
+
async function publishAuthNeeded(options, payload) {
|
|
2520
|
+
try {
|
|
2521
|
+
await options.onAuthNeeded?.(payload);
|
|
2522
|
+
} catch {
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
async function mcpRequestInfo(input, init) {
|
|
2526
|
+
const body = typeof init?.body === "string" ? init.body : input instanceof Request && (init?.method ?? input.method).toUpperCase() === "POST" ? await input.clone().text().catch(() => "") : "";
|
|
2527
|
+
if (!body) {
|
|
2528
|
+
return {};
|
|
2529
|
+
}
|
|
2530
|
+
try {
|
|
2531
|
+
const parsed = JSON.parse(body);
|
|
2532
|
+
const method = typeof parsed.method === "string" ? parsed.method : void 0;
|
|
2533
|
+
const id = typeof parsed.id === "string" || typeof parsed.id === "number" || parsed.id === null ? parsed.id : void 0;
|
|
2534
|
+
const toolName = method === "tools/call" && typeof parsed.params?.name === "string" ? parsed.params.name : void 0;
|
|
2535
|
+
return {
|
|
2536
|
+
...method ? { method } : {},
|
|
2537
|
+
...id !== void 0 ? { id } : {},
|
|
2538
|
+
...toolName ? { toolName } : {}
|
|
2539
|
+
};
|
|
2540
|
+
} catch {
|
|
2541
|
+
return {};
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
function withConnectionHeaders(input, init, authHeaders) {
|
|
2545
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
2546
|
+
for (const [name, value] of Object.entries(authHeaders)) {
|
|
2547
|
+
headers.set(name, value);
|
|
2548
|
+
}
|
|
2549
|
+
return { ...init, headers };
|
|
2550
|
+
}
|
|
2551
|
+
function fetchInputForAttempt(input) {
|
|
2552
|
+
return input instanceof Request ? input.clone() : input;
|
|
2553
|
+
}
|
|
2554
|
+
function parseWwwAuthenticate(header) {
|
|
2555
|
+
if (!header) {
|
|
2556
|
+
return {};
|
|
2557
|
+
}
|
|
2558
|
+
const bearerIndex = header.toLowerCase().indexOf("bearer");
|
|
2559
|
+
if (bearerIndex < 0) {
|
|
2560
|
+
return {};
|
|
2561
|
+
}
|
|
2562
|
+
const paramsText = header.slice(bearerIndex + "bearer".length);
|
|
2563
|
+
const params = {};
|
|
2564
|
+
const re = /([a-zA-Z_][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|[^,\s]+)/g;
|
|
2565
|
+
let match;
|
|
2566
|
+
while ((match = re.exec(paramsText)) !== null) {
|
|
2567
|
+
const raw = match[2];
|
|
2568
|
+
params[match[1].toLowerCase()] = raw.startsWith('"') ? raw.slice(1, -1).replace(/\\"/g, '"') : raw;
|
|
2569
|
+
}
|
|
2570
|
+
return {
|
|
2571
|
+
...params.error ? { error: params.error } : {},
|
|
2572
|
+
...params.scope ? { scope: params.scope.split(/\s+/).filter(Boolean) } : {},
|
|
2573
|
+
...params.resource ? { resource: params.resource } : {}
|
|
2574
|
+
};
|
|
2575
|
+
}
|
|
2576
|
+
var MCP_AUTH_NEEDED_ERROR_CODE = -32001;
|
|
2577
|
+
var MCP_AUTH_NEEDED_MESSAGE = "Authentication required - a connection link was posted to the session.";
|
|
2578
|
+
function mcpToolAuthNeededResponse(id) {
|
|
2579
|
+
return new Response(JSON.stringify({
|
|
2580
|
+
jsonrpc: "2.0",
|
|
2581
|
+
id: id ?? null,
|
|
2582
|
+
error: {
|
|
2583
|
+
code: MCP_AUTH_NEEDED_ERROR_CODE,
|
|
2584
|
+
message: MCP_AUTH_NEEDED_MESSAGE
|
|
2585
|
+
}
|
|
2586
|
+
}), {
|
|
2587
|
+
status: 200,
|
|
2588
|
+
headers: { "content-type": "application/json" }
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
function isAuthNeededMcpError(error) {
|
|
2592
|
+
if (!(error instanceof Error)) {
|
|
2593
|
+
return false;
|
|
2594
|
+
}
|
|
2595
|
+
const code = error.code;
|
|
2596
|
+
return code === MCP_AUTH_NEEDED_ERROR_CODE || error.message.includes(MCP_AUTH_NEEDED_MESSAGE);
|
|
2597
|
+
}
|
|
2242
2598
|
async function mcpServerRequestInit(settings, config, options) {
|
|
2243
2599
|
if (isCodexAppsMcpServer(config)) {
|
|
2244
2600
|
return await codexAppsMcpRequestInit(settings);
|
|
@@ -2382,7 +2738,7 @@ function normalizeUrl(raw) {
|
|
|
2382
2738
|
}
|
|
2383
2739
|
}
|
|
2384
2740
|
function prefixedMcpToolName(registryId, toolName) {
|
|
2385
|
-
return
|
|
2741
|
+
return sharedPrefixedMcpToolName(registryId, toolName);
|
|
2386
2742
|
}
|
|
2387
2743
|
var PrefixedMcpServer = class {
|
|
2388
2744
|
constructor(inner, registryId, allowedTools) {
|
|
@@ -2412,7 +2768,14 @@ var PrefixedMcpServer = class {
|
|
|
2412
2768
|
if (!this.isAllowed(unprefixed)) {
|
|
2413
2769
|
throw new Error(`MCP tool ${unprefixed} is not allowed for server ${this.name}`);
|
|
2414
2770
|
}
|
|
2415
|
-
|
|
2771
|
+
try {
|
|
2772
|
+
return await this.inner.callTool(unprefixed, args, meta);
|
|
2773
|
+
} catch (error) {
|
|
2774
|
+
if (isAuthNeededMcpError(error)) {
|
|
2775
|
+
return { isError: true, content: [{ type: "text", text: MCP_AUTH_NEEDED_MESSAGE }] };
|
|
2776
|
+
}
|
|
2777
|
+
throw error;
|
|
2778
|
+
}
|
|
2416
2779
|
}
|
|
2417
2780
|
invalidateToolsCache() {
|
|
2418
2781
|
return this.inner.invalidateToolsCache();
|
|
@@ -2623,15 +2986,18 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
|
|
|
2623
2986
|
...runAs2 ? { runAs: runAs2 } : {}
|
|
2624
2987
|
}) : ownedClient;
|
|
2625
2988
|
const ownedGitTokenSeed = gitTokenSeedForAgent(agent);
|
|
2989
|
+
const ownedToolspaceTokenSeed = toolspaceTokenSeedForAgent(agent);
|
|
2626
2990
|
const ownedHooks = [
|
|
2627
2991
|
...sandboxLifecycleHooksForIds(sandboxLifecycleHookIds(settings)),
|
|
2992
|
+
...sandboxToolspaceTokenHooksForAgent(agent),
|
|
2628
2993
|
...sandboxRepositoryCloneHooksForAgent(agent)
|
|
2629
2994
|
];
|
|
2630
2995
|
const ownedHookContext = {
|
|
2631
2996
|
environment,
|
|
2632
2997
|
...overrides.onRuntimeEvent ? { onRuntimeEvent: overrides.onRuntimeEvent } : {},
|
|
2633
2998
|
...runAs2 ? { runAs: runAs2 } : {},
|
|
2634
|
-
...ownedGitTokenSeed ? { gitTokenSeed: ownedGitTokenSeed } : {}
|
|
2999
|
+
...ownedGitTokenSeed ? { gitTokenSeed: ownedGitTokenSeed } : {},
|
|
3000
|
+
...ownedToolspaceTokenSeed ? { toolspaceTokenSeed: ownedToolspaceTokenSeed } : {}
|
|
2635
3001
|
};
|
|
2636
3002
|
if (agentActiveSandboxBackend.get(agent) !== "selfhosted") {
|
|
2637
3003
|
await runBeforeAgentStartHooks(setupSession, ownedHooks, ownedHookContext);
|
|
@@ -2675,14 +3041,17 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
|
|
|
2675
3041
|
...runAs ? { runAs } : {}
|
|
2676
3042
|
}) : refreshedClient;
|
|
2677
3043
|
const gitTokenSeed = gitTokenSeedForAgent(agent);
|
|
3044
|
+
const toolspaceTokenSeed = toolspaceTokenSeedForAgent(agent);
|
|
2678
3045
|
const client = resourceClient ? withSandboxLifecycleHooks(resourceClient, [
|
|
2679
3046
|
...sandboxLifecycleHooksForIds(sandboxLifecycleHookIds(settings)),
|
|
3047
|
+
...sandboxToolspaceTokenHooksForAgent(agent),
|
|
2680
3048
|
...sandboxRepositoryCloneHooksForAgent(agent)
|
|
2681
3049
|
], {
|
|
2682
3050
|
environment,
|
|
2683
3051
|
...overrides.onRuntimeEvent ? { onRuntimeEvent: overrides.onRuntimeEvent } : {},
|
|
2684
3052
|
...runAs ? { runAs } : {},
|
|
2685
|
-
...gitTokenSeed ? { gitTokenSeed } : {}
|
|
3053
|
+
...gitTokenSeed ? { gitTokenSeed } : {},
|
|
3054
|
+
...toolspaceTokenSeed ? { toolspaceTokenSeed } : {}
|
|
2686
3055
|
}) : void 0;
|
|
2687
3056
|
const sandboxSessionState = prepared.sandboxSessionState ?? (prepared.serializedRunStateForSandbox && client ? await restoredSandboxSessionState(await RunState.fromString(agent, prepared.serializedRunStateForSandbox), client) : void 0);
|
|
2688
3057
|
const callModelInputFilter = composeCallModelInputFilters(
|
|
@@ -3356,6 +3725,16 @@ function sandboxRepositoryCloneHooksForAgent(agent) {
|
|
|
3356
3725
|
function gitTokenSeedForAgent(agent) {
|
|
3357
3726
|
return agentGitTokenSeed.get(agent);
|
|
3358
3727
|
}
|
|
3728
|
+
function toolspaceTokenSeedForAgent(agent) {
|
|
3729
|
+
return agentToolspaceTokenSeed.get(agent);
|
|
3730
|
+
}
|
|
3731
|
+
function sandboxToolspaceTokenHooksForAgent(agent) {
|
|
3732
|
+
return toolspaceTokenSeedForAgent(agent) ? [{
|
|
3733
|
+
id: "toolspace-token",
|
|
3734
|
+
phase: "beforeAgentStart",
|
|
3735
|
+
run: runToolspaceTokenSeedHook
|
|
3736
|
+
}] : [];
|
|
3737
|
+
}
|
|
3359
3738
|
function sandboxRepositoryCloneHooks(settings, resources, activeSandboxBackend = settings.sandboxBackend) {
|
|
3360
3739
|
const repositories = resources.filter((resource) => resource.kind === "repository" && repositoryUsesSandboxClone(settings, resource, activeSandboxBackend));
|
|
3361
3740
|
if (repositories.length === 0) {
|
|
@@ -3526,6 +3905,49 @@ function repositoryCloneCommand(resources) {
|
|
|
3526
3905
|
}
|
|
3527
3906
|
return commands.join("\n");
|
|
3528
3907
|
}
|
|
3908
|
+
function toolspaceTokenSeedCommand() {
|
|
3909
|
+
return [
|
|
3910
|
+
"set -eu",
|
|
3911
|
+
'export HOME="${HOME:-/workspace}"',
|
|
3912
|
+
'if [ -n "${OPENGENI_TOOLSPACE_TOKEN_SEED:-}" ]; then',
|
|
3913
|
+
' seed_umask="$(umask)"',
|
|
3914
|
+
" umask 077",
|
|
3915
|
+
' token_file="${OPENGENI_TOOLSPACE_TOKEN_FILE:-$HOME/.opengeni/toolspace-token}"',
|
|
3916
|
+
' mkdir -p "$(dirname "$token_file")"',
|
|
3917
|
+
` printf '%s' "$OPENGENI_TOOLSPACE_TOKEN_SEED" > "$token_file.tmp.$$"`,
|
|
3918
|
+
' mv -f "$token_file.tmp.$$" "$token_file"',
|
|
3919
|
+
' umask "$seed_umask"',
|
|
3920
|
+
"fi"
|
|
3921
|
+
].join("\n");
|
|
3922
|
+
}
|
|
3923
|
+
async function runToolspaceTokenSeedHook(session, context) {
|
|
3924
|
+
if (!context.toolspaceTokenSeed) {
|
|
3925
|
+
return;
|
|
3926
|
+
}
|
|
3927
|
+
const command = `export OPENGENI_TOOLSPACE_TOKEN_SEED=${shellQuote(context.toolspaceTokenSeed)}
|
|
3928
|
+
${toolspaceTokenSeedCommand()}`;
|
|
3929
|
+
if (session.exec) {
|
|
3930
|
+
const result = await session.exec({
|
|
3931
|
+
cmd: command,
|
|
3932
|
+
workdir: "/workspace",
|
|
3933
|
+
...context.runAs ? { runAs: context.runAs } : {},
|
|
3934
|
+
yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
|
|
3935
|
+
maxOutputTokens: 4e3
|
|
3936
|
+
});
|
|
3937
|
+
assertSandboxCommandSucceeded(result, "Toolspace token seed hook");
|
|
3938
|
+
} else if (session.execCommand) {
|
|
3939
|
+
const result = await session.execCommand({
|
|
3940
|
+
cmd: command,
|
|
3941
|
+
workdir: "/workspace",
|
|
3942
|
+
...context.runAs ? { runAs: context.runAs } : {},
|
|
3943
|
+
yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
|
|
3944
|
+
maxOutputTokens: 4e3
|
|
3945
|
+
});
|
|
3946
|
+
assertSandboxCommandSucceeded(result, "Toolspace token seed hook");
|
|
3947
|
+
} else {
|
|
3948
|
+
throw new Error("Sandbox session does not support command execution");
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3529
3951
|
async function runRepositoryCloneHook(session, resources, context = { environment: {} }) {
|
|
3530
3952
|
const payload = { name: "repository-clone", repositoryCount: resources.length };
|
|
3531
3953
|
await context.onRuntimeEvent?.({ type: "sandbox.operation.started", payload });
|
|
@@ -3874,7 +4296,6 @@ function approvalIdentifier(item) {
|
|
|
3874
4296
|
export {
|
|
3875
4297
|
ActiveBackendUnresolvableError,
|
|
3876
4298
|
CAPABILITY_DESCRIPTORS,
|
|
3877
|
-
CLIENT_COMPACTION_TRIGGER_FRACTION,
|
|
3878
4299
|
COMPACTION_PROMPT,
|
|
3879
4300
|
COMPACTION_SUMMARY_MARKER,
|
|
3880
4301
|
COMPACT_USER_MESSAGE_MAX_TOKENS,
|
|
@@ -3888,12 +4309,15 @@ export {
|
|
|
3888
4309
|
ComputerReadOnlyError,
|
|
3889
4310
|
ComputerUnavailableError,
|
|
3890
4311
|
ComputerUseCapability,
|
|
4312
|
+
DEFAULT_COMPACTION_THRESHOLD_RATIO,
|
|
3891
4313
|
DEFAULT_DESKTOP_GEOMETRY,
|
|
3892
4314
|
DESKTOP_STREAM_PORT,
|
|
3893
4315
|
DISPLAY_STACK_TIMEOUT_MS,
|
|
3894
4316
|
DisplayStackError,
|
|
3895
4317
|
DisplayStackUnsupportedError,
|
|
3896
4318
|
GENESIS_TITLE_DIRECTIVE,
|
|
4319
|
+
MAX_COMPACTION_THRESHOLD_RATIO,
|
|
4320
|
+
MIN_COMPACTION_THRESHOLD_RATIO,
|
|
3897
4321
|
MaxTurnsExceededError2 as MaxTurnsExceededError,
|
|
3898
4322
|
MockAgentResponder,
|
|
3899
4323
|
MultiProviderModelProvider,
|
|
@@ -3941,6 +4365,7 @@ export {
|
|
|
3941
4365
|
buildAgentCapabilities,
|
|
3942
4366
|
buildCompactionPromptInput,
|
|
3943
4367
|
buildCompactionReplacementHistory,
|
|
4368
|
+
buildDeterministicFallbackCompactionHistory,
|
|
3944
4369
|
buildDisplayStackScript,
|
|
3945
4370
|
buildManifest,
|
|
3946
4371
|
buildModelInstance,
|
|
@@ -3952,6 +4377,7 @@ export {
|
|
|
3952
4377
|
buildSummaryItem,
|
|
3953
4378
|
buildTerminalServerScript,
|
|
3954
4379
|
callModelInputFilterForSettings,
|
|
4380
|
+
clampCompactionThresholdRatio,
|
|
3955
4381
|
clientCompactionThresholdTokens,
|
|
3956
4382
|
collectSandboxEnvironment,
|
|
3957
4383
|
composeAgentInstructions,
|
|
@@ -3993,6 +4419,7 @@ export {
|
|
|
3993
4419
|
makeActiveBackendResolver,
|
|
3994
4420
|
materializeSandboxFileDownloads,
|
|
3995
4421
|
maxTurnsExceededRunState,
|
|
4422
|
+
mcpToolErrorOutput,
|
|
3996
4423
|
mintStreamToken,
|
|
3997
4424
|
modalSandboxAttributionEnvironment,
|
|
3998
4425
|
modalSandboxAttributionTags,
|
|
@@ -4025,6 +4452,7 @@ export {
|
|
|
4025
4452
|
runAzureCliLoginHook,
|
|
4026
4453
|
runBeforeAgentStartHooks,
|
|
4027
4454
|
runRepositoryCloneHook,
|
|
4455
|
+
runToolspaceTokenSeedHook,
|
|
4028
4456
|
sandboxCommandExitCode,
|
|
4029
4457
|
sandboxCommandOutput,
|
|
4030
4458
|
sandboxCommandStillRunning,
|
|
@@ -4053,6 +4481,7 @@ export {
|
|
|
4053
4481
|
terminateModalSandboxById,
|
|
4054
4482
|
timeoutAgentError,
|
|
4055
4483
|
timeoutControlResponse,
|
|
4484
|
+
toolspaceTokenSeedCommand,
|
|
4056
4485
|
verifyStreamToken,
|
|
4057
4486
|
withManifestRefreshOnResume,
|
|
4058
4487
|
withSandboxFileDownloads,
|