@google/gemini-cli-a2a-server 0.15.0-preview.0 → 0.16.0-nightly.20251112.c961f274

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 = "2abc288c";
295903
- var CLI_VERSION = "0.15.0-preview.0";
295941
+ var GIT_COMMIT_INFO = "c961f274";
295942
+ var CLI_VERSION = "0.16.0-nightly.20251112.c961f274";
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.0";
298787
+ const version3 = "0.16.0-nightly.20251112.c961f274";
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
  }
@@ -345309,7 +345373,7 @@ ${todoListString}` : "Successfully cleared the todo list.";
345309
345373
  var WriteTodosTool = class _WriteTodosTool extends BaseDeclarativeTool {
345310
345374
  static Name = WRITE_TODOS_TOOL_NAME;
345311
345375
  constructor() {
345312
- super(_WriteTodosTool.Name, "Write Todos", WRITE_TODOS_DESCRIPTION, Kind.Other, {
345376
+ super(_WriteTodosTool.Name, "WriteTodos", WRITE_TODOS_DESCRIPTION, Kind.Other, {
345313
345377
  type: "object",
345314
345378
  properties: {
345315
345379
  todos: {
@@ -345777,6 +345841,8 @@ var LLM_CHECK_AFTER_TURNS = 30;
345777
345841
  var DEFAULT_LLM_CHECK_INTERVAL = 3;
345778
345842
  var MIN_LLM_CHECK_INTERVAL = 5;
345779
345843
  var MAX_LLM_CHECK_INTERVAL = 15;
345844
+ var LLM_CONFIDENCE_THRESHOLD = 0.9;
345845
+ var DOUBLE_CHECK_MODEL_ALIAS = "loop-detection-double-check";
345780
345846
  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.
345781
345847
 
345782
345848
  An unproductive state is characterized by one or more of the following patterns over the last 5 or more assistant turns:
@@ -345787,6 +345853,20 @@ Cognitive Loop: The assistant seems unable to determine the next logical step. I
345787
345853
 
345788
345854
  Crucially, differentiate between a true unproductive state and legitimate, incremental progress.
345789
345855
  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.`;
345856
+ var LOOP_DETECTION_SCHEMA = {
345857
+ type: "object",
345858
+ properties: {
345859
+ unproductive_state_analysis: {
345860
+ type: "string",
345861
+ description: "Your reasoning on if the conversation is looping without forward progress."
345862
+ },
345863
+ unproductive_state_confidence: {
345864
+ type: "number",
345865
+ description: "A number between 0.0 and 1.0 representing your confidence that the conversation is in an unproductive state."
345866
+ }
345867
+ },
345868
+ required: ["unproductive_state_analysis", "unproductive_state_confidence"]
345869
+ };
345790
345870
  var LoopDetectionService = class {
345791
345871
  config;
345792
345872
  promptId = "";
@@ -346014,49 +346094,67 @@ var LoopDetectionService = class {
346014
346094
  parts: [{ text: "Recent conversation history:" }]
346015
346095
  });
346016
346096
  }
