feat: full implementation for .geminiignore in settings and respective tool calls (#3727)

This commit is contained in:
Pyush Sinha
2025-07-20 00:55:33 -07:00
committed by GitHub
parent 76b935d598
commit a01b1219a3
19 changed files with 803 additions and 116 deletions

View File

@@ -17,7 +17,7 @@ import {
getSpecificMimeType,
} from '../utils/fileUtils.js';
import { PartListUnion, Schema, Type } from '@google/genai';
import { Config } from '../config/config.js';
import { Config, DEFAULT_FILE_FILTERING_OPTIONS } from '../config/config.js';
import {
recordFileOperationMetric,
FileOperation,
@@ -62,9 +62,12 @@ export interface ReadManyFilesParams {
useDefaultExcludes?: boolean;
/**
* Optional. Whether to respect .gitignore patterns. Defaults to true.
* Whether to respect .gitignore and .geminiignore patterns (optional, defaults to true)
*/
respect_git_ignore?: boolean;
file_filtering_options?: {
respect_git_ignore?: boolean;
respect_gemini_ignore?: boolean;
};
}
/**
@@ -173,11 +176,22 @@ export class ReadManyFilesTool extends BaseTool<
'Optional. Whether to apply a list of default exclusion patterns (e.g., node_modules, .git, binary files). Defaults to true.',
default: true,
},
respect_git_ignore: {
type: Type.BOOLEAN,
file_filtering_options: {
description:
'Optional. Whether to respect .gitignore patterns when discovering files. Only available in git repositories. Defaults to true.',
default: true,
'Whether to respect ignore patterns from .gitignore or .geminiignore',
type: Type.OBJECT,
properties: {
respect_git_ignore: {
description:
'Optional: Whether to respect .gitignore patterns when listing files. Only available in git repositories. Defaults to true.',
type: Type.BOOLEAN,
},
respect_gemini_ignore: {
description:
'Optional: Whether to respect .geminiignore patterns when listing files. Defaults to true.',
type: Type.BOOLEAN,
},
},
},
},
required: ['paths'],
@@ -257,12 +271,19 @@ Use this tool when the user's query implies needing the content of several files
include = [],
exclude = [],
useDefaultExcludes = true,
respect_git_ignore = true,
} = params;
const respectGitIgnore =
respect_git_ignore ?? this.config.getFileFilteringRespectGitIgnore();
const defaultFileIgnores =
this.config.getFileFilteringOptions() ?? DEFAULT_FILE_FILTERING_OPTIONS;
const fileFilteringOptions = {
respectGitIgnore:
params.file_filtering_options?.respect_git_ignore ??
defaultFileIgnores.respectGitIgnore, // Use the property from the returned object
respectGeminiIgnore:
params.file_filtering_options?.respect_gemini_ignore ??
defaultFileIgnores.respectGeminiIgnore, // Use the property from the returned object
};
// Get centralized file discovery service
const fileDiscovery = this.config.getFileService();
@@ -272,8 +293,8 @@ Use this tool when the user's query implies needing the content of several files
const contentParts: PartListUnion = [];
const effectiveExcludes = useDefaultExcludes
? [...DEFAULT_EXCLUDES, ...exclude, ...this.geminiIgnorePatterns]
: [...exclude, ...this.geminiIgnorePatterns];
? [...DEFAULT_EXCLUDES, ...exclude]
: [...exclude];
const searchPatterns = [...inputPatterns, ...include];
if (searchPatterns.length === 0) {
@@ -294,18 +315,36 @@ Use this tool when the user's query implies needing the content of several files
signal,
});
const filteredEntries = respectGitIgnore
const gitFilteredEntries = fileFilteringOptions.respectGitIgnore
? fileDiscovery
.filterFiles(
entries.map((p) => path.relative(this.config.getTargetDir(), p)),
{
respectGitIgnore,
respectGitIgnore: true,
respectGeminiIgnore: false,
},
)
.map((p) => path.resolve(this.config.getTargetDir(), p))
: entries;
// Apply gemini ignore filtering if enabled
const finalFilteredEntries = fileFilteringOptions.respectGeminiIgnore
? fileDiscovery
.filterFiles(
gitFilteredEntries.map((p) =>
path.relative(this.config.getTargetDir(), p),
),
{
respectGitIgnore: false,
respectGeminiIgnore: true,
},
)
.map((p) => path.resolve(this.config.getTargetDir(), p))
: gitFilteredEntries;
let gitIgnoredCount = 0;
let geminiIgnoredCount = 0;
for (const absoluteFilePath of entries) {
// Security check: ensure the glob library didn't return something outside targetDir.
if (!absoluteFilePath.startsWith(this.config.getTargetDir())) {
@@ -317,11 +356,23 @@ Use this tool when the user's query implies needing the content of several files
}
// Check if this file was filtered out by git ignore
if (respectGitIgnore && !filteredEntries.includes(absoluteFilePath)) {
if (
fileFilteringOptions.respectGitIgnore &&
!gitFilteredEntries.includes(absoluteFilePath)
) {
gitIgnoredCount++;
continue;
}
// Check if this file was filtered out by gemini ignore
if (
fileFilteringOptions.respectGeminiIgnore &&
!finalFilteredEntries.includes(absoluteFilePath)
) {
geminiIgnoredCount++;
continue;
}
filesToConsider.add(absoluteFilePath);
}
@@ -329,7 +380,15 @@ Use this tool when the user's query implies needing the content of several files
if (gitIgnoredCount > 0) {
skippedFiles.push({
path: `${gitIgnoredCount} file(s)`,
reason: 'ignored',
reason: 'git ignored',
});
}
// Add info about gemini-ignored files if any were filtered
if (geminiIgnoredCount > 0) {
skippedFiles.push({
path: `${geminiIgnoredCount} file(s)`,
reason: 'gemini ignored',
});
}
} catch (error) {