@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.
@@ -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
- constructor(loop_type, prompt_id) {
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
- return {
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 = "605d9167";
295903
- var CLI_VERSION = "0.15.0-preview.3";
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.15.0-preview.3";
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, "Save Memory", memoryToolDescription, Kind.Think, memoryToolSchemaData.parametersJsonSchema, true, false, messageBus);
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 workspaceContext = this.config.getWorkspaceContext();
320655
- const searchDirAbs = this.resolveAndValidatePath(this.params.dir_path);
320656
- const searchDirDisplay = this.params.dir_path || ".";
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
- for (const searchDir of searchDirectories) {
320669
- const searchResult = await this.performRipgrepSearch({
320670
- pattern: this.params.pattern,
320671
- path: searchDir,
320672
- include: this.params.include,
320673
- signal
320674
- });
320675
- if (searchDirectories.length > 1) {
320676
- const dirName = path33.basename(searchDir);
320677
- searchResult.forEach((match2) => {
320678
- match2.filePath = path33.join(dirName, match2.filePath);
320679
- });
320680
- }
320681
- allMatches = allMatches.concat(searchResult);
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", "--ignore-case", "--regexp", pattern];
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
- const excludes = [
320779
- ".git",
320780
- "node_modules",
320781
- "bower_components",
320782
- "*.log",
320783
- "*.tmp",
320784
- "build",
320785
- "dist",
320786
- "coverage"
320787
- ];
320788
- excludes.forEach((exclude) => {
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
- if (this.params.dir_path) {
320843
- const resolvedPath = path33.resolve(this.config.getTargetDir(), this.params.dir_path);
320844
- if (resolvedPath === this.config.getTargetDir() || this.params.dir_path === ".") {
320845
- description += ` within ./`;
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 workspaceContext = this.config.getWorkspaceContext();
320852
- const directories = workspaceContext.getDirectories();
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
- "Searches for a regular expression pattern within the content of files in a specified directory (or current working directory). Can filter files by a glob pattern. Returns the lines containing matches, along with their file paths and line numbers. Total results limited to 20,000 matches like VSCode.",
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 regular expression (regex) pattern to search for within file contents (e.g., 'function\\s+myFunction', 'import\\s+\\{.*\\}\\s+from\\s+.*').",
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: "Optional: The absolute path to the directory to search within. If omitted, searches the current working directory.",
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: "Optional: A glob pattern to filter which files are searched (e.g., '*.js', '*.{ts,tsx}', 'src/**'). If omitted, searches all files (respecting potential global ignores).",
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.resolveAndValidatePath(params.dir_path);
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, "Write Todos", WRITE_TODOS_DESCRIPTION, Kind.Other, {
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 schema = {
346051
- type: "object",
346052
- properties: {
346053
- unproductive_state_analysis: {
346054
- type: "string",
346055
- description: "Your reasoning on if the conversation is looping without forward progress."
346056
- },
346057
- unproductive_state_confidence: {
346058
- type: "number",
346059
- description: "A number between 0.0 and 1.0 representing your confidence that the conversation is in an unproductive state."
346060
- }
346061
- },
346062
- required: [
346063
- "unproductive_state_analysis",
346064
- "unproductive_state_confidence"
346065
- ]
346066
- };
346067
- let result;
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: "loop-detection" },
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 false;
346184
+ return null;
346080
346185
  }
346081
- if (typeof result["unproductive_state_confidence"] === "number") {
346082
- if (result["unproductive_state_confidence"] > 0.9) {
346083
- if (typeof result["unproductive_state_analysis"] === "string" && result["unproductive_state_analysis"]) {
346084
- debugLogger.warn(result["unproductive_state_analysis"]);
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
- return false;
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
- constructor(config2 = {}) {
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
- return this.applyNonInteractiveMode(rule.decision);
352614
+ matchedRule = rule;
352615
+ decision = this.applyNonInteractiveMode(rule.decision);
352616
+ break;
352492
352617
  }
352493
352618
  }
352494
- debugLogger.debug(`[PolicyEngine.check] NO MATCH - using default decision: ${this.defaultDecision}`);
352495
- return this.applyNonInteractiveMode(this.defaultDecision);
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: "GEMINI_CLI",
355009
- ideVersion: "0.15.0-preview.3",
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