@google/gemini-cli-a2a-server 0.15.0-preview.3 → 0.16.0-nightly.20251113.ad1f0d99
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 +374 -185
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/a2a-server.mjs
CHANGED
|
@@ -293122,16 +293122,14 @@ var CodeAssistServer = class {
|
|
|
293122
293122
|
});
|
|
293123
293123
|
let bufferedLines = [];
|
|
293124
293124
|
for await (const line of rl) {
|
|
293125
|
-
if (line
|
|
293125
|
+
if (line.startsWith("data: ")) {
|
|
293126
|
+
bufferedLines.push(line.slice(6).trim());
|
|
293127
|
+
} else if (line === "") {
|
|
293126
293128
|
if (bufferedLines.length === 0) {
|
|
293127
293129
|
continue;
|
|
293128
293130
|
}
|
|
293129
293131
|
yield JSON.parse(bufferedLines.join("\n"));
|
|
293130
293132
|
bufferedLines = [];
|
|
293131
|
-
} else if (line.startsWith("data: ")) {
|
|
293132
|
-
bufferedLines.push(line.slice(6).trim());
|
|
293133
|
-
} else {
|
|
293134
|
-
throw new Error(`Unexpected line format in response: ${line}`);
|
|
293135
293133
|
}
|
|
293136
293134
|
}
|
|
293137
293135
|
}();
|
|
@@ -293643,7 +293641,7 @@ function hasCycleInSchema(schema) {
|
|
|
293643
293641
|
}
|
|
293644
293642
|
if ("$ref" in node && typeof node.$ref === "string") {
|
|
293645
293643
|
const ref = node.$ref;
|
|
293646
|
-
if (ref === "#/" || pathRefs.has(ref)) {
|
|
293644
|
+
if (ref === "#" || ref === "#/" || pathRefs.has(ref)) {
|
|
293647
293645
|
return true;
|
|
293648
293646
|
}
|
|
293649
293647
|
if (visitedRefs.has(ref)) {
|
|
@@ -295263,23 +295261,29 @@ var LoopDetectedEvent = class {
|
|
|
295263
295261
|
"event.timestamp";
|
|
295264
295262
|
loop_type;
|
|
295265
295263
|
prompt_id;
|
|
295266
|
-
|
|
295264
|
+
confirmed_by_model;
|
|
295265
|
+
constructor(loop_type, prompt_id, confirmed_by_model) {
|
|
295267
295266
|
this["event.name"] = "loop_detected";
|
|
295268
295267
|
this["event.timestamp"] = (/* @__PURE__ */ new Date()).toISOString();
|
|
295269
295268
|
this.loop_type = loop_type;
|
|
295270
295269
|
this.prompt_id = prompt_id;
|
|
295270
|
+
this.confirmed_by_model = confirmed_by_model;
|
|
295271
295271
|
}
|
|
295272
295272
|
toOpenTelemetryAttributes(config2) {
|
|
295273
|
-
|
|
295273
|
+
const attributes = {
|
|
295274
295274
|
...getCommonAttributes(config2),
|
|
295275
295275
|
"event.name": this["event.name"],
|
|
295276
295276
|
"event.timestamp": this["event.timestamp"],
|
|
295277
295277
|
loop_type: this.loop_type,
|
|
295278
295278
|
prompt_id: this.prompt_id
|
|
295279
295279
|
};
|
|
295280
|
+
if (this.confirmed_by_model) {
|
|
295281
|
+
attributes["confirmed_by_model"] = this.confirmed_by_model;
|
|
295282
|
+
}
|
|
295283
|
+
return attributes;
|
|
295280
295284
|
}
|
|
295281
295285
|
toLogBody() {
|
|
295282
|
-
return `Loop detected. Type: ${this.loop_type}
|
|
295286
|
+
return `Loop detected. Type: ${this.loop_type}.${this.confirmed_by_model ? ` Confirmed by: ${this.confirmed_by_model}` : ""}`;
|
|
295283
295287
|
}
|
|
295284
295288
|
};
|
|
295285
295289
|
var LoopDetectionDisabledEvent = class {
|
|
@@ -295569,6 +295573,37 @@ var ToolOutputTruncatedEvent = class {
|
|
|
295569
295573
|
return `Tool output truncated for ${this.tool_name}.`;
|
|
295570
295574
|
}
|
|
295571
295575
|
};
|
|
295576
|
+
var EVENT_LLM_LOOP_CHECK = "gemini_cli.llm_loop_check";
|
|
295577
|
+
var LlmLoopCheckEvent = class {
|
|
295578
|
+
"event.name";
|
|
295579
|
+
"event.timestamp";
|
|
295580
|
+
prompt_id;
|
|
295581
|
+
flash_confidence;
|
|
295582
|
+
main_model;
|
|
295583
|
+
main_model_confidence;
|
|
295584
|
+
constructor(prompt_id, flash_confidence, main_model, main_model_confidence) {
|
|
295585
|
+
this["event.name"] = "llm_loop_check";
|
|
295586
|
+
this["event.timestamp"] = (/* @__PURE__ */ new Date()).toISOString();
|
|
295587
|
+
this.prompt_id = prompt_id;
|
|
295588
|
+
this.flash_confidence = flash_confidence;
|
|
295589
|
+
this.main_model = main_model;
|
|
295590
|
+
this.main_model_confidence = main_model_confidence;
|
|
295591
|
+
}
|
|
295592
|
+
toOpenTelemetryAttributes(config2) {
|
|
295593
|
+
return {
|
|
295594
|
+
...getCommonAttributes(config2),
|
|
295595
|
+
"event.name": EVENT_LLM_LOOP_CHECK,
|
|
295596
|
+
"event.timestamp": this["event.timestamp"],
|
|
295597
|
+
prompt_id: this.prompt_id,
|
|
295598
|
+
flash_confidence: this.flash_confidence,
|
|
295599
|
+
main_model: this.main_model,
|
|
295600
|
+
main_model_confidence: this.main_model_confidence
|
|
295601
|
+
};
|
|
295602
|
+
}
|
|
295603
|
+
toLogBody() {
|
|
295604
|
+
return this.main_model_confidence === -1 ? `LLM loop check. Flash confidence: ${this.flash_confidence.toFixed(2)}. Main model (${this.main_model}) check skipped` : `LLM loop check. Flash confidence: ${this.flash_confidence.toFixed(2)}. Main model (${this.main_model}) confidence: ${this.main_model_confidence.toFixed(2)}`;
|
|
295605
|
+
}
|
|
295606
|
+
};
|
|
295572
295607
|
var EVENT_SMART_EDIT_STRATEGY = "gemini_cli.smart_edit_strategy";
|
|
295573
295608
|
var SmartEditStrategyEvent = class {
|
|
295574
295609
|
"event.name";
|
|
@@ -295874,6 +295909,10 @@ var EventMetadataKey;
|
|
|
295874
295909
|
EventMetadataKey2[EventMetadataKey2["GEMINI_CLI_AGENT_RECOVERY_DURATION_MS"] = 123] = "GEMINI_CLI_AGENT_RECOVERY_DURATION_MS";
|
|
295875
295910
|
EventMetadataKey2[EventMetadataKey2["GEMINI_CLI_AGENT_RECOVERY_SUCCESS"] = 124] = "GEMINI_CLI_AGENT_RECOVERY_SUCCESS";
|
|
295876
295911
|
EventMetadataKey2[EventMetadataKey2["GEMINI_CLI_INTERACTIVE"] = 125] = "GEMINI_CLI_INTERACTIVE";
|
|
295912
|
+
EventMetadataKey2[EventMetadataKey2["GEMINI_CLI_LLM_LOOP_CHECK_FLASH_CONFIDENCE"] = 126] = "GEMINI_CLI_LLM_LOOP_CHECK_FLASH_CONFIDENCE";
|
|
295913
|
+
EventMetadataKey2[EventMetadataKey2["GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL"] = 127] = "GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL";
|
|
295914
|
+
EventMetadataKey2[EventMetadataKey2["GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL_CONFIDENCE"] = 128] = "GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL_CONFIDENCE";
|
|
295915
|
+
EventMetadataKey2[EventMetadataKey2["GEMINI_CLI_LOOP_DETECTED_CONFIRMED_BY_MODEL"] = 129] = "GEMINI_CLI_LOOP_DETECTED_CONFIRMED_BY_MODEL";
|
|
295877
295916
|
})(EventMetadataKey || (EventMetadataKey = {}));
|
|
295878
295917
|
|
|
295879
295918
|
// node_modules/mnemonist/index.mjs
|
|
@@ -295899,8 +295938,8 @@ var Float64Vector = import_vector.default.Float64Vector;
|
|
|
295899
295938
|
var PointerVector = import_vector.default.PointerVector;
|
|
295900
295939
|
|
|
295901
295940
|
// packages/core/dist/src/generated/git-commit.js
|
|
295902
|
-
var GIT_COMMIT_INFO = "
|
|
295903
|
-
var CLI_VERSION = "0.
|
|
295941
|
+
var GIT_COMMIT_INFO = "ad1f0d99";
|
|
295942
|
+
var CLI_VERSION = "0.16.0-nightly.20251113.ad1f0d99";
|
|
295904
295943
|
|
|
295905
295944
|
// packages/core/dist/src/ide/detect-ide.js
|
|
295906
295945
|
var IDE_DEFINITIONS = {
|
|
@@ -296003,6 +296042,7 @@ var EventNames;
|
|
|
296003
296042
|
EventNames2["AGENT_FINISH"] = "agent_finish";
|
|
296004
296043
|
EventNames2["RECOVERY_ATTEMPT"] = "recovery_attempt";
|
|
296005
296044
|
EventNames2["WEB_FETCH_FALLBACK_ATTEMPT"] = "web_fetch_fallback_attempt";
|
|
296045
|
+
EventNames2["LLM_LOOP_CHECK"] = "llm_loop_check";
|
|
296006
296046
|
})(EventNames || (EventNames = {}));
|
|
296007
296047
|
function determineSurface() {
|
|
296008
296048
|
if (process.env["SURFACE"]) {
|
|
@@ -296494,6 +296534,12 @@ var ClearcutLogger = class _ClearcutLogger {
|
|
|
296494
296534
|
value: JSON.stringify(event.loop_type)
|
|
296495
296535
|
}
|
|
296496
296536
|
];
|
|
296537
|
+
if (event.confirmed_by_model) {
|
|
296538
|
+
data.push({
|
|
296539
|
+
gemini_cli_key: EventMetadataKey.GEMINI_CLI_LOOP_DETECTED_CONFIRMED_BY_MODEL,
|
|
296540
|
+
value: event.confirmed_by_model
|
|
296541
|
+
});
|
|
296542
|
+
}
|
|
296497
296543
|
this.enqueueLogEvent(this.createLogEvent(EventNames.LOOP_DETECTED, data));
|
|
296498
296544
|
this.flushIfNeeded();
|
|
296499
296545
|
}
|
|
@@ -296929,6 +296975,28 @@ var ClearcutLogger = class _ClearcutLogger {
|
|
|
296929
296975
|
this.enqueueLogEvent(this.createLogEvent(EventNames.WEB_FETCH_FALLBACK_ATTEMPT, data));
|
|
296930
296976
|
this.flushIfNeeded();
|
|
296931
296977
|
}
|
|
296978
|
+
logLlmLoopCheckEvent(event) {
|
|
296979
|
+
const data = [
|
|
296980
|
+
{
|
|
296981
|
+
gemini_cli_key: EventMetadataKey.GEMINI_CLI_PROMPT_ID,
|
|
296982
|
+
value: event.prompt_id
|
|
296983
|
+
},
|
|
296984
|
+
{
|
|
296985
|
+
gemini_cli_key: EventMetadataKey.GEMINI_CLI_LLM_LOOP_CHECK_FLASH_CONFIDENCE,
|
|
296986
|
+
value: event.flash_confidence.toString()
|
|
296987
|
+
},
|
|
296988
|
+
{
|
|
296989
|
+
gemini_cli_key: EventMetadataKey.GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL,
|
|
296990
|
+
value: event.main_model
|
|
296991
|
+
},
|
|
296992
|
+
{
|
|
296993
|
+
gemini_cli_key: EventMetadataKey.GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL_CONFIDENCE,
|
|
296994
|
+
value: event.main_model_confidence.toString()
|
|
296995
|
+
}
|
|
296996
|
+
];
|
|
296997
|
+
this.enqueueLogEvent(this.createLogEvent(EventNames.LLM_LOOP_CHECK, data));
|
|
296998
|
+
this.flushIfNeeded();
|
|
296999
|
+
}
|
|
296932
297000
|
/**
|
|
296933
297001
|
* Adds default fields to data, and returns a new data array. This fields
|
|
296934
297002
|
* should exist on all log events.
|
|
@@ -298363,6 +298431,17 @@ function logWebFetchFallbackAttempt(config2, event) {
|
|
|
298363
298431
|
};
|
|
298364
298432
|
logger6.emit(logRecord);
|
|
298365
298433
|
}
|
|
298434
|
+
function logLlmLoopCheck(config2, event) {
|
|
298435
|
+
ClearcutLogger.getInstance(config2)?.logLlmLoopCheckEvent(event);
|
|
298436
|
+
if (!isTelemetrySdkInitialized())
|
|
298437
|
+
return;
|
|
298438
|
+
const logger6 = import_api_logs.logs.getLogger(SERVICE_NAME);
|
|
298439
|
+
const logRecord = {
|
|
298440
|
+
body: event.toLogBody(),
|
|
298441
|
+
attributes: event.toOpenTelemetryAttributes(config2)
|
|
298442
|
+
};
|
|
298443
|
+
logger6.emit(logRecord);
|
|
298444
|
+
}
|
|
298366
298445
|
|
|
298367
298446
|
// packages/core/dist/src/utils/quotaErrorDetection.js
|
|
298368
298447
|
function isApiError(error) {
|
|
@@ -298705,7 +298784,7 @@ async function createContentGenerator(config2, gcConfig, sessionId2) {
|
|
|
298705
298784
|
if (gcConfig.fakeResponses) {
|
|
298706
298785
|
return FakeContentGenerator.fromFile(gcConfig.fakeResponses);
|
|
298707
298786
|
}
|
|
298708
|
-
const version3 = "0.
|
|
298787
|
+
const version3 = "0.16.0-nightly.20251113.ad1f0d99";
|
|
298709
298788
|
const userAgent = `GeminiCLI/${version3} (${process.platform}; ${process.arch})`;
|
|
298710
298789
|
const baseHeaders = {
|
|
298711
298790
|
"User-Agent": userAgent
|
|
@@ -300911,7 +300990,7 @@ var MemoryToolInvocation = class _MemoryToolInvocation extends BaseToolInvocatio
|
|
|
300911
300990
|
var MemoryTool = class _MemoryTool extends BaseDeclarativeTool {
|
|
300912
300991
|
static Name = MEMORY_TOOL_NAME;
|
|
300913
300992
|
constructor(messageBus) {
|
|
300914
|
-
super(_MemoryTool.Name, "
|
|
300993
|
+
super(_MemoryTool.Name, "SaveMemory", memoryToolDescription, Kind.Think, memoryToolSchemaData.parametersJsonSchema, true, false, messageBus);
|
|
300915
300994
|
}
|
|
300916
300995
|
validateToolParamValues(params) {
|
|
300917
300996
|
if (params.fact.trim() === "") {
|
|
@@ -320614,83 +320693,61 @@ async function ensureRgPath() {
|
|
|
320614
320693
|
}
|
|
320615
320694
|
throw new Error("Cannot use ripgrep.");
|
|
320616
320695
|
}
|
|
320696
|
+
function resolveAndValidatePath(config2, relativePath) {
|
|
320697
|
+
if (!relativePath) {
|
|
320698
|
+
return null;
|
|
320699
|
+
}
|
|
320700
|
+
const targetDir = config2.getTargetDir();
|
|
320701
|
+
const targetPath = path33.resolve(targetDir, relativePath);
|
|
320702
|
+
const workspaceContext = config2.getWorkspaceContext();
|
|
320703
|
+
if (!workspaceContext.isPathWithinWorkspace(targetPath)) {
|
|
320704
|
+
const directories = workspaceContext.getDirectories();
|
|
320705
|
+
throw new Error(`Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(", ")}`);
|
|
320706
|
+
}
|
|
320707
|
+
try {
|
|
320708
|
+
const stats = fs31.statSync(targetPath);
|
|
320709
|
+
if (!stats.isDirectory() && !stats.isFile()) {
|
|
320710
|
+
throw new Error(`Path is not a valid directory or file: ${targetPath} (CWD: ${targetDir})`);
|
|
320711
|
+
}
|
|
320712
|
+
} catch (error) {
|
|
320713
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
320714
|
+
throw new Error(`Path does not exist: ${targetPath} (CWD: ${targetDir})`);
|
|
320715
|
+
}
|
|
320716
|
+
throw new Error(`Failed to access path stats for ${targetPath}: ${error}`);
|
|
320717
|
+
}
|
|
320718
|
+
return targetPath;
|
|
320719
|
+
}
|
|
320617
320720
|
var GrepToolInvocation2 = class extends BaseToolInvocation {
|
|
320618
320721
|
config;
|
|
320619
320722
|
constructor(config2, params, messageBus, _toolName, _toolDisplayName) {
|
|
320620
320723
|
super(params, messageBus, _toolName, _toolDisplayName);
|
|
320621
320724
|
this.config = config2;
|
|
320622
320725
|
}
|
|
320623
|
-
/**
|
|
320624
|
-
* Checks if a path is within the root directory and resolves it.
|
|
320625
|
-
* @param relativePath Path relative to the root directory (or undefined for root).
|
|
320626
|
-
* @returns The absolute path if valid and exists, or null if no path specified (to search all directories).
|
|
320627
|
-
* @throws {Error} If path is outside root, doesn't exist, or isn't a directory.
|
|
320628
|
-
*/
|
|
320629
|
-
resolveAndValidatePath(relativePath) {
|
|
320630
|
-
if (!relativePath) {
|
|
320631
|
-
return null;
|
|
320632
|
-
}
|
|
320633
|
-
const targetPath = path33.resolve(this.config.getTargetDir(), relativePath);
|
|
320634
|
-
const workspaceContext = this.config.getWorkspaceContext();
|
|
320635
|
-
if (!workspaceContext.isPathWithinWorkspace(targetPath)) {
|
|
320636
|
-
const directories = workspaceContext.getDirectories();
|
|
320637
|
-
throw new Error(`Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(", ")}`);
|
|
320638
|
-
}
|
|
320639
|
-
try {
|
|
320640
|
-
const stats = fs31.statSync(targetPath);
|
|
320641
|
-
if (!stats.isDirectory()) {
|
|
320642
|
-
throw new Error(`Path is not a directory: ${targetPath}`);
|
|
320643
|
-
}
|
|
320644
|
-
} catch (error) {
|
|
320645
|
-
if (isNodeError(error) && error.code !== "ENOENT") {
|
|
320646
|
-
throw new Error(`Path does not exist: ${targetPath}`);
|
|
320647
|
-
}
|
|
320648
|
-
throw new Error(`Failed to access path stats for ${targetPath}: ${error}`);
|
|
320649
|
-
}
|
|
320650
|
-
return targetPath;
|
|
320651
|
-
}
|
|
320652
320726
|
async execute(signal) {
|
|
320653
320727
|
try {
|
|
320654
|
-
const
|
|
320655
|
-
const searchDirAbs =
|
|
320656
|
-
const searchDirDisplay =
|
|
320657
|
-
let searchDirectories;
|
|
320658
|
-
if (searchDirAbs === null) {
|
|
320659
|
-
searchDirectories = workspaceContext.getDirectories();
|
|
320660
|
-
} else {
|
|
320661
|
-
searchDirectories = [searchDirAbs];
|
|
320662
|
-
}
|
|
320663
|
-
let allMatches = [];
|
|
320728
|
+
const pathParam = this.params.dir_path || ".";
|
|
320729
|
+
const searchDirAbs = resolveAndValidatePath(this.config, pathParam);
|
|
320730
|
+
const searchDirDisplay = pathParam;
|
|
320664
320731
|
const totalMaxMatches = DEFAULT_TOTAL_MAX_MATCHES;
|
|
320665
320732
|
if (this.config.getDebugMode()) {
|
|
320666
320733
|
debugLogger.log(`[GrepTool] Total result limit: ${totalMaxMatches}`);
|
|
320667
320734
|
}
|
|
320668
|
-
|
|
320669
|
-
|
|
320670
|
-
|
|
320671
|
-
|
|
320672
|
-
|
|
320673
|
-
|
|
320674
|
-
|
|
320675
|
-
|
|
320676
|
-
|
|
320677
|
-
|
|
320678
|
-
|
|
320679
|
-
|
|
320680
|
-
|
|
320681
|
-
allMatches = allMatches.
|
|
320682
|
-
if (allMatches.length >= totalMaxMatches) {
|
|
320683
|
-
allMatches = allMatches.slice(0, totalMaxMatches);
|
|
320684
|
-
break;
|
|
320685
|
-
}
|
|
320686
|
-
}
|
|
320687
|
-
let searchLocationDescription;
|
|
320688
|
-
if (searchDirAbs === null) {
|
|
320689
|
-
const numDirs = workspaceContext.getDirectories().length;
|
|
320690
|
-
searchLocationDescription = numDirs > 1 ? `across ${numDirs} workspace directories` : `in the workspace directory`;
|
|
320691
|
-
} else {
|
|
320692
|
-
searchLocationDescription = `in path "${searchDirDisplay}"`;
|
|
320735
|
+
let allMatches = await this.performRipgrepSearch({
|
|
320736
|
+
pattern: this.params.pattern,
|
|
320737
|
+
path: searchDirAbs,
|
|
320738
|
+
include: this.params.include,
|
|
320739
|
+
case_sensitive: this.params.case_sensitive,
|
|
320740
|
+
fixed_strings: this.params.fixed_strings,
|
|
320741
|
+
context: this.params.context,
|
|
320742
|
+
after: this.params.after,
|
|
320743
|
+
before: this.params.before,
|
|
320744
|
+
no_ignore: this.params.no_ignore,
|
|
320745
|
+
signal
|
|
320746
|
+
});
|
|
320747
|
+
if (allMatches.length >= totalMaxMatches) {
|
|
320748
|
+
allMatches = allMatches.slice(0, totalMaxMatches);
|
|
320693
320749
|
}
|
|
320750
|
+
const searchLocationDescription = `in path "${searchDirDisplay}"`;
|
|
320694
320751
|
if (allMatches.length === 0) {
|
|
320695
320752
|
const noMatchMsg = `No matches found for pattern "${this.params.pattern}" ${searchLocationDescription}${this.params.include ? ` (filter: "${this.params.include}")` : ""}.`;
|
|
320696
320753
|
return { llmContent: noMatchMsg, returnDisplay: `No matches found` };
|
|
@@ -320770,24 +320827,43 @@ var GrepToolInvocation2 = class extends BaseToolInvocation {
|
|
|
320770
320827
|
return results;
|
|
320771
320828
|
}
|
|
320772
320829
|
async performRipgrepSearch(options2) {
|
|
320773
|
-
const { pattern, path: absolutePath, include } = options2;
|
|
320774
|
-
const rgArgs = ["--json"
|
|
320830
|
+
const { pattern, path: absolutePath, include, case_sensitive, fixed_strings, context: context2, after, before, no_ignore } = options2;
|
|
320831
|
+
const rgArgs = ["--json"];
|
|
320832
|
+
if (!case_sensitive) {
|
|
320833
|
+
rgArgs.push("--ignore-case");
|
|
320834
|
+
}
|
|
320835
|
+
if (fixed_strings) {
|
|
320836
|
+
rgArgs.push("--fixed-strings");
|
|
320837
|
+
rgArgs.push(pattern);
|
|
320838
|
+
} else {
|
|
320839
|
+
rgArgs.push("--regexp", pattern);
|
|
320840
|
+
}
|
|
320841
|
+
if (context2) {
|
|
320842
|
+
rgArgs.push("--context", context2.toString());
|
|
320843
|
+
}
|
|
320844
|
+
if (after) {
|
|
320845
|
+
rgArgs.push("--after-context", after.toString());
|
|
320846
|
+
}
|
|
320847
|
+
if (before) {
|
|
320848
|
+
rgArgs.push("--before-context", before.toString());
|
|
320849
|
+
}
|
|
320850
|
+
if (no_ignore) {
|
|
320851
|
+
rgArgs.push("--no-ignore");
|
|
320852
|
+
}
|
|
320775
320853
|
if (include) {
|
|
320776
320854
|
rgArgs.push("--glob", include);
|
|
320777
320855
|
}
|
|
320778
|
-
|
|
320779
|
-
|
|
320780
|
-
|
|
320781
|
-
|
|
320782
|
-
|
|
320783
|
-
|
|
320784
|
-
|
|
320785
|
-
|
|
320786
|
-
|
|
320787
|
-
|
|
320788
|
-
|
|
320789
|
-
rgArgs.push("--glob", `!${exclude}`);
|
|
320790
|
-
});
|
|
320856
|
+
if (!no_ignore) {
|
|
320857
|
+
const fileExclusions = new FileExclusions(this.config);
|
|
320858
|
+
const excludes = fileExclusions.getGlobExcludes([
|
|
320859
|
+
...COMMON_DIRECTORY_EXCLUDES,
|
|
320860
|
+
"*.log",
|
|
320861
|
+
"*.tmp"
|
|
320862
|
+
]);
|
|
320863
|
+
excludes.forEach((exclude) => {
|
|
320864
|
+
rgArgs.push("--glob", `!${exclude}`);
|
|
320865
|
+
});
|
|
320866
|
+
}
|
|
320791
320867
|
rgArgs.push("--threads", "4");
|
|
320792
320868
|
rgArgs.push(absolutePath);
|
|
320793
320869
|
try {
|
|
@@ -320839,20 +320915,13 @@ var GrepToolInvocation2 = class extends BaseToolInvocation {
|
|
|
320839
320915
|
if (this.params.include) {
|
|
320840
320916
|
description += ` in ${this.params.include}`;
|
|
320841
320917
|
}
|
|
320842
|
-
|
|
320843
|
-
|
|
320844
|
-
|
|
320845
|
-
|
|
320846
|
-
} else {
|
|
320847
|
-
const relativePath = makeRelative(resolvedPath, this.config.getTargetDir());
|
|
320848
|
-
description += ` within ${shortenPath(relativePath)}`;
|
|
320849
|
-
}
|
|
320918
|
+
const pathParam = this.params.dir_path || ".";
|
|
320919
|
+
const resolvedPath = path33.resolve(this.config.getTargetDir(), pathParam);
|
|
320920
|
+
if (resolvedPath === this.config.getTargetDir() || pathParam === ".") {
|
|
320921
|
+
description += ` within ./`;
|
|
320850
320922
|
} else {
|
|
320851
|
-
const
|
|
320852
|
-
|
|
320853
|
-
if (directories.length > 1) {
|
|
320854
|
-
description += ` across all workspace directories`;
|
|
320855
|
-
}
|
|
320923
|
+
const relativePath = makeRelative(resolvedPath, this.config.getTargetDir());
|
|
320924
|
+
description += ` within ${shortenPath(relativePath)}`;
|
|
320856
320925
|
}
|
|
320857
320926
|
return description;
|
|
320858
320927
|
}
|
|
@@ -320864,21 +320933,45 @@ var RipGrepTool = class _RipGrepTool extends BaseDeclarativeTool {
|
|
|
320864
320933
|
super(
|
|
320865
320934
|
_RipGrepTool.Name,
|
|
320866
320935
|
"SearchText",
|
|
320867
|
-
|
|
320936
|
+
'FAST, optimized search powered by `ripgrep`. PREFERRED over standard `run_shell_command("grep ...")` due to better performance and automatic output limiting (max 20k matches).',
|
|
320868
320937
|
Kind.Search,
|
|
320869
320938
|
{
|
|
320870
320939
|
properties: {
|
|
320871
320940
|
pattern: {
|
|
320872
|
-
description: "The
|
|
320941
|
+
description: "The pattern to search for. By default, treated as a Rust-flavored regular expression. Use '\\b' for precise symbol matching (e.g., '\\bMatchMe\\b').",
|
|
320873
320942
|
type: "string"
|
|
320874
320943
|
},
|
|
320875
320944
|
dir_path: {
|
|
320876
|
-
description: "
|
|
320945
|
+
description: "Directory or file to search. Directories are searched recursively. Relative paths are resolved against current working directory. Defaults to current working directory ('.') if omitted.",
|
|
320877
320946
|
type: "string"
|
|
320878
320947
|
},
|
|
320879
320948
|
include: {
|
|
320880
|
-
description: "
|
|
320949
|
+
description: "Glob pattern to filter files (e.g., '*.ts', 'src/**'). Recommended for large repositories to reduce noise. Defaults to all files if omitted.",
|
|
320881
320950
|
type: "string"
|
|
320951
|
+
},
|
|
320952
|
+
case_sensitive: {
|
|
320953
|
+
description: "If true, search is case-sensitive. Defaults to false (ignore case) if omitted.",
|
|
320954
|
+
type: "boolean"
|
|
320955
|
+
},
|
|
320956
|
+
fixed_strings: {
|
|
320957
|
+
description: "If true, treats the `pattern` as a literal string instead of a regular expression. Defaults to false (basic regex) if omitted.",
|
|
320958
|
+
type: "boolean"
|
|
320959
|
+
},
|
|
320960
|
+
context: {
|
|
320961
|
+
description: "Show this many lines of context around each match (equivalent to grep -C). Defaults to 0 if omitted.",
|
|
320962
|
+
type: "integer"
|
|
320963
|
+
},
|
|
320964
|
+
after: {
|
|
320965
|
+
description: "Show this many lines after each match (equivalent to grep -A). Defaults to 0 if omitted.",
|
|
320966
|
+
type: "integer"
|
|
320967
|
+
},
|
|
320968
|
+
before: {
|
|
320969
|
+
description: "Show this many lines before each match (equivalent to grep -B). Defaults to 0 if omitted.",
|
|
320970
|
+
type: "integer"
|
|
320971
|
+
},
|
|
320972
|
+
no_ignore: {
|
|
320973
|
+
description: "If true, searches all files including those usually ignored (like in .gitignore, build/, dist/, etc). Defaults to false if omitted.",
|
|
320974
|
+
type: "boolean"
|
|
320882
320975
|
}
|
|
320883
320976
|
},
|
|
320884
320977
|
required: ["pattern"],
|
|
@@ -320892,35 +320985,6 @@ var RipGrepTool = class _RipGrepTool extends BaseDeclarativeTool {
|
|
|
320892
320985
|
);
|
|
320893
320986
|
this.config = config2;
|
|
320894
320987
|
}
|
|
320895
|
-
/**
|
|
320896
|
-
* Checks if a path is within the root directory and resolves it.
|
|
320897
|
-
* @param relativePath Path relative to the root directory (or undefined for root).
|
|
320898
|
-
* @returns The absolute path if valid and exists, or null if no path specified (to search all directories).
|
|
320899
|
-
* @throws {Error} If path is outside root, doesn't exist, or isn't a directory.
|
|
320900
|
-
*/
|
|
320901
|
-
resolveAndValidatePath(relativePath) {
|
|
320902
|
-
if (!relativePath) {
|
|
320903
|
-
return null;
|
|
320904
|
-
}
|
|
320905
|
-
const targetPath = path33.resolve(this.config.getTargetDir(), relativePath);
|
|
320906
|
-
const workspaceContext = this.config.getWorkspaceContext();
|
|
320907
|
-
if (!workspaceContext.isPathWithinWorkspace(targetPath)) {
|
|
320908
|
-
const directories = workspaceContext.getDirectories();
|
|
320909
|
-
throw new Error(`Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(", ")}`);
|
|
320910
|
-
}
|
|
320911
|
-
try {
|
|
320912
|
-
const stats = fs31.statSync(targetPath);
|
|
320913
|
-
if (!stats.isDirectory()) {
|
|
320914
|
-
throw new Error(`Path is not a directory: ${targetPath}`);
|
|
320915
|
-
}
|
|
320916
|
-
} catch (error) {
|
|
320917
|
-
if (isNodeError(error) && error.code !== "ENOENT") {
|
|
320918
|
-
throw new Error(`Path does not exist: ${targetPath}`);
|
|
320919
|
-
}
|
|
320920
|
-
throw new Error(`Failed to access path stats for ${targetPath}: ${error}`);
|
|
320921
|
-
}
|
|
320922
|
-
return targetPath;
|
|
320923
|
-
}
|
|
320924
320988
|
/**
|
|
320925
320989
|
* Validates the parameters for the tool
|
|
320926
320990
|
* @param params Parameters to validate
|
|
@@ -320933,7 +320997,7 @@ var RipGrepTool = class _RipGrepTool extends BaseDeclarativeTool {
|
|
|
320933
320997
|
}
|
|
320934
320998
|
if (params.dir_path) {
|
|
320935
320999
|
try {
|
|
320936
|
-
this.
|
|
321000
|
+
resolveAndValidatePath(this.config, params.dir_path);
|
|
320937
321001
|
} catch (error) {
|
|
320938
321002
|
return getErrorMessage(error);
|
|
320939
321003
|
}
|
|
@@ -321163,6 +321227,10 @@ var ApprovalMode;
|
|
|
321163
321227
|
ApprovalMode2["AUTO_EDIT"] = "autoEdit";
|
|
321164
321228
|
ApprovalMode2["YOLO"] = "yolo";
|
|
321165
321229
|
})(ApprovalMode || (ApprovalMode = {}));
|
|
321230
|
+
var InProcessCheckerType;
|
|
321231
|
+
(function(InProcessCheckerType2) {
|
|
321232
|
+
InProcessCheckerType2["ALLOWED_PATH"] = "allowed-path";
|
|
321233
|
+
})(InProcessCheckerType || (InProcessCheckerType = {}));
|
|
321166
321234
|
|
|
321167
321235
|
// packages/core/dist/src/utils/LruCache.js
|
|
321168
321236
|
var LruCache = class {
|
|
@@ -345309,7 +345377,7 @@ ${todoListString}` : "Successfully cleared the todo list.";
|
|
|
345309
345377
|
var WriteTodosTool = class _WriteTodosTool extends BaseDeclarativeTool {
|
|
345310
345378
|
static Name = WRITE_TODOS_TOOL_NAME;
|
|
345311
345379
|
constructor() {
|
|
345312
|
-
super(_WriteTodosTool.Name, "
|
|
345380
|
+
super(_WriteTodosTool.Name, "WriteTodos", WRITE_TODOS_DESCRIPTION, Kind.Other, {
|
|
345313
345381
|
type: "object",
|
|
345314
345382
|
properties: {
|
|
345315
345383
|
todos: {
|
|
@@ -345810,6 +345878,8 @@ var LLM_CHECK_AFTER_TURNS = 30;
|
|
|
345810
345878
|
var DEFAULT_LLM_CHECK_INTERVAL = 3;
|
|
345811
345879
|
var MIN_LLM_CHECK_INTERVAL = 5;
|
|
345812
345880
|
var MAX_LLM_CHECK_INTERVAL = 15;
|
|
345881
|
+
var LLM_CONFIDENCE_THRESHOLD = 0.9;
|
|
345882
|
+
var DOUBLE_CHECK_MODEL_ALIAS = "loop-detection-double-check";
|
|
345813
345883
|
var LOOP_DETECTION_SYSTEM_PROMPT = `You are a sophisticated AI diagnostic agent specializing in identifying when a conversational AI is stuck in an unproductive state. Your task is to analyze the provided conversation history and determine if the assistant has ceased to make meaningful progress.
|
|
345814
345884
|
|
|
345815
345885
|
An unproductive state is characterized by one or more of the following patterns over the last 5 or more assistant turns:
|
|
@@ -345820,6 +345890,20 @@ Cognitive Loop: The assistant seems unable to determine the next logical step. I
|
|
|
345820
345890
|
|
|
345821
345891
|
Crucially, differentiate between a true unproductive state and legitimate, incremental progress.
|
|
345822
345892
|
For example, a series of 'tool_A' or 'tool_B' tool calls that make small, distinct changes to the same file (like adding docstrings to functions one by one) is considered forward progress and is NOT a loop. A loop would be repeatedly replacing the same text with the same content, or cycling between a small set of files with no net change.`;
|
|
345893
|
+
var LOOP_DETECTION_SCHEMA = {
|
|
345894
|
+
type: "object",
|
|
345895
|
+
properties: {
|
|
345896
|
+
unproductive_state_analysis: {
|
|
345897
|
+
type: "string",
|
|
345898
|
+
description: "Your reasoning on if the conversation is looping without forward progress."
|
|
345899
|
+
},
|
|
345900
|
+
unproductive_state_confidence: {
|
|
345901
|
+
type: "number",
|
|
345902
|
+
description: "A number between 0.0 and 1.0 representing your confidence that the conversation is in an unproductive state."
|
|
345903
|
+
}
|
|
345904
|
+
},
|
|
345905
|
+
required: ["unproductive_state_analysis", "unproductive_state_confidence"]
|
|
345906
|
+
};
|
|
345823
345907
|
var LoopDetectionService = class {
|
|
345824
345908
|
config;
|
|
345825
345909
|
promptId = "";
|
|
@@ -346047,49 +346131,67 @@ var LoopDetectionService = class {
|
|
|
346047
346131
|
parts: [{ text: "Recent conversation history:" }]
|
|
346048
346132
|
});
|
|
346049
346133
|
}
|
|
346050
|
-
const
|
|
346051
|
-
|
|
346052
|
-
|
|
346053
|
-
|
|
346054
|
-
|
|
346055
|
-
|
|
346056
|
-
|
|
346057
|
-
|
|
346058
|
-
|
|
346059
|
-
|
|
346060
|
-
|
|
346061
|
-
|
|
346062
|
-
|
|
346063
|
-
|
|
346064
|
-
|
|
346065
|
-
|
|
346066
|
-
|
|
346067
|
-
|
|
346134
|
+
const flashResult = await this.queryLoopDetectionModel("loop-detection", contents, signal);
|
|
346135
|
+
if (!flashResult) {
|
|
346136
|
+
return false;
|
|
346137
|
+
}
|
|
346138
|
+
const flashConfidence = flashResult["unproductive_state_confidence"];
|
|
346139
|
+
const doubleCheckModelName = this.config.modelConfigService.getResolvedConfig({
|
|
346140
|
+
model: DOUBLE_CHECK_MODEL_ALIAS
|
|
346141
|
+
}).model;
|
|
346142
|
+
if (flashConfidence < LLM_CONFIDENCE_THRESHOLD) {
|
|
346143
|
+
logLlmLoopCheck(this.config, new LlmLoopCheckEvent(this.promptId, flashConfidence, doubleCheckModelName, -1));
|
|
346144
|
+
this.updateCheckInterval(flashConfidence);
|
|
346145
|
+
return false;
|
|
346146
|
+
}
|
|
346147
|
+
if (this.config.isInFallbackMode()) {
|
|
346148
|
+
const flashModelName = this.config.modelConfigService.getResolvedConfig({
|
|
346149
|
+
model: "loop-detection"
|
|
346150
|
+
}).model;
|
|
346151
|
+
this.handleConfirmedLoop(flashResult, flashModelName);
|
|
346152
|
+
return true;
|
|
346153
|
+
}
|
|
346154
|
+
const mainModelResult = await this.queryLoopDetectionModel(DOUBLE_CHECK_MODEL_ALIAS, contents, signal);
|
|
346155
|
+
const mainModelConfidence = mainModelResult ? mainModelResult["unproductive_state_confidence"] : 0;
|
|
346156
|
+
logLlmLoopCheck(this.config, new LlmLoopCheckEvent(this.promptId, flashConfidence, doubleCheckModelName, mainModelConfidence));
|
|
346157
|
+
if (mainModelResult) {
|
|
346158
|
+
if (mainModelConfidence >= LLM_CONFIDENCE_THRESHOLD) {
|
|
346159
|
+
this.handleConfirmedLoop(mainModelResult, doubleCheckModelName);
|
|
346160
|
+
return true;
|
|
346161
|
+
} else {
|
|
346162
|
+
this.updateCheckInterval(mainModelConfidence);
|
|
346163
|
+
}
|
|
346164
|
+
}
|
|
346165
|
+
return false;
|
|
346166
|
+
}
|
|
346167
|
+
async queryLoopDetectionModel(model, contents, signal) {
|
|
346068
346168
|
try {
|
|
346069
|
-
result = await this.config.getBaseLlmClient().generateJson({
|
|
346070
|
-
modelConfigKey: { model
|
|
346169
|
+
const result = await this.config.getBaseLlmClient().generateJson({
|
|
346170
|
+
modelConfigKey: { model },
|
|
346071
346171
|
contents,
|
|
346072
|
-
schema,
|
|
346172
|
+
schema: LOOP_DETECTION_SCHEMA,
|
|
346073
346173
|
systemInstruction: LOOP_DETECTION_SYSTEM_PROMPT,
|
|
346074
346174
|
abortSignal: signal,
|
|
346075
|
-
promptId: this.promptId
|
|
346175
|
+
promptId: this.promptId,
|
|
346176
|
+
maxAttempts: 2
|
|
346076
346177
|
});
|
|
346178
|
+
if (result && typeof result["unproductive_state_confidence"] === "number") {
|
|
346179
|
+
return result;
|
|
346180
|
+
}
|
|
346181
|
+
return null;
|
|
346077
346182
|
} catch (e2) {
|
|
346078
346183
|
this.config.getDebugMode() ? debugLogger.warn(e2) : debugLogger.debug(e2);
|
|
346079
|
-
return
|
|
346184
|
+
return null;
|
|
346080
346185
|
}
|
|
346081
|
-
|
|
346082
|
-
|
|
346083
|
-
|
|
346084
|
-
|
|
346085
|
-
}
|
|
346086
|
-
logLoopDetected(this.config, new LoopDetectedEvent(LoopType.LLM_DETECTED_LOOP, this.promptId));
|
|
346087
|
-
return true;
|
|
346088
|
-
} else {
|
|
346089
|
-
this.llmCheckInterval = Math.round(MIN_LLM_CHECK_INTERVAL + (MAX_LLM_CHECK_INTERVAL - MIN_LLM_CHECK_INTERVAL) * (1 - result["unproductive_state_confidence"]));
|
|
346090
|
-
}
|
|
346186
|
+
}
|
|
346187
|
+
handleConfirmedLoop(result, modelName) {
|
|
346188
|
+
if (typeof result["unproductive_state_analysis"] === "string" && result["unproductive_state_analysis"]) {
|
|
346189
|
+
debugLogger.warn(result["unproductive_state_analysis"]);
|
|
346091
346190
|
}
|
|
346092
|
-
|
|
346191
|
+
logLoopDetected(this.config, new LoopDetectedEvent(LoopType.LLM_DETECTED_LOOP, this.promptId, modelName));
|
|
346192
|
+
}
|
|
346193
|
+
updateCheckInterval(unproductive_state_confidence) {
|
|
346194
|
+
this.llmCheckInterval = Math.round(MIN_LLM_CHECK_INTERVAL + (MAX_LLM_CHECK_INTERVAL - MIN_LLM_CHECK_INTERVAL) * (1 - unproductive_state_confidence));
|
|
346093
346195
|
}
|
|
346094
346196
|
/**
|
|
346095
346197
|
* Resets all loop detection state.
|
|
@@ -352154,6 +352256,12 @@ var DEFAULT_MODEL_CONFIGS = {
|
|
|
352154
352256
|
extends: "gemini-2.5-flash-base",
|
|
352155
352257
|
modelConfig: {}
|
|
352156
352258
|
},
|
|
352259
|
+
"loop-detection-double-check": {
|
|
352260
|
+
extends: "base",
|
|
352261
|
+
modelConfig: {
|
|
352262
|
+
model: "gemini-2.5-pro"
|
|
352263
|
+
}
|
|
352264
|
+
},
|
|
352157
352265
|
"llm-edit-fixer": {
|
|
352158
352266
|
extends: "gemini-2.5-flash-base",
|
|
352159
352267
|
modelConfig: {}
|
|
@@ -352334,7 +352442,7 @@ var MessageBus = class extends EventEmitter10 {
|
|
|
352334
352442
|
emitMessage(message) {
|
|
352335
352443
|
this.emit(message.type, message);
|
|
352336
352444
|
}
|
|
352337
|
-
publish(message) {
|
|
352445
|
+
async publish(message) {
|
|
352338
352446
|
if (this.debug) {
|
|
352339
352447
|
console.debug(`[MESSAGE_BUS] publish: ${safeJsonStringify(message)}`);
|
|
352340
352448
|
}
|
|
@@ -352343,7 +352451,7 @@ var MessageBus = class extends EventEmitter10 {
|
|
|
352343
352451
|
throw new Error(`Invalid message structure: ${safeJsonStringify(message)}`);
|
|
352344
352452
|
}
|
|
352345
352453
|
if (message.type === MessageBusType.TOOL_CONFIRMATION_REQUEST) {
|
|
352346
|
-
const decision = this.policyEngine.check(message.toolCall, message.serverName);
|
|
352454
|
+
const { decision } = await this.policyEngine.check(message.toolCall, message.serverName);
|
|
352347
352455
|
switch (decision) {
|
|
352348
352456
|
case PolicyDecision.ALLOW:
|
|
352349
352457
|
this.emitMessage({
|
|
@@ -352440,6 +352548,14 @@ function stableStringify(obj) {
|
|
|
352440
352548
|
return stringify5(obj, /* @__PURE__ */ new Set());
|
|
352441
352549
|
}
|
|
352442
352550
|
|
|
352551
|
+
// packages/core/dist/src/safety/protocol.js
|
|
352552
|
+
var SafetyCheckDecision;
|
|
352553
|
+
(function(SafetyCheckDecision2) {
|
|
352554
|
+
SafetyCheckDecision2["ALLOW"] = "allow";
|
|
352555
|
+
SafetyCheckDecision2["DENY"] = "deny";
|
|
352556
|
+
SafetyCheckDecision2["ASK_USER"] = "ask_user";
|
|
352557
|
+
})(SafetyCheckDecision || (SafetyCheckDecision = {}));
|
|
352558
|
+
|
|
352443
352559
|
// packages/core/dist/src/policy/policy-engine.js
|
|
352444
352560
|
function ruleMatches(rule, toolCall, stringifiedArgs, serverName) {
|
|
352445
352561
|
if (rule.toolName) {
|
|
@@ -352469,30 +352585,71 @@ function ruleMatches(rule, toolCall, stringifiedArgs, serverName) {
|
|
|
352469
352585
|
}
|
|
352470
352586
|
var PolicyEngine = class {
|
|
352471
352587
|
rules;
|
|
352588
|
+
checkers;
|
|
352472
352589
|
defaultDecision;
|
|
352473
352590
|
nonInteractive;
|
|
352474
|
-
|
|
352591
|
+
checkerRunner;
|
|
352592
|
+
constructor(config2 = {}, checkerRunner) {
|
|
352475
352593
|
this.rules = (config2.rules ?? []).sort((a2, b) => (b.priority ?? 0) - (a2.priority ?? 0));
|
|
352594
|
+
this.checkers = (config2.checkers ?? []).sort((a2, b) => (b.priority ?? 0) - (a2.priority ?? 0));
|
|
352476
352595
|
this.defaultDecision = config2.defaultDecision ?? PolicyDecision.ASK_USER;
|
|
352477
352596
|
this.nonInteractive = config2.nonInteractive ?? false;
|
|
352597
|
+
this.checkerRunner = checkerRunner;
|
|
352478
352598
|
}
|
|
352479
352599
|
/**
|
|
352480
352600
|
* Check if a tool call is allowed based on the configured policies.
|
|
352601
|
+
* Returns the decision and the matching rule (if any).
|
|
352481
352602
|
*/
|
|
352482
|
-
check(toolCall, serverName) {
|
|
352603
|
+
async check(toolCall, serverName) {
|
|
352483
352604
|
let stringifiedArgs;
|
|
352484
|
-
if (toolCall.args && this.rules.some((rule) => rule.argsPattern)) {
|
|
352605
|
+
if (toolCall.args && (this.rules.some((rule) => rule.argsPattern) || this.checkers.some((checker) => checker.argsPattern))) {
|
|
352485
352606
|
stringifiedArgs = stableStringify(toolCall.args);
|
|
352486
352607
|
}
|
|
352487
352608
|
debugLogger.debug(`[PolicyEngine.check] toolCall.name: ${toolCall.name}, stringifiedArgs: ${stringifiedArgs}`);
|
|
352609
|
+
let matchedRule;
|
|
352610
|
+
let decision;
|
|
352488
352611
|
for (const rule of this.rules) {
|
|
352489
352612
|
if (ruleMatches(rule, toolCall, stringifiedArgs, serverName)) {
|
|
352490
352613
|
debugLogger.debug(`[PolicyEngine.check] MATCHED rule: toolName=${rule.toolName}, decision=${rule.decision}, priority=${rule.priority}, argsPattern=${rule.argsPattern?.source || "none"}`);
|
|
352491
|
-
|
|
352614
|
+
matchedRule = rule;
|
|
352615
|
+
decision = this.applyNonInteractiveMode(rule.decision);
|
|
352616
|
+
break;
|
|
352492
352617
|
}
|
|
352493
352618
|
}
|
|
352494
|
-
|
|
352495
|
-
|
|
352619
|
+
if (!decision) {
|
|
352620
|
+
debugLogger.debug(`[PolicyEngine.check] NO MATCH - using default decision: ${this.defaultDecision}`);
|
|
352621
|
+
decision = this.applyNonInteractiveMode(this.defaultDecision);
|
|
352622
|
+
}
|
|
352623
|
+
if (decision !== PolicyDecision.DENY && this.checkerRunner) {
|
|
352624
|
+
for (const checkerRule of this.checkers) {
|
|
352625
|
+
if (ruleMatches(checkerRule, toolCall, stringifiedArgs, serverName)) {
|
|
352626
|
+
debugLogger.debug(`[PolicyEngine.check] Running safety checker: ${checkerRule.checker.name}`);
|
|
352627
|
+
try {
|
|
352628
|
+
const result = await this.checkerRunner.runChecker(toolCall, checkerRule.checker);
|
|
352629
|
+
if (result.decision === SafetyCheckDecision.DENY) {
|
|
352630
|
+
debugLogger.debug(`[PolicyEngine.check] Safety checker denied: ${result.reason}`);
|
|
352631
|
+
return {
|
|
352632
|
+
decision: PolicyDecision.DENY,
|
|
352633
|
+
rule: matchedRule
|
|
352634
|
+
};
|
|
352635
|
+
} else if (result.decision === SafetyCheckDecision.ASK_USER) {
|
|
352636
|
+
debugLogger.debug(`[PolicyEngine.check] Safety checker requested ASK_USER: ${result.reason}`);
|
|
352637
|
+
decision = PolicyDecision.ASK_USER;
|
|
352638
|
+
}
|
|
352639
|
+
} catch (error) {
|
|
352640
|
+
debugLogger.debug(`[PolicyEngine.check] Safety checker failed: ${error}`);
|
|
352641
|
+
return {
|
|
352642
|
+
decision: PolicyDecision.DENY,
|
|
352643
|
+
rule: matchedRule
|
|
352644
|
+
};
|
|
352645
|
+
}
|
|
352646
|
+
}
|
|
352647
|
+
}
|
|
352648
|
+
}
|
|
352649
|
+
return {
|
|
352650
|
+
decision: this.applyNonInteractiveMode(decision),
|
|
352651
|
+
rule: matchedRule
|
|
352652
|
+
};
|
|
352496
352653
|
}
|
|
352497
352654
|
/**
|
|
352498
352655
|
* Add a new rule to the policy engine.
|
|
@@ -352501,6 +352658,10 @@ var PolicyEngine = class {
|
|
|
352501
352658
|
this.rules.push(rule);
|
|
352502
352659
|
this.rules.sort((a2, b) => (b.priority ?? 0) - (a2.priority ?? 0));
|
|
352503
352660
|
}
|
|
352661
|
+
addChecker(checker) {
|
|
352662
|
+
this.checkers.push(checker);
|
|
352663
|
+
this.checkers.sort((a2, b) => (b.priority ?? 0) - (a2.priority ?? 0));
|
|
352664
|
+
}
|
|
352504
352665
|
/**
|
|
352505
352666
|
* Remove rules for a specific tool.
|
|
352506
352667
|
*/
|
|
@@ -352513,6 +352674,9 @@ var PolicyEngine = class {
|
|
|
352513
352674
|
getRules() {
|
|
352514
352675
|
return this.rules;
|
|
352515
352676
|
}
|
|
352677
|
+
getCheckers() {
|
|
352678
|
+
return this.checkers;
|
|
352679
|
+
}
|
|
352516
352680
|
applyNonInteractiveMode(decision) {
|
|
352517
352681
|
if (this.nonInteractive && decision === PolicyDecision.ASK_USER) {
|
|
352518
352682
|
return PolicyDecision.DENY;
|
|
@@ -355005,8 +355169,9 @@ function getPlatform() {
|
|
|
355005
355169
|
async function getClientMetadata() {
|
|
355006
355170
|
if (!clientMetadataPromise) {
|
|
355007
355171
|
clientMetadataPromise = (async () => ({
|
|
355008
|
-
ideName: "
|
|
355009
|
-
|
|
355172
|
+
ideName: "IDE_UNSPECIFIED",
|
|
355173
|
+
pluginType: "GEMINI",
|
|
355174
|
+
ideVersion: "0.16.0-nightly.20251113.ad1f0d99",
|
|
355010
355175
|
platform: getPlatform(),
|
|
355011
355176
|
updateChannel: await getReleaseChannel(__dirname5)
|
|
355012
355177
|
}))();
|
|
@@ -361345,8 +361510,32 @@ var PolicyRuleSchema = external_exports.object({
|
|
|
361345
361510
|
}),
|
|
361346
361511
|
modes: external_exports.array(external_exports.string()).optional()
|
|
361347
361512
|
});
|
|
361513
|
+
var SafetyCheckerRuleSchema = external_exports.object({
|
|
361514
|
+
toolName: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).optional(),
|
|
361515
|
+
mcpName: external_exports.string().optional(),
|
|
361516
|
+
argsPattern: external_exports.string().optional(),
|
|
361517
|
+
commandPrefix: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).optional(),
|
|
361518
|
+
commandRegex: external_exports.string().optional(),
|
|
361519
|
+
priority: external_exports.number().int().default(0),
|
|
361520
|
+
modes: external_exports.array(external_exports.string()).optional(),
|
|
361521
|
+
checker: external_exports.discriminatedUnion("type", [
|
|
361522
|
+
external_exports.object({
|
|
361523
|
+
type: external_exports.literal("in-process"),
|
|
361524
|
+
name: external_exports.nativeEnum(InProcessCheckerType),
|
|
361525
|
+
required_context: external_exports.array(external_exports.string()).optional(),
|
|
361526
|
+
config: external_exports.record(external_exports.unknown()).optional()
|
|
361527
|
+
}),
|
|
361528
|
+
external_exports.object({
|
|
361529
|
+
type: external_exports.literal("external"),
|
|
361530
|
+
name: external_exports.string(),
|
|
361531
|
+
required_context: external_exports.array(external_exports.string()).optional(),
|
|
361532
|
+
config: external_exports.record(external_exports.unknown()).optional()
|
|
361533
|
+
})
|
|
361534
|
+
])
|
|
361535
|
+
});
|
|
361348
361536
|
var PolicyFileSchema = external_exports.object({
|
|
361349
|
-
rule: external_exports.array(PolicyRuleSchema)
|
|
361537
|
+
rule: external_exports.array(PolicyRuleSchema).optional(),
|
|
361538
|
+
safety_checker: external_exports.array(SafetyCheckerRuleSchema).optional()
|
|
361350
361539
|
});
|
|
361351
361540
|
|
|
361352
361541
|
// packages/core/dist/src/policy/config.js
|