346017
- const schema = {
346018
- type: "object",
346019
- properties: {
346020
- unproductive_state_analysis: {
346021
- type: "string",
346022
- description: "Your reasoning on if the conversation is looping without forward progress."
346023
- },
346024
- unproductive_state_confidence: {
346025
- type: "number",
346026
- description: "A number between 0.0 and 1.0 representing your confidence that the conversation is in an unproductive state."
346027
- }
346028
- },
346029
- required: [
346030
- "unproductive_state_analysis",
346031
- "unproductive_state_confidence"
346032
- ]
346033
- };
346034
- let result;
346097
+ const flashResult = await this.queryLoopDetectionModel("loop-detection", contents, signal);
346098
+ if (!flashResult) {
346099
+ return false;
346100
+ }
346101
+ const flashConfidence = flashResult["unproductive_state_confidence"];
346102
+ const doubleCheckModelName = this.config.modelConfigService.getResolvedConfig({
346103
+ model: DOUBLE_CHECK_MODEL_ALIAS
346104
+ }).model;
346105
+ if (flashConfidence < LLM_CONFIDENCE_THRESHOLD) {
346106
+ logLlmLoopCheck(this.config, new LlmLoopCheckEvent(this.promptId, flashConfidence, doubleCheckModelName, -1));
346107
+ this.updateCheckInterval(flashConfidence);
346108
+ return false;
346109
+ }
346110
+ if (this.config.isInFallbackMode()) {
346111
+ const flashModelName = this.config.modelConfigService.getResolvedConfig({
346112
+ model: "loop-detection"
346113
+ }).model;
346114
+ this.handleConfirmedLoop(flashResult, flashModelName);
346115
+ return true;
346116
+ }
346117
+ const mainModelResult = await this.queryLoopDetectionModel(DOUBLE_CHECK_MODEL_ALIAS, contents, signal);
346118
+ const mainModelConfidence = mainModelResult ? mainModelResult["unproductive_state_confidence"] : 0;
346119
+ logLlmLoopCheck(this.config, new LlmLoopCheckEvent(this.promptId, flashConfidence, doubleCheckModelName, mainModelConfidence));
346120
+ if (mainModelResult) {
346121
+ if (mainModelConfidence >= LLM_CONFIDENCE_THRESHOLD) {
346122
+ this.handleConfirmedLoop(mainModelResult, doubleCheckModelName);
346123
+ return true;
346124
+ } else {
346125
+ this.updateCheckInterval(mainModelConfidence);
346126
+ }
346127
+ }
346128
+ return false;
346129
+ }
346130
+ async queryLoopDetectionModel(model, contents, signal) {
346035
346131
  try {
346036
- result = await this.config.getBaseLlmClient().generateJson({
346037
- modelConfigKey: { model: "loop-detection" },
346132
+ const result = await this.config.getBaseLlmClient().generateJson({
346133
+ modelConfigKey: { model },
346038
346134
  contents,
346039
- schema,
346135
+ schema: LOOP_DETECTION_SCHEMA,
346040
346136
  systemInstruction: LOOP_DETECTION_SYSTEM_PROMPT,
346041
346137
  abortSignal: signal,
346042
- promptId: this.promptId
346138
+ promptId: this.promptId,
346139
+ maxAttempts: 2
346043
346140
  });
346141
+ if (result && typeof result["unproductive_state_confidence"] === "number") {
346142
+ return result;
346143
+ }
346144
+ return null;
346044
346145
  } catch (e2) {
346045
346146
  this.config.getDebugMode() ? debugLogger.warn(e2) : debugLogger.debug(e2);
346046
- return false;
346147
+ return null;
346047
346148
  }
346048
- if (typeof result["unproductive_state_confidence"] === "number") {
346049
- if (result["unproductive_state_confidence"] > 0.9) {
346050
- if (typeof result["unproductive_state_analysis"] === "string" && result["unproductive_state_analysis"]) {
346051
- debugLogger.warn(result["unproductive_state_analysis"]);
346052
- }
346053
- logLoopDetected(this.config, new LoopDetectedEvent(LoopType.LLM_DETECTED_LOOP, this.promptId));
346054
- return true;
346055
- } else {
346056
- this.llmCheckInterval = Math.round(MIN_LLM_CHECK_INTERVAL + (MAX_LLM_CHECK_INTERVAL - MIN_LLM_CHECK_INTERVAL) * (1 - result["unproductive_state_confidence"]));
346057
- }
346149
+ }
346150
+ handleConfirmedLoop(result, modelName) {
346151
+ if (typeof result["unproductive_state_analysis"] === "string" && result["unproductive_state_analysis"]) {
346152
+ debugLogger.warn(result["unproductive_state_analysis"]);
346058
346153
  }
346059
- return false;
346154
+ logLoopDetected(this.config, new LoopDetectedEvent(LoopType.LLM_DETECTED_LOOP, this.promptId, modelName));
346155
+ }
346156
+ updateCheckInterval(unproductive_state_confidence) {
346157
+ this.llmCheckInterval = Math.round(MIN_LLM_CHECK_INTERVAL + (MAX_LLM_CHECK_INTERVAL - MIN_LLM_CHECK_INTERVAL) * (1 - unproductive_state_confidence));
346060
346158
  }
346061
346159
  /**
346062
346160
  * Resets all loop detection state.
@@ -352121,6 +352219,12 @@ var DEFAULT_MODEL_CONFIGS = {
352121
352219
  extends: "gemini-2.5-flash-base",
352122
352220
  modelConfig: {}
352123
352221
  },
352222
+ "loop-detection-double-check": {
352223
+ extends: "base",
352224
+ modelConfig: {
352225
+ model: "gemini-2.5-pro"
352226
+ }
352227
+ },
352124
352228
  "llm-edit-fixer": {
352125
352229
  extends: "gemini-2.5-flash-base",
352126
352230
  modelConfig: {}
@@ -354973,7 +355077,7 @@ async function getClientMetadata() {
354973
355077
  if (!clientMetadataPromise) {
354974
355078
  clientMetadataPromise = (async () => ({
354975
355079
  ideName: "GEMINI_CLI",
354976
- ideVersion: "0.15.0-preview.0",
355080
+ ideVersion: "0.16.0-nightly.20251112.c961f274",
354977
355081
  platform: getPlatform(),
354978
355082
  updateChannel: await getReleaseChannel(__dirname5)
354979
355083
  }))();