@google/gemini-cli-a2a-server 0.64.0-preview.0 → 0.64.0-preview.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/a2a-server.mjs +424 -93
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/a2a-server.mjs
CHANGED
|
@@ -221367,8 +221367,8 @@ var GIT_COMMIT_INFO, CLI_VERSION;
|
|
|
221367
221367
|
var init_git_commit = __esm({
|
|
221368
221368
|
"packages/core/dist/src/generated/git-commit.js"() {
|
|
221369
221369
|
"use strict";
|
|
221370
|
-
GIT_COMMIT_INFO = "
|
|
221371
|
-
CLI_VERSION = "0.64.0-preview.
|
|
221370
|
+
GIT_COMMIT_INFO = "581fdbbfa";
|
|
221371
|
+
CLI_VERSION = "0.64.0-preview.1";
|
|
221372
221372
|
}
|
|
221373
221373
|
});
|
|
221374
221374
|
|
|
@@ -337592,7 +337592,7 @@ function getVersion() {
|
|
|
337592
337592
|
}
|
|
337593
337593
|
versionPromise = (async () => {
|
|
337594
337594
|
const pkgJson = await getPackageJson(__dirname4);
|
|
337595
|
-
return "0.64.0-preview.
|
|
337595
|
+
return "0.64.0-preview.1";
|
|
337596
337596
|
})();
|
|
337597
337597
|
return versionPromise;
|
|
337598
337598
|
}
|
|
@@ -339930,6 +339930,13 @@ var init_planUtils = __esm({
|
|
|
339930
339930
|
});
|
|
339931
339931
|
|
|
339932
339932
|
// packages/core/dist/src/utils/untrustedContextTracker.js
|
|
339933
|
+
function isHighRiskPatternToken(token2) {
|
|
339934
|
+
return token2.startsWith("http://") || token2.startsWith("https://") || token2.startsWith("/") || token2.startsWith("\\") || token2.startsWith("./") || token2.startsWith("../") || /^[a-zA-Z]:[\\/]/.test(token2) || /\.(sh|bash|zsh|ps1|bat|cmd|exe)$/i.test(token2);
|
|
339935
|
+
}
|
|
339936
|
+
function hasUntrustedSubstring(untrustedContext, value) {
|
|
339937
|
+
const normalized = value.toLowerCase().replace(/\\/g, "/");
|
|
339938
|
+
return untrustedContext.untrustedTexts.some((text) => text.toLowerCase().includes(normalized));
|
|
339939
|
+
}
|
|
339933
339940
|
function extractUntrustedContext(history) {
|
|
339934
339941
|
const untrustedTexts = [];
|
|
339935
339942
|
const untrustedTokens = /* @__PURE__ */ new Set();
|
|
@@ -339960,35 +339967,19 @@ function extractUntrustedContext(history) {
|
|
|
339960
339967
|
if (untrustedContent) {
|
|
339961
339968
|
const normalizedContent = untrustedContent.replace(/\\/g, "/");
|
|
339962
339969
|
untrustedTexts.push(normalizedContent);
|
|
339963
|
-
const
|
|
339970
|
+
const contentWithoutShellMetadata = normalizedContent.replace(/^\s*Output:\s*(\(empty\))?\s*/i, "").replace(/\n(?:Exit Code|Signal|Background PIDs|Process Group PGID):.*$/gim, "");
|
|
339971
|
+
const tokens = contentWithoutShellMetadata.split(/[\s,`"';()|&[\]{}<>]+/).map((t3) => t3.trim()).filter((t3) => t3.length > 1).filter((t3) => !BARE_DASHES_REGEX.test(t3)).filter((t3) => !FILE_MODE_STRING_REGEX.test(t3)).filter((t3) => !BENIGN_SUBCOMMAND_TOKENS.has(t3.toLowerCase())).filter((t3) => !SAFE_SHORT_FLAGS.has(t3)).filter((t3) => !SAFE_LONG_FLAGS.has(t3.toLowerCase()));
|
|
339964
339972
|
for (const token2 of tokens) {
|
|
339965
|
-
const
|
|
339966
|
-
|
|
339967
|
-
|
|
339968
|
-
|
|
339969
|
-
|
|
339970
|
-
untrustedTokens.add(lowerToken.substring(1));
|
|
339971
|
-
}
|
|
339972
|
-
if (lowerToken.includes("=")) {
|
|
339973
|
-
const eqParts = lowerToken.split("=");
|
|
339973
|
+
const isShortFlag = token2.startsWith("-") && !token2.startsWith("--");
|
|
339974
|
+
const tokenToStore = isShortFlag ? token2 : token2.toLowerCase();
|
|
339975
|
+
untrustedTokens.add(tokenToStore);
|
|
339976
|
+
if (token2.includes("=")) {
|
|
339977
|
+
const eqParts = token2.split("=");
|
|
339974
339978
|
for (const eqPart of eqParts) {
|
|
339975
339979
|
const trimmedPart = eqPart.trim();
|
|
339976
|
-
if (trimmedPart.length > 1) {
|
|
339977
|
-
|
|
339978
|
-
|
|
339979
|
-
untrustedTokens.add(trimmedPart.substring(2));
|
|
339980
|
-
} else if (trimmedPart.startsWith("-")) {
|
|
339981
|
-
untrustedTokens.add(trimmedPart.substring(1));
|
|
339982
|
-
}
|
|
339983
|
-
}
|
|
339984
|
-
}
|
|
339985
|
-
}
|
|
339986
|
-
if (lowerToken.includes("/")) {
|
|
339987
|
-
const pathParts = lowerToken.split("/");
|
|
339988
|
-
for (const part2 of pathParts) {
|
|
339989
|
-
const trimmedPart = part2.trim();
|
|
339990
|
-
if (trimmedPart.length > 1) {
|
|
339991
|
-
untrustedTokens.add(trimmedPart);
|
|
339980
|
+
if (trimmedPart.length > 1 && !BARE_DASHES_REGEX.test(trimmedPart) && !SAFE_SHORT_FLAGS.has(trimmedPart) && !SAFE_LONG_FLAGS.has(trimmedPart.toLowerCase())) {
|
|
339981
|
+
const isPartShortFlag = trimmedPart.startsWith("-") && !trimmedPart.startsWith("--");
|
|
339982
|
+
untrustedTokens.add(isPartShortFlag ? trimmedPart : trimmedPart.toLowerCase());
|
|
339992
339983
|
}
|
|
339993
339984
|
}
|
|
339994
339985
|
}
|
|
@@ -340007,7 +339998,7 @@ function findUntrustedFlags(command, untrustedContext) {
|
|
|
340007
339998
|
let parsed;
|
|
340008
339999
|
try {
|
|
340009
340000
|
const normalizedCommand = process.platform === "win32" ? command.replace(/\\(?!")/g, "/") : command;
|
|
340010
|
-
parsed = (0, import_shell_quote5.parse)(normalizedCommand);
|
|
340001
|
+
parsed = (0, import_shell_quote5.parse)(normalizedCommand, (key) => `$${key}`);
|
|
340011
340002
|
} catch {
|
|
340012
340003
|
parsed = command.trim().split(/\s+/);
|
|
340013
340004
|
}
|
|
@@ -340030,45 +340021,57 @@ function findUntrustedFlags(command, untrustedContext) {
|
|
|
340030
340021
|
const token2 = rawTokens[i3];
|
|
340031
340022
|
const lowerToken = token2.toLowerCase();
|
|
340032
340023
|
if (token2.startsWith("-")) {
|
|
340024
|
+
if (/^--?$/.test(token2)) {
|
|
340025
|
+
continue;
|
|
340026
|
+
}
|
|
340027
|
+
let rawFlagName = token2;
|
|
340033
340028
|
let flagToCheck = lowerToken;
|
|
340029
|
+
let rawValToCheck;
|
|
340034
340030
|
let valToCheck;
|
|
340035
340031
|
if (token2.includes("=")) {
|
|
340036
|
-
const eqIdx =
|
|
340032
|
+
const eqIdx = token2.indexOf("=");
|
|
340033
|
+
rawFlagName = token2.substring(0, eqIdx);
|
|
340037
340034
|
flagToCheck = lowerToken.substring(0, eqIdx);
|
|
340035
|
+
rawValToCheck = token2.substring(eqIdx + 1);
|
|
340038
340036
|
valToCheck = lowerToken.substring(eqIdx + 1);
|
|
340039
340037
|
}
|
|
340040
|
-
|
|
340038
|
+
const isSafeFlag = SAFE_SHORT_FLAGS.has(rawFlagName) || SAFE_LONG_FLAGS.has(flagToCheck);
|
|
340039
|
+
const isHighRiskFlag = HIGH_RISK_VALUE_FLAGS.has(rawFlagName) || rawFlagName.startsWith("--") && HIGH_RISK_VALUE_FLAGS.has(flagToCheck);
|
|
340040
|
+
const isShortFlag = rawFlagName.startsWith("-") && !rawFlagName.startsWith("--");
|
|
340041
|
+
const tokenToLookup = isShortFlag ? rawFlagName : lowerToken;
|
|
340042
|
+
const flagToLookup = isShortFlag ? rawFlagName : flagToCheck;
|
|
340043
|
+
if (!isSafeFlag && (untrustedContext.untrustedTokens.has(tokenToLookup) || untrustedContext.untrustedTokens.has(flagToLookup))) {
|
|
340041
340044
|
detected.add(token2);
|
|
340042
|
-
|
|
340045
|
+
if (token2.includes("=") || !isHighRiskFlag) {
|
|
340046
|
+
continue;
|
|
340047
|
+
}
|
|
340043
340048
|
}
|
|
340044
|
-
if (valToCheck &&
|
|
340045
|
-
|
|
340046
|
-
|
|
340049
|
+
if (valToCheck && rawValToCheck) {
|
|
340050
|
+
const isValUntrusted = untrustedContext.untrustedTokens.has(valToCheck) && (isHighRiskFlag || !isSafeFlag && isHighRiskPatternToken(rawValToCheck));
|
|
340051
|
+
const isHighRiskValSubstring = (!isSafeFlag || isHighRiskFlag) && isHighRiskPatternToken(rawValToCheck) && hasUntrustedSubstring(untrustedContext, valToCheck);
|
|
340052
|
+
if (isValUntrusted || isHighRiskValSubstring) {
|
|
340053
|
+
detected.add(token2);
|
|
340054
|
+
continue;
|
|
340055
|
+
}
|
|
340047
340056
|
}
|
|
340048
|
-
|
|
340049
|
-
|
|
340050
|
-
|
|
340051
|
-
|
|
340057
|
+
if (!token2.includes("=") && isHighRiskFlag) {
|
|
340058
|
+
const nextToken = rawTokens[i3 + 1];
|
|
340059
|
+
if (nextToken && !nextToken.startsWith("-") && !BARE_SHELL_VARIABLE_REGEX.test(nextToken) && !BENIGN_SUBCOMMAND_TOKENS.has(nextToken.toLowerCase()) && (untrustedContext.untrustedTokens.has(nextToken.toLowerCase()) || isHighRiskPatternToken(nextToken) && hasUntrustedSubstring(untrustedContext, nextToken))) {
|
|
340060
|
+
detected.add(token2);
|
|
340061
|
+
detected.add(nextToken);
|
|
340062
|
+
}
|
|
340052
340063
|
}
|
|
340053
340064
|
} else {
|
|
340054
|
-
if (token2.length <= 1) {
|
|
340065
|
+
if (token2.length <= 1 || BARE_SHELL_VARIABLE_REGEX.test(token2)) {
|
|
340055
340066
|
continue;
|
|
340056
340067
|
}
|
|
340057
|
-
|
|
340058
|
-
const isHighRiskPattern = token2.startsWith("http://") || token2.startsWith("https://") || token2.startsWith("/") || token2.startsWith("\\") || /^[a-zA-Z]:[\\/]/.test(token2);
|
|
340059
|
-
if (isSensitiveWord) {
|
|
340068
|
+
if (isHighRiskPatternToken(token2)) {
|
|
340060
340069
|
if (untrustedContext.untrustedTokens.has(lowerToken)) {
|
|
340061
340070
|
detected.add(token2);
|
|
340062
340071
|
continue;
|
|
340063
340072
|
}
|
|
340064
|
-
if (
|
|
340065
|
-
|
|
340066
|
-
for (const text of untrustedContext.untrustedTexts) {
|
|
340067
|
-
if (text.toLowerCase().includes(normalizedLowerToken)) {
|
|
340068
|
-
detected.add(token2);
|
|
340069
|
-
break;
|
|
340070
|
-
}
|
|
340071
|
-
}
|
|
340073
|
+
if (hasUntrustedSubstring(untrustedContext, lowerToken)) {
|
|
340074
|
+
detected.add(token2);
|
|
340072
340075
|
}
|
|
340073
340076
|
}
|
|
340074
340077
|
}
|
|
@@ -340126,7 +340129,7 @@ function getModifiedBuildFiles(sessionKey) {
|
|
|
340126
340129
|
}
|
|
340127
340130
|
return [];
|
|
340128
340131
|
}
|
|
340129
|
-
var import_shell_quote5, UNTRUSTED_CONTEXT_REGEX, BUILD_TEST_COMMAND_ROOTS, BENIGN_SUBCOMMAND_TOKENS, MODIFIED_BUILD_FILES_SYMBOL;
|
|
340132
|
+
var import_shell_quote5, UNTRUSTED_CONTEXT_REGEX, BUILD_TEST_COMMAND_ROOTS, BENIGN_SUBCOMMAND_TOKENS, SAFE_SHORT_FLAGS, SAFE_LONG_FLAGS, HIGH_RISK_VALUE_FLAGS, FILE_MODE_STRING_REGEX, BARE_DASHES_REGEX, BARE_SHELL_VARIABLE_REGEX, MODIFIED_BUILD_FILES_SYMBOL;
|
|
340130
340133
|
var init_untrustedContextTracker = __esm({
|
|
340131
340134
|
"packages/core/dist/src/utils/untrustedContextTracker.js"() {
|
|
340132
340135
|
"use strict";
|
|
@@ -340177,6 +340180,135 @@ var init_untrustedContextTracker = __esm({
|
|
|
340177
340180
|
"restart",
|
|
340178
340181
|
"status"
|
|
340179
340182
|
]);
|
|
340183
|
+
SAFE_SHORT_FLAGS = /* @__PURE__ */ new Set([
|
|
340184
|
+
"-a",
|
|
340185
|
+
"-A",
|
|
340186
|
+
"-b",
|
|
340187
|
+
"-B",
|
|
340188
|
+
"-C",
|
|
340189
|
+
"-d",
|
|
340190
|
+
"-D",
|
|
340191
|
+
"-E",
|
|
340192
|
+
"-F",
|
|
340193
|
+
"-g",
|
|
340194
|
+
"-G",
|
|
340195
|
+
"-h",
|
|
340196
|
+
"-H",
|
|
340197
|
+
"-i",
|
|
340198
|
+
"-I",
|
|
340199
|
+
"-l",
|
|
340200
|
+
"-L",
|
|
340201
|
+
"-m",
|
|
340202
|
+
"-n",
|
|
340203
|
+
"-N",
|
|
340204
|
+
"-p",
|
|
340205
|
+
"-P",
|
|
340206
|
+
"-q",
|
|
340207
|
+
"-r",
|
|
340208
|
+
"-R",
|
|
340209
|
+
"-s",
|
|
340210
|
+
"-S",
|
|
340211
|
+
"-t",
|
|
340212
|
+
"-T",
|
|
340213
|
+
"-u",
|
|
340214
|
+
"-U",
|
|
340215
|
+
"-v",
|
|
340216
|
+
"-V",
|
|
340217
|
+
"-w",
|
|
340218
|
+
"-W",
|
|
340219
|
+
"-x",
|
|
340220
|
+
"-z",
|
|
340221
|
+
"-1",
|
|
340222
|
+
// Common combined POSIX inspection flags (ls, grep, ps, git)
|
|
340223
|
+
"-la",
|
|
340224
|
+
"-al",
|
|
340225
|
+
"-ld",
|
|
340226
|
+
"-dl",
|
|
340227
|
+
"-lh",
|
|
340228
|
+
"-hl",
|
|
340229
|
+
"-lah",
|
|
340230
|
+
"-alh",
|
|
340231
|
+
"-lrt",
|
|
340232
|
+
"-ltr",
|
|
340233
|
+
"-rn",
|
|
340234
|
+
"-nr",
|
|
340235
|
+
"-ri",
|
|
340236
|
+
"-ir",
|
|
340237
|
+
"-rni",
|
|
340238
|
+
"-rin",
|
|
340239
|
+
"-ni",
|
|
340240
|
+
"-in",
|
|
340241
|
+
"-ef",
|
|
340242
|
+
"-aux"
|
|
340243
|
+
]);
|
|
340244
|
+
SAFE_LONG_FLAGS = /* @__PURE__ */ new Set([
|
|
340245
|
+
"--all",
|
|
340246
|
+
"--oneline",
|
|
340247
|
+
"--stat",
|
|
340248
|
+
"--numstat",
|
|
340249
|
+
"--shortstat",
|
|
340250
|
+
"--name-only",
|
|
340251
|
+
"--name-status",
|
|
340252
|
+
"--graph",
|
|
340253
|
+
"--decorate",
|
|
340254
|
+
"--no-pager",
|
|
340255
|
+
"--color",
|
|
340256
|
+
"--no-color",
|
|
340257
|
+
"--grep",
|
|
340258
|
+
"--author",
|
|
340259
|
+
"--since",
|
|
340260
|
+
"--until",
|
|
340261
|
+
"--before",
|
|
340262
|
+
"--after",
|
|
340263
|
+
"--pretty",
|
|
340264
|
+
"--format",
|
|
340265
|
+
"--abbrev-commit",
|
|
340266
|
+
"--max-count",
|
|
340267
|
+
"--cached",
|
|
340268
|
+
"--staged",
|
|
340269
|
+
"--short",
|
|
340270
|
+
"--branch",
|
|
340271
|
+
"--porcelain",
|
|
340272
|
+
"--help",
|
|
340273
|
+
"--version",
|
|
340274
|
+
"--quiet",
|
|
340275
|
+
"--verbose",
|
|
340276
|
+
"--dry-run",
|
|
340277
|
+
"--ignore-case",
|
|
340278
|
+
"--line-number",
|
|
340279
|
+
"--recursive",
|
|
340280
|
+
"--extended-regexp",
|
|
340281
|
+
"--fixed-strings",
|
|
340282
|
+
"--files-with-matches",
|
|
340283
|
+
"--count",
|
|
340284
|
+
"--context",
|
|
340285
|
+
"--before-context",
|
|
340286
|
+
"--after-context"
|
|
340287
|
+
]);
|
|
340288
|
+
HIGH_RISK_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
340289
|
+
"-c",
|
|
340290
|
+
"-e",
|
|
340291
|
+
"--eval",
|
|
340292
|
+
"--exec",
|
|
340293
|
+
"-exec",
|
|
340294
|
+
"-execdir",
|
|
340295
|
+
"--run_under",
|
|
340296
|
+
"--test_strategy",
|
|
340297
|
+
"--test_arg",
|
|
340298
|
+
"--test_env",
|
|
340299
|
+
"--action_env",
|
|
340300
|
+
"--jvmopt",
|
|
340301
|
+
"--host_jvm_args",
|
|
340302
|
+
"--wrapper_script_flag",
|
|
340303
|
+
"--upload-pack",
|
|
340304
|
+
"--receive-pack",
|
|
340305
|
+
"--require",
|
|
340306
|
+
"--import",
|
|
340307
|
+
"--loader"
|
|
340308
|
+
]);
|
|
340309
|
+
FILE_MODE_STRING_REGEX = /^[dcbpsl-][rwxstST-]{9}[+@.]?$/i;
|
|
340310
|
+
BARE_DASHES_REGEX = /^--+$/;
|
|
340311
|
+
BARE_SHELL_VARIABLE_REGEX = /^\$(?:[a-zA-Z_][a-zA-Z0-9_]*|\{[a-zA-Z_][a-zA-Z0-9_]*\})$/;
|
|
340180
340312
|
MODIFIED_BUILD_FILES_SYMBOL = Symbol("sessionModifiedBuildFiles");
|
|
340181
340313
|
}
|
|
340182
340314
|
});
|
|
@@ -368074,6 +368206,9 @@ function scrubPart(part) {
|
|
|
368074
368206
|
if (part.functionResponse.id) {
|
|
368075
368207
|
scrubbedResp["id"] = part.functionResponse.id;
|
|
368076
368208
|
}
|
|
368209
|
+
if ("parts" in part.functionResponse && Array.isArray(part.functionResponse.parts)) {
|
|
368210
|
+
scrubbedResp["parts"] = part.functionResponse.parts.map(scrubPart);
|
|
368211
|
+
}
|
|
368077
368212
|
scrubbed["functionResponse"] = scrubbedResp;
|
|
368078
368213
|
}
|
|
368079
368214
|
if ("fileData" in part) {
|
|
@@ -368221,8 +368356,41 @@ function isSchemaDepthError(errorMessage) {
|
|
|
368221
368356
|
function isInvalidArgumentError(errorMessage) {
|
|
368222
368357
|
return errorMessage.includes("Request contains an invalid argument");
|
|
368223
368358
|
}
|
|
368359
|
+
function isEmptyTextPart(part) {
|
|
368360
|
+
if (part.text !== "") {
|
|
368361
|
+
return false;
|
|
368362
|
+
}
|
|
368363
|
+
return !Object.keys(part).some((key) => key !== "text" && key !== "thought" && key !== "callIndex");
|
|
368364
|
+
}
|
|
368365
|
+
function hasNonEmptyParts(content) {
|
|
368366
|
+
return (content.parts ?? []).some((part) => !isEmptyTextPart(part));
|
|
368367
|
+
}
|
|
368368
|
+
function buildInterruptedToolResponseParts(parts2) {
|
|
368369
|
+
return parts2.filter((part) => !!part?.functionCall).map((part) => ({
|
|
368370
|
+
functionResponse: {
|
|
368371
|
+
name: part.functionCall.name?.trim() || "generic_tool",
|
|
368372
|
+
id: part.functionCall.id,
|
|
368373
|
+
response: { error: INTERRUPTED_TOOL_RESPONSE_ERROR }
|
|
368374
|
+
}
|
|
368375
|
+
}));
|
|
368376
|
+
}
|
|
368377
|
+
function ensureTerminalUserTurn(contents) {
|
|
368378
|
+
const last2 = contents.at(-1);
|
|
368379
|
+
if (last2?.role === "user" && hasNonEmptyParts(last2)) {
|
|
368380
|
+
return contents;
|
|
368381
|
+
}
|
|
368382
|
+
if (last2?.role === "user") {
|
|
368383
|
+
return [
|
|
368384
|
+
...contents.slice(0, -1),
|
|
368385
|
+
{ ...last2, parts: [{ text: CONTINUE_PROMPT_TEXT }] }
|
|
368386
|
+
];
|
|
368387
|
+
}
|
|
368388
|
+
const missingResponses = buildInterruptedToolResponseParts(last2?.parts ?? []);
|
|
368389
|
+
const parts2 = missingResponses.length > 0 ? missingResponses : [{ text: CONTINUE_PROMPT_TEXT }];
|
|
368390
|
+
return [...contents, { role: "user", parts: parts2 }];
|
|
368391
|
+
}
|
|
368224
368392
|
function stripToolCallIdPrefixes(contents) {
|
|
368225
|
-
|
|
368393
|
+
const stripped = contents.map((content) => {
|
|
368226
368394
|
const parts2 = (content.parts || []).map((part) => {
|
|
368227
368395
|
const newPart = { ...part };
|
|
368228
368396
|
if (newPart.functionCall) {
|
|
@@ -368230,8 +368398,7 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
368230
368398
|
const name3 = fc.name?.trim() || "generic_tool";
|
|
368231
368399
|
if (fc.id && fc.id.startsWith(`${name3}__`)) {
|
|
368232
368400
|
newPart.functionCall = {
|
|
368233
|
-
|
|
368234
|
-
args: fc.args,
|
|
368401
|
+
...fc,
|
|
368235
368402
|
id: fc.id.substring(name3.length + 2)
|
|
368236
368403
|
};
|
|
368237
368404
|
}
|
|
@@ -368241,8 +368408,9 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
368241
368408
|
const name3 = fr2.name?.trim() || "generic_tool";
|
|
368242
368409
|
if (fr2.id && fr2.id.startsWith(`${name3}__`)) {
|
|
368243
368410
|
newPart.functionResponse = {
|
|
368244
|
-
|
|
368245
|
-
|
|
368411
|
+
// History parts are plain JSON objects, not class instances.
|
|
368412
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-spread
|
|
368413
|
+
...fr2,
|
|
368246
368414
|
id: fr2.id.substring(name3.length + 2)
|
|
368247
368415
|
};
|
|
368248
368416
|
}
|
|
@@ -368252,18 +368420,30 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
368252
368420
|
delete newPart.text;
|
|
368253
368421
|
}
|
|
368254
368422
|
return newPart;
|
|
368255
|
-
}).filter((part) =>
|
|
368256
|
-
const hasOtherKeys = Object.keys(part).some((key) => key !== "text" && key !== "thought" && key !== "callIndex");
|
|
368257
|
-
if (part.text !== void 0 && part.text === "" && !hasOtherKeys) {
|
|
368258
|
-
return false;
|
|
368259
|
-
}
|
|
368260
|
-
return true;
|
|
368261
|
-
});
|
|
368423
|
+
}).filter((part) => !isEmptyTextPart(part));
|
|
368262
368424
|
return {
|
|
368263
368425
|
...content,
|
|
368264
368426
|
parts: parts2
|
|
368265
368427
|
};
|
|
368266
|
-
});
|
|
368428
|
+
}).filter((content) => content.parts.length > 0);
|
|
368429
|
+
return coalesceConsecutiveContents(stripped);
|
|
368430
|
+
}
|
|
368431
|
+
function coalesceConsecutiveContents(contents) {
|
|
368432
|
+
const result2 = [];
|
|
368433
|
+
for (const item of contents) {
|
|
368434
|
+
const lastIdx = result2.length - 1;
|
|
368435
|
+
const last2 = result2[lastIdx];
|
|
368436
|
+
if (last2 && last2.role && last2.role === item.role) {
|
|
368437
|
+
const hasParts = last2.parts || item.parts;
|
|
368438
|
+
result2[lastIdx] = {
|
|
368439
|
+
...last2,
|
|
368440
|
+
parts: hasParts ? [...last2.parts || [], ...item.parts || []] : void 0
|
|
368441
|
+
};
|
|
368442
|
+
} else {
|
|
368443
|
+
result2.push({ ...item });
|
|
368444
|
+
}
|
|
368445
|
+
}
|
|
368446
|
+
return result2;
|
|
368267
368447
|
}
|
|
368268
368448
|
function coalesceConsecutiveRoles(history) {
|
|
368269
368449
|
const result2 = [];
|
|
@@ -368318,7 +368498,7 @@ function stripThoughts2(history) {
|
|
|
368318
368498
|
};
|
|
368319
368499
|
}).filter((turn) => !turn.content.parts || turn.content.parts.length > 0);
|
|
368320
368500
|
}
|
|
368321
|
-
var StreamEventType, MID_STREAM_RETRY_OPTIONS, SYNTHETIC_THOUGHT_SIGNATURE2, INTERRUPTED_RESPONSE_PLACEHOLDER, THINKING_ONLY_NUDGE_MESSAGE, NO_RESPONSE_TEXT_NUDGE_MESSAGE, InvalidStreamError, AgentExecutionStoppedError, AgentExecutionBlockedError, GeminiChat;
|
|
368501
|
+
var StreamEventType, MID_STREAM_RETRY_OPTIONS, SYNTHETIC_THOUGHT_SIGNATURE2, INTERRUPTED_RESPONSE_PLACEHOLDER, INTERRUPTED_TOOL_RESPONSE_ERROR, CONTINUE_PROMPT_TEXT, THINKING_ONLY_NUDGE_MESSAGE, NO_RESPONSE_TEXT_NUDGE_MESSAGE, InvalidStreamError, AgentExecutionStoppedError, AgentExecutionBlockedError, GeminiChat;
|
|
368322
368502
|
var init_geminiChat = __esm({
|
|
368323
368503
|
"packages/core/dist/src/core/geminiChat.js"() {
|
|
368324
368504
|
"use strict";
|
|
@@ -368341,6 +368521,7 @@ var init_geminiChat = __esm({
|
|
|
368341
368521
|
init_tokenCalculation();
|
|
368342
368522
|
init_policyHelpers();
|
|
368343
368523
|
init_events();
|
|
368524
|
+
init_debugLogger();
|
|
368344
368525
|
(function(StreamEventType2) {
|
|
368345
368526
|
StreamEventType2["CHUNK"] = "chunk";
|
|
368346
368527
|
StreamEventType2["RETRY"] = "retry";
|
|
@@ -368355,6 +368536,8 @@ var init_geminiChat = __esm({
|
|
|
368355
368536
|
};
|
|
368356
368537
|
SYNTHETIC_THOUGHT_SIGNATURE2 = "skip_thought_signature_validator";
|
|
368357
368538
|
INTERRUPTED_RESPONSE_PLACEHOLDER = "[The previous response was interrupted before it completed.]";
|
|
368539
|
+
INTERRUPTED_TOOL_RESPONSE_ERROR = "Response was lost or interrupted.";
|
|
368540
|
+
CONTINUE_PROMPT_TEXT = "Please continue.";
|
|
368358
368541
|
THINKING_ONLY_NUDGE_MESSAGE = "[System: You previously generated thoughts but failed to provide a final user-facing response. Please ensure you provide your final answer or call a tool now.]";
|
|
368359
368542
|
NO_RESPONSE_TEXT_NUDGE_MESSAGE = "[System: You previously returned an empty response with no text or thoughts. Please ensure you provide your final answer or call a tool now.]";
|
|
368360
368543
|
InvalidStreamError = class extends Error {
|
|
@@ -368486,6 +368669,7 @@ var init_geminiChat = __esm({
|
|
|
368486
368669
|
let userContent = createUserContent(message);
|
|
368487
368670
|
const isOriginalFunctionResponse = isFunctionResponse(userContent);
|
|
368488
368671
|
if (!isOriginalFunctionResponse) {
|
|
368672
|
+
this.closeUnansweredToolCallsTurn();
|
|
368489
368673
|
this.closeUnansweredToolResponseTurn();
|
|
368490
368674
|
}
|
|
368491
368675
|
const { model } = this.context.config.modelConfigService.getResolvedConfig(modelConfigKey);
|
|
@@ -368512,7 +368696,7 @@ var init_geminiChat = __esm({
|
|
|
368512
368696
|
} else {
|
|
368513
368697
|
const history = this.agentHistory.get();
|
|
368514
368698
|
const lastTurn = history[history.length - 1];
|
|
368515
|
-
if (!lastTurn || partListUnionToString(lastTurn.content.parts || []) !== userMessageContent) {
|
|
368699
|
+
if (!lastTurn || lastTurn.content.role !== "user" || partListUnionToString(lastTurn.content.parts || []) !== userMessageContent) {
|
|
368516
368700
|
const id = this.chatRecordingService.recordMessage({
|
|
368517
368701
|
model,
|
|
368518
368702
|
type: "user",
|
|
@@ -368560,11 +368744,12 @@ var init_geminiChat = __esm({
|
|
|
368560
368744
|
} else {
|
|
368561
368745
|
const history = this.agentHistory.get();
|
|
368562
368746
|
const lastTurn = history[history.length - 1];
|
|
368563
|
-
if (!lastTurn || partListUnionToString(lastTurn.content.parts || []) !== partListUnionToString(userContent.parts || [])) {
|
|
368747
|
+
if (!lastTurn || lastTurn.content.role !== "user" || partListUnionToString(lastTurn.content.parts || []) !== partListUnionToString(userContent.parts || [])) {
|
|
368564
368748
|
this.agentHistory.push({ id, content: userContent });
|
|
368565
368749
|
}
|
|
368566
368750
|
}
|
|
368567
368751
|
}
|
|
368752
|
+
this.replaceEmptyTrailingUserTurn();
|
|
368568
368753
|
const requestHistory = this.getHistoryTurns(true);
|
|
368569
368754
|
const streamWithRetries = async function* () {
|
|
368570
368755
|
let isSuccess = false;
|
|
@@ -368676,23 +368861,77 @@ var init_geminiChat = __esm({
|
|
|
368676
368861
|
return streamWithRetries.call(this);
|
|
368677
368862
|
}
|
|
368678
368863
|
/**
|
|
368679
|
-
* Appends a
|
|
368680
|
-
*
|
|
368864
|
+
* Appends a dedicated synthetic user turn with matching functionResponse
|
|
368865
|
+
* parts when history ends with an unclosed model functionCall. The
|
|
368866
|
+
* subsequent user prompt is then recorded as a clean turn of its own (after
|
|
368867
|
+
* `closeUnansweredToolResponseTurn` adds the closing model turn).
|
|
368681
368868
|
*/
|
|
368682
|
-
|
|
368869
|
+
closeUnansweredToolCallsTurn() {
|
|
368683
368870
|
const turns = this.agentHistory.get();
|
|
368684
368871
|
const last2 = turns[turns.length - 1];
|
|
368685
|
-
if (last2?.content.role !== "
|
|
368872
|
+
if (last2?.content.role !== "model") {
|
|
368873
|
+
return;
|
|
368874
|
+
}
|
|
368875
|
+
const missingResponses = buildInterruptedToolResponseParts(last2.content.parts ?? []);
|
|
368876
|
+
if (missingResponses.length === 0) {
|
|
368686
368877
|
return;
|
|
368687
368878
|
}
|
|
368879
|
+
const id = this.chatRecordingService.recordSyntheticMessage("user", missingResponses);
|
|
368688
368880
|
this.agentHistory.push({
|
|
368689
|
-
id
|
|
368690
|
-
content: {
|
|
368691
|
-
role: "model",
|
|
368692
|
-
parts: [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }]
|
|
368693
|
-
}
|
|
368881
|
+
id,
|
|
368882
|
+
content: { role: "user", parts: missingResponses }
|
|
368694
368883
|
});
|
|
368695
368884
|
}
|
|
368885
|
+
/**
|
|
368886
|
+
* Replaces the parts of a trailing user turn that carries no content (e.g.
|
|
368887
|
+
* only empty text parts) with a continuation prompt, keeping the in-memory
|
|
368888
|
+
* history and the session log in sync. Runs once per send so that the
|
|
368889
|
+
* persisted history never keeps an empty user turn between model turns.
|
|
368890
|
+
*/
|
|
368891
|
+
replaceEmptyTrailingUserTurn() {
|
|
368892
|
+
const turns = this.agentHistory.get();
|
|
368893
|
+
const last2 = turns[turns.length - 1];
|
|
368894
|
+
if (last2?.content.role !== "user" || hasNonEmptyParts(last2.content)) {
|
|
368895
|
+
return;
|
|
368896
|
+
}
|
|
368897
|
+
this.agentHistory.set([
|
|
368898
|
+
...turns.slice(0, -1),
|
|
368899
|
+
{
|
|
368900
|
+
id: last2.id,
|
|
368901
|
+
content: { ...last2.content, parts: [{ text: CONTINUE_PROMPT_TEXT }] }
|
|
368902
|
+
}
|
|
368903
|
+
]);
|
|
368904
|
+
this.chatRecordingService.updateMessagesFromHistory(this.agentHistory.get());
|
|
368905
|
+
}
|
|
368906
|
+
/**
|
|
368907
|
+
* Appends a closing model turn when history ends with an unanswered tool
|
|
368908
|
+
* response, so the next user message stays a turn of its own.
|
|
368909
|
+
*/
|
|
368910
|
+
closeUnansweredToolResponseTurn() {
|
|
368911
|
+
const turns = this.agentHistory.get();
|
|
368912
|
+
let targetTurn = turns[turns.length - 1];
|
|
368913
|
+
let hadEmptyTrailingModelTurn = false;
|
|
368914
|
+
if (targetTurn?.content.role === "model" && (!targetTurn.content.parts || targetTurn.content.parts.length === 0)) {
|
|
368915
|
+
hadEmptyTrailingModelTurn = true;
|
|
368916
|
+
targetTurn = turns[turns.length - 2];
|
|
368917
|
+
}
|
|
368918
|
+
if (targetTurn?.content.role !== "user" || !targetTurn.content.parts?.some((part) => !!part.functionResponse)) {
|
|
368919
|
+
return;
|
|
368920
|
+
}
|
|
368921
|
+
if (hadEmptyTrailingModelTurn) {
|
|
368922
|
+
const lastTurn = turns[turns.length - 1];
|
|
368923
|
+
lastTurn.content.parts = [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }];
|
|
368924
|
+
this.chatRecordingService.updateMessagesFromHistory(turns);
|
|
368925
|
+
} else {
|
|
368926
|
+
this.agentHistory.push({
|
|
368927
|
+
id: randomUUID8(),
|
|
368928
|
+
content: {
|
|
368929
|
+
role: "model",
|
|
368930
|
+
parts: [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }]
|
|
368931
|
+
}
|
|
368932
|
+
});
|
|
368933
|
+
}
|
|
368934
|
+
}
|
|
368696
368935
|
extractBinaryInjections(parts2) {
|
|
368697
368936
|
const binaryParts = [];
|
|
368698
368937
|
if (parts2) {
|
|
@@ -368809,10 +369048,14 @@ var init_geminiChat = __esm({
|
|
|
368809
369048
|
if (this.onModelChanged) {
|
|
368810
369049
|
this.tools = await this.onModelChanged(modelToUse);
|
|
368811
369050
|
}
|
|
369051
|
+
const normalizedContents = ensureTerminalUserTurn(contentsToUse);
|
|
369052
|
+
if (normalizedContents !== contentsToUse) {
|
|
369053
|
+
debugLogger.warn("Final contents do not end with a valid user turn. Normalizing contents to satisfy Gemini API invariant.");
|
|
369054
|
+
}
|
|
368812
369055
|
lastModelToUse = modelToUse;
|
|
368813
369056
|
lastConfig = config2;
|
|
368814
|
-
lastContentsToUse =
|
|
368815
|
-
const finalContents = stripToolCallIdPrefixes(
|
|
369057
|
+
lastContentsToUse = normalizedContents;
|
|
369058
|
+
const finalContents = stripToolCallIdPrefixes(normalizedContents);
|
|
368816
369059
|
return this.context.config.getContentGenerator().generateContentStream({
|
|
368817
369060
|
model: modelToUse,
|
|
368818
369061
|
contents: finalContents,
|
|
@@ -368910,6 +369153,25 @@ var init_geminiChat = __esm({
|
|
|
368910
369153
|
}
|
|
368911
369154
|
ensureStableToolIds(this.agentHistory.get());
|
|
368912
369155
|
}
|
|
369156
|
+
/**
|
|
369157
|
+
* Removes the trailing model turn when it holds function calls that were
|
|
369158
|
+
* never answered (e.g. every call in the batch was declined). Earlier
|
|
369159
|
+
* completed tool rounds and the originating user prompt are kept, and the
|
|
369160
|
+
* durable IDs of the remaining turns are preserved.
|
|
369161
|
+
*
|
|
369162
|
+
* @returns true when a turn was removed.
|
|
369163
|
+
*/
|
|
369164
|
+
discardTrailingUnansweredToolCallTurn() {
|
|
369165
|
+
const turns = this.agentHistory.get();
|
|
369166
|
+
const last2 = turns[turns.length - 1];
|
|
369167
|
+
if (last2?.content.role !== "model" || !last2.content.parts?.some((part) => !!part.functionCall)) {
|
|
369168
|
+
return false;
|
|
369169
|
+
}
|
|
369170
|
+
this.agentHistory.rollback(turns.length - 1);
|
|
369171
|
+
this.lastPromptTokenCount = estimateTokenCountSync(this.agentHistory.flatMap((c2) => c2.content.parts || []));
|
|
369172
|
+
this.chatRecordingService.updateMessagesFromHistory(this.agentHistory.get());
|
|
369173
|
+
return true;
|
|
369174
|
+
}
|
|
368913
369175
|
setHistory(history) {
|
|
368914
369176
|
const wrappedHistory = history.map((item) => {
|
|
368915
369177
|
if ("id" in item && "content" in item) {
|
|
@@ -376673,7 +376935,13 @@ var init_oauth_utils = __esm({
|
|
|
376673
376935
|
issuer: metadata2.issuer,
|
|
376674
376936
|
tokenUrl: metadata2.token_endpoint,
|
|
376675
376937
|
scopes: metadata2.scopes_supported || [],
|
|
376676
|
-
registrationUrl: metadata2.registration_endpoint
|
|
376938
|
+
registrationUrl: metadata2.registration_endpoint,
|
|
376939
|
+
// RFC 9207 Section 3: the flag defaults to false when omitted. Discovered
|
|
376940
|
+
// configurations therefore always carry an explicit boolean, which lets
|
|
376941
|
+
// the callback policy distinguish them from an explicitly configured issuer.
|
|
376942
|
+
// Only a literal boolean `true` enables the flag, so loosely typed values
|
|
376943
|
+
// returned by some servers (e.g. "false" or "0") are not coerced to true.
|
|
376944
|
+
authorizationResponseIssParameterSupported: metadata2.authorization_response_iss_parameter_supported === true
|
|
376677
376945
|
};
|
|
376678
376946
|
}
|
|
376679
376947
|
/**
|
|
@@ -380473,7 +380741,7 @@ function areIssuersEqual(issuerA, issuerB) {
|
|
|
380473
380741
|
}
|
|
380474
380742
|
return normA === normB;
|
|
380475
380743
|
}
|
|
380476
|
-
function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
380744
|
+
function startCallbackServer(expectedState, port, expectedIssuer, requireIssInResponse) {
|
|
380477
380745
|
let portResolve;
|
|
380478
380746
|
let portReject;
|
|
380479
380747
|
const portPromise = new Promise((resolve23, reject) => {
|
|
@@ -380527,8 +380795,9 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380527
380795
|
return;
|
|
380528
380796
|
}
|
|
380529
380797
|
if (expectedIssuer) {
|
|
380530
|
-
|
|
380531
|
-
|
|
380798
|
+
const requireIss = requireIssInResponse ?? true;
|
|
380799
|
+
if (requireIss && !iss) {
|
|
380800
|
+
debugLogger.error('OAuth callback rejected: Missing required "iss" parameter for the expected authorization server (RFC 9207).');
|
|
380532
380801
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
380533
380802
|
res.end(`
|
|
380534
380803
|
<html>
|
|
@@ -380543,7 +380812,7 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380543
380812
|
reject(new Error('Missing "iss" parameter in authorization response per RFC 9207'));
|
|
380544
380813
|
return;
|
|
380545
380814
|
}
|
|
380546
|
-
if (!areIssuersEqual(iss, expectedIssuer)) {
|
|
380815
|
+
if (iss && !areIssuersEqual(iss, expectedIssuer)) {
|
|
380547
380816
|
debugLogger.error("OAuth callback rejected: Issuer mismatch between authorization response and expected authorization server. Possible IdP mix-up attack (RFC 9207).");
|
|
380548
380817
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
380549
380818
|
res.end(`
|
|
@@ -380559,7 +380828,9 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380559
380828
|
reject(new Error("Issuer mismatch in authorization response - possible OAuth mix-up attack"));
|
|
380560
380829
|
return;
|
|
380561
380830
|
}
|
|
380562
|
-
|
|
380831
|
+
if (iss) {
|
|
380832
|
+
debugLogger.debug("\u2713 OAuth callback issuer validated successfully.");
|
|
380833
|
+
}
|
|
380563
380834
|
} else if (iss) {
|
|
380564
380835
|
debugLogger.debug('OAuth callback received "iss" parameter (no expected issuer was configured).');
|
|
380565
380836
|
}
|
|
@@ -387642,6 +387913,21 @@ var init_client3 = __esm({
|
|
|
387642
387913
|
this.updateTelemetryTokenCount();
|
|
387643
387914
|
this.forceFullIdeContext = true;
|
|
387644
387915
|
}
|
|
387916
|
+
/**
|
|
387917
|
+
* Removes the trailing model turn when it only holds unanswered function
|
|
387918
|
+
* calls. See {@link GeminiChat.discardTrailingUnansweredToolCallTurn}.
|
|
387919
|
+
* Returns false without side effects when the chat is not initialized.
|
|
387920
|
+
*/
|
|
387921
|
+
discardTrailingUnansweredToolCallTurn() {
|
|
387922
|
+
if (!this.isInitialized()) {
|
|
387923
|
+
return false;
|
|
387924
|
+
}
|
|
387925
|
+
const removed = this.getChat().discardTrailingUnansweredToolCallTurn();
|
|
387926
|
+
if (removed) {
|
|
387927
|
+
this.updateTelemetryTokenCount();
|
|
387928
|
+
}
|
|
387929
|
+
return removed;
|
|
387930
|
+
}
|
|
387645
387931
|
lastUsedModelId;
|
|
387646
387932
|
async setTools(modelId) {
|
|
387647
387933
|
if (!this.chat) {
|
|
@@ -404549,7 +404835,7 @@ var init_policy_engine = __esm({
|
|
|
404549
404835
|
}
|
|
404550
404836
|
return decision;
|
|
404551
404837
|
}
|
|
404552
|
-
async checkShellCommand(toolName, command, ruleDecision, serverName, dir_path, allowRedirection, rule, toolAnnotations, subagent) {
|
|
404838
|
+
async checkShellCommand(toolName, command, ruleDecision, serverName, dir_path, allowRedirection, rule, toolAnnotations, subagent, hasTopLevelHeuristicDowngrade = false) {
|
|
404553
404839
|
if (!command) {
|
|
404554
404840
|
return {
|
|
404555
404841
|
decision: ruleDecision,
|
|
@@ -404585,13 +404871,17 @@ var init_policy_engine = __esm({
|
|
|
404585
404871
|
}
|
|
404586
404872
|
let aggregateDecision = ruleDecision;
|
|
404587
404873
|
let responsibleRule = rule && ruleDecision === rule.decision ? rule : void 0;
|
|
404588
|
-
|
|
404874
|
+
const hasTopLevelRedirectionDowngrade = this.shouldDowngradeForRedirection(command, allowRedirection, rule);
|
|
404875
|
+
if (hasTopLevelRedirectionDowngrade) {
|
|
404589
404876
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
404590
404877
|
debugLogger.debug(`[PolicyEngine.check] Downgrading ALLOW to ASK_USER for redirected command: ${command}`);
|
|
404591
404878
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
404592
404879
|
responsibleRule = void 0;
|
|
404593
404880
|
}
|
|
404594
404881
|
}
|
|
404882
|
+
let evaluatedSubCommands = 0;
|
|
404883
|
+
let allSubCommandsExplicitlyAllowed = true;
|
|
404884
|
+
let lastAllowedSubRule;
|
|
404595
404885
|
for (const detail of subCommands) {
|
|
404596
404886
|
if (REDIRECTION_NAMES.has(detail.name)) {
|
|
404597
404887
|
continue;
|
|
@@ -404600,23 +404890,31 @@ var init_policy_engine = __esm({
|
|
|
404600
404890
|
const isAtomic = subCmd === command || detail.startIndex === 0 && detail.text.length === command.length;
|
|
404601
404891
|
const stripped = stripShellWrapper(subCmd);
|
|
404602
404892
|
if (stripped !== subCmd) {
|
|
404893
|
+
evaluatedSubCommands++;
|
|
404603
404894
|
const wrapperResult = await this.check({ name: toolName, args: { command: stripped, dir_path } }, serverName, toolAnnotations, subagent, true);
|
|
404604
404895
|
if (wrapperResult.decision === PolicyDecision.DENY)
|
|
404605
404896
|
return wrapperResult;
|
|
404606
404897
|
if (wrapperResult.decision === PolicyDecision.ASK_USER) {
|
|
404898
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
404607
404899
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
404608
404900
|
responsibleRule = wrapperResult.rule;
|
|
404609
404901
|
} else {
|
|
404610
404902
|
responsibleRule ??= wrapperResult.rule;
|
|
404611
404903
|
}
|
|
404612
404904
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
404905
|
+
} else if (wrapperResult.decision === PolicyDecision.ALLOW && wrapperResult.rule?.decision === PolicyDecision.ALLOW && Boolean(wrapperResult.rule?.argsPattern)) {
|
|
404906
|
+
lastAllowedSubRule = wrapperResult.rule;
|
|
404907
|
+
} else {
|
|
404908
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
404613
404909
|
}
|
|
404614
404910
|
}
|
|
404615
404911
|
if (!isAtomic) {
|
|
404912
|
+
evaluatedSubCommands++;
|
|
404616
404913
|
const subResult = await this.check({ name: toolName, args: { command: subCmd, dir_path } }, serverName, toolAnnotations, subagent, true);
|
|
404617
404914
|
if (subResult.decision === PolicyDecision.DENY)
|
|
404618
404915
|
return subResult;
|
|
404619
404916
|
if (subResult.decision === PolicyDecision.ASK_USER) {
|
|
404917
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
404620
404918
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
404621
404919
|
responsibleRule = subResult.rule;
|
|
404622
404920
|
} else {
|
|
@@ -404625,13 +404923,31 @@ var init_policy_engine = __esm({
|
|
|
404625
404923
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
404626
404924
|
}
|
|
404627
404925
|
if (subResult.decision === PolicyDecision.ALLOW && this.shouldDowngradeForRedirection(subCmd, subResult.rule?.allowRedirection ?? allowRedirection, subResult.rule)) {
|
|
404926
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
404628
404927
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
404629
404928
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
404630
404929
|
responsibleRule = void 0;
|
|
404631
404930
|
}
|
|
404931
|
+
} else if (subResult.decision === PolicyDecision.ALLOW && subResult.rule?.decision === PolicyDecision.ALLOW && Boolean(subResult.rule?.argsPattern)) {
|
|
404932
|
+
lastAllowedSubRule = subResult.rule;
|
|
404933
|
+
} else {
|
|
404934
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
404632
404935
|
}
|
|
404936
|
+
} else if (stripped === subCmd) {
|
|
404937
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
404633
404938
|
}
|
|
404634
404939
|
}
|
|
404940
|
+
const workspace = typeof this.sandboxManager.getWorkspace === "function" ? this.sandboxManager.getWorkspace() : process.cwd();
|
|
404941
|
+
const effectiveCwd = dir_path ? path85.resolve(workspace, dir_path) : workspace;
|
|
404942
|
+
const isOutsideWorkspace = effectiveCwd !== workspace && !isSubpath(workspace, effectiveCwd) && this.approvalMode !== ApprovalMode.YOLO;
|
|
404943
|
+
const parsedObjArgs = (0, import_shell_quote7.parse)(command);
|
|
404944
|
+
const parsedArgs = parsedObjArgs.map(extractStringFromParseEntry);
|
|
404945
|
+
const isUntrustedGit = containsGitCommand(parsedArgs) && !this.isTrustedFolder();
|
|
404946
|
+
const isDangerous = this.approvalMode !== ApprovalMode.YOLO && this.sandboxManager.isDangerousCommand(parsedArgs, effectiveCwd);
|
|
404947
|
+
if (aggregateDecision === PolicyDecision.ASK_USER && !rule?.argsPattern && !hasTopLevelRedirectionDowngrade && !hasTopLevelHeuristicDowngrade && !isOutsideWorkspace && !isUntrustedGit && !isDangerous && evaluatedSubCommands > 0 && allSubCommandsExplicitlyAllowed) {
|
|
404948
|
+
aggregateDecision = PolicyDecision.ALLOW;
|
|
404949
|
+
responsibleRule = lastAllowedSubRule;
|
|
404950
|
+
}
|
|
404635
404951
|
return {
|
|
404636
404952
|
decision: aggregateDecision,
|
|
404637
404953
|
rule: aggregateDecision === ruleDecision ? rule : responsibleRule
|
|
@@ -404689,11 +405005,16 @@ var init_policy_engine = __esm({
|
|
|
404689
405005
|
if (match2) {
|
|
404690
405006
|
debugLogger.debug(`[PolicyEngine.check] MATCHED rule: toolName=${rule.toolName}, decision=${rule.decision}, priority=${rule.priority}, argsPattern=${rule.argsPattern?.source || "none"}`);
|
|
404691
405007
|
let ruleDecision = rule.decision;
|
|
405008
|
+
let hasTopLevelHeuristicDowngrade = false;
|
|
404692
405009
|
if (!skipHeuristics && isShellCommand && command && !("commandPrefix" in rule) && !rule.argsPattern) {
|
|
405010
|
+
const prevDecision = ruleDecision;
|
|
404693
405011
|
ruleDecision = await this.applyShellHeuristics(command, ruleDecision, shellDirPath);
|
|
405012
|
+
if (prevDecision === PolicyDecision.ALLOW && ruleDecision === PolicyDecision.ASK_USER) {
|
|
405013
|
+
hasTopLevelHeuristicDowngrade = true;
|
|
405014
|
+
}
|
|
404694
405015
|
}
|
|
404695
405016
|
if (isShellCommand && toolName) {
|
|
404696
|
-
const shellResult = await this.checkShellCommand(toolName, command, ruleDecision, serverName, shellDirPath, rule.allowRedirection, rule, toolAnnotations, subagent);
|
|
405017
|
+
const shellResult = await this.checkShellCommand(toolName, command, ruleDecision, serverName, shellDirPath, rule.allowRedirection, rule, toolAnnotations, subagent, hasTopLevelHeuristicDowngrade);
|
|
404697
405018
|
decision = shellResult.decision;
|
|
404698
405019
|
matchedRule = shellResult.rule;
|
|
404699
405020
|
break;
|
|
@@ -404712,10 +405033,15 @@ var init_policy_engine = __esm({
|
|
|
404712
405033
|
debugLogger.debug(`[PolicyEngine.check] NO MATCH - using default decision: ${this.defaultDecision}`);
|
|
404713
405034
|
if (toolName && SHELL_TOOL_NAMES.includes(toolName)) {
|
|
404714
405035
|
let heuristicDecision = this.defaultDecision;
|
|
405036
|
+
let hasTopLevelHeuristicDowngrade = false;
|
|
404715
405037
|
if (!skipHeuristics && command) {
|
|
405038
|
+
const prevDecision = heuristicDecision;
|
|
404716
405039
|
heuristicDecision = await this.applyShellHeuristics(command, heuristicDecision, shellDirPath);
|
|
405040
|
+
if (prevDecision === PolicyDecision.ALLOW && heuristicDecision === PolicyDecision.ASK_USER) {
|
|
405041
|
+
hasTopLevelHeuristicDowngrade = true;
|
|
405042
|
+
}
|
|
404717
405043
|
}
|
|
404718
|
-
const shellResult = await this.checkShellCommand(toolName, command, heuristicDecision, serverName, shellDirPath, false, void 0, toolAnnotations, subagent);
|
|
405044
|
+
const shellResult = await this.checkShellCommand(toolName, command, heuristicDecision, serverName, shellDirPath, false, void 0, toolAnnotations, subagent, hasTopLevelHeuristicDowngrade);
|
|
404719
405045
|
decision = shellResult.decision;
|
|
404720
405046
|
matchedRule = shellResult.rule;
|
|
404721
405047
|
} else {
|
|
@@ -410196,6 +410522,7 @@ var init_oauth_provider = __esm({
|
|
|
410196
410522
|
issuer: discoveredConfig.issuer,
|
|
410197
410523
|
tokenUrl: discoveredConfig.tokenUrl,
|
|
410198
410524
|
scopes: config2.scopes || discoveredConfig.scopes || [],
|
|
410525
|
+
authorizationResponseIssParameterSupported: config2.authorizationResponseIssParameterSupported ?? discoveredConfig.authorizationResponseIssParameterSupported,
|
|
410199
410526
|
// Preserve existing client credentials
|
|
410200
410527
|
clientId: config2.clientId,
|
|
410201
410528
|
clientSecret: config2.clientSecret
|
|
@@ -410219,6 +410546,7 @@ var init_oauth_provider = __esm({
|
|
|
410219
410546
|
issuer: discoveredConfig.issuer,
|
|
410220
410547
|
scopes: config2.scopes || discoveredConfig.scopes || [],
|
|
410221
410548
|
registrationUrl: discoveredConfig.registrationUrl,
|
|
410549
|
+
authorizationResponseIssParameterSupported: config2.authorizationResponseIssParameterSupported ?? discoveredConfig.authorizationResponseIssParameterSupported,
|
|
410222
410550
|
// Preserve existing client credentials
|
|
410223
410551
|
clientId: config2.clientId,
|
|
410224
410552
|
clientSecret: config2.clientSecret
|
|
@@ -410231,7 +410559,8 @@ var init_oauth_provider = __esm({
|
|
|
410231
410559
|
const pkceParams = generatePKCEParams();
|
|
410232
410560
|
const preferredPort = getPortFromUrl(config2.redirectUri);
|
|
410233
410561
|
debugLogger.debug(`Starting callback server for "${serverName}" (expected issuer: ${config2.issuer || "none"})...`);
|
|
410234
|
-
const
|
|
410562
|
+
const requireIssInResponse = config2.authorizationResponseIssParameterSupported ?? Boolean(config2.issuer);
|
|
410563
|
+
const callbackServer = startCallbackServer(pkceParams.state, preferredPort, config2.issuer, requireIssInResponse);
|
|
410235
410564
|
const redirectPort = await callbackServer.port;
|
|
410236
410565
|
debugLogger.debug(`Callback server listening on port ${redirectPort}`);
|
|
410237
410566
|
if (!config2.clientId) {
|
|
@@ -410628,7 +410957,8 @@ async function handleAutomaticOAuth(mcpServerName, mcpServerConfig, wwwAuthentic
|
|
|
410628
410957
|
authorizationUrl: oauthConfig.authorizationUrl,
|
|
410629
410958
|
issuer: oauthConfig.issuer,
|
|
410630
410959
|
tokenUrl: oauthConfig.tokenUrl,
|
|
410631
|
-
scopes: oauthConfig.scopes || []
|
|
410960
|
+
scopes: oauthConfig.scopes || [],
|
|
410961
|
+
authorizationResponseIssParameterSupported: mcpServerConfig.oauth?.authorizationResponseIssParameterSupported ?? oauthConfig.authorizationResponseIssParameterSupported
|
|
410632
410962
|
};
|
|
410633
410963
|
debugLogger.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|
|
410634
410964
|
const authProvider = new MCPOAuthProvider(new MCPOAuthTokenStorage());
|
|
@@ -411044,7 +411374,8 @@ async function connectToMcpServer(clientVersion, mcpServerName, mcpServerConfig,
|
|
|
411044
411374
|
authorizationUrl: oauthConfig.authorizationUrl,
|
|
411045
411375
|
issuer: oauthConfig.issuer,
|
|
411046
411376
|
tokenUrl: oauthConfig.tokenUrl,
|
|
411047
|
-
scopes: oauthConfig.scopes || []
|
|
411377
|
+
scopes: oauthConfig.scopes || [],
|
|
411378
|
+
authorizationResponseIssParameterSupported: mcpServerConfig.oauth?.authorizationResponseIssParameterSupported ?? oauthConfig.authorizationResponseIssParameterSupported
|
|
411048
411379
|
};
|
|
411049
411380
|
const authServerUrl = mcpServerConfig.httpUrl || mcpServerConfig.url;
|
|
411050
411381
|
debugLogger.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|