feat(memory): make directory search limit on memory discovery configurable with settings.json (#4460)
This commit is contained in:
parent
9d3164621a
commit
d7a304bcff
|
@ -429,7 +429,7 @@ This example demonstrates how you can provide general project context, specific
|
||||||
- Location: The CLI searches for the configured context file in the current working directory and then in each parent directory up to either the project root (identified by a `.git` folder) or your home directory.
|
- Location: The CLI searches for the configured context file in the current working directory and then in each parent directory up to either the project root (identified by a `.git` folder) or your home directory.
|
||||||
- Scope: Provides context relevant to the entire project or a significant portion of it.
|
- Scope: Provides context relevant to the entire project or a significant portion of it.
|
||||||
3. **Sub-directory Context Files (Contextual/Local):**
|
3. **Sub-directory Context Files (Contextual/Local):**
|
||||||
- Location: The CLI also scans for the configured context file in subdirectories _below_ the current working directory (respecting common ignore patterns like `node_modules`, `.git`, etc.).
|
- Location: The CLI also scans for the configured context file in subdirectories _below_ the current working directory (respecting common ignore patterns like `node_modules`, `.git`, etc.). The breadth of this search is limited to 200 directories by default, but can be configured with a `memoryDiscoveryMaxDirs` field in your `settings.json` file.
|
||||||
- Scope: Allows for highly specific instructions relevant to a particular component, module, or subsection of your project.
|
- Scope: Allows for highly specific instructions relevant to a particular component, module, or subsection of your project.
|
||||||
- **Concatenation & UI Indication:** The contents of all found context files are concatenated (with separators indicating their origin and path) and provided as part of the system prompt to the Gemini model. The CLI footer displays the count of loaded context files, giving you a quick visual cue about the active instructional context.
|
- **Concatenation & UI Indication:** The contents of all found context files are concatenated (with separators indicating their origin and path) and provided as part of the system prompt to the Gemini model. The CLI footer displays the count of loaded context files, giving you a quick visual cue about the active instructional context.
|
||||||
- **Commands for Memory Management:**
|
- **Commands for Memory Management:**
|
||||||
|
|
|
@ -37,7 +37,7 @@ vi.mock('@google/gemini-cli-core', async () => {
|
||||||
...actualServer,
|
...actualServer,
|
||||||
loadEnvironment: vi.fn(),
|
loadEnvironment: vi.fn(),
|
||||||
loadServerHierarchicalMemory: vi.fn(
|
loadServerHierarchicalMemory: vi.fn(
|
||||||
(cwd, debug, fileService, extensionPaths) =>
|
(cwd, debug, fileService, extensionPaths, _maxDirs) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
memoryContent: extensionPaths?.join(',') || '',
|
memoryContent: extensionPaths?.join(',') || '',
|
||||||
fileCount: extensionPaths?.length || 0,
|
fileCount: extensionPaths?.length || 0,
|
||||||
|
@ -491,6 +491,7 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
|
||||||
respectGitIgnore: false,
|
respectGitIgnore: false,
|
||||||
respectGeminiIgnore: true,
|
respectGeminiIgnore: true,
|
||||||
},
|
},
|
||||||
|
undefined, // maxDirs
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -225,6 +225,7 @@ export async function loadHierarchicalGeminiMemory(
|
||||||
currentWorkingDirectory: string,
|
currentWorkingDirectory: string,
|
||||||
debugMode: boolean,
|
debugMode: boolean,
|
||||||
fileService: FileDiscoveryService,
|
fileService: FileDiscoveryService,
|
||||||
|
settings: Settings,
|
||||||
extensionContextFilePaths: string[] = [],
|
extensionContextFilePaths: string[] = [],
|
||||||
fileFilteringOptions?: FileFilteringOptions,
|
fileFilteringOptions?: FileFilteringOptions,
|
||||||
): Promise<{ memoryContent: string; fileCount: number }> {
|
): Promise<{ memoryContent: string; fileCount: number }> {
|
||||||
|
@ -242,6 +243,7 @@ export async function loadHierarchicalGeminiMemory(
|
||||||
fileService,
|
fileService,
|
||||||
extensionContextFilePaths,
|
extensionContextFilePaths,
|
||||||
fileFilteringOptions,
|
fileFilteringOptions,
|
||||||
|
settings.memoryDiscoveryMaxDirs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,6 +300,7 @@ export async function loadCliConfig(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
debugMode,
|
debugMode,
|
||||||
fileService,
|
fileService,
|
||||||
|
settings,
|
||||||
extensionContextFilePaths,
|
extensionContextFilePaths,
|
||||||
fileFiltering,
|
fileFiltering,
|
||||||
);
|
);
|
||||||
|
|
|
@ -100,6 +100,7 @@ export interface Settings {
|
||||||
|
|
||||||
// Add other settings here.
|
// Add other settings here.
|
||||||
ideMode?: boolean;
|
ideMode?: boolean;
|
||||||
|
memoryDiscoveryMaxDirs?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SettingsError {
|
export interface SettingsError {
|
||||||
|
|
|
@ -236,6 +236,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
config.getDebugMode(),
|
config.getDebugMode(),
|
||||||
config.getFileService(),
|
config.getFileService(),
|
||||||
|
settings.merged,
|
||||||
config.getExtensionContextFilePaths(),
|
config.getExtensionContextFilePaths(),
|
||||||
config.getFileFilteringOptions(),
|
config.getFileFilteringOptions(),
|
||||||
);
|
);
|
||||||
|
@ -267,7 +268,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
);
|
);
|
||||||
console.error('Error refreshing memory:', error);
|
console.error('Error refreshing memory:', error);
|
||||||
}
|
}
|
||||||
}, [config, addItem]);
|
}, [config, addItem, settings.merged]);
|
||||||
|
|
||||||
// Watch for model changes (e.g., from Flash fallback)
|
// Watch for model changes (e.g., from Flash fallback)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -9,7 +9,12 @@ import { memoryCommand } from './memoryCommand.js';
|
||||||
import { type CommandContext, SlashCommand } from './types.js';
|
import { type CommandContext, SlashCommand } from './types.js';
|
||||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||||
import { MessageType } from '../types.js';
|
import { MessageType } from '../types.js';
|
||||||
import { getErrorMessage } from '@google/gemini-cli-core';
|
import { LoadedSettings } from '../../config/settings.js';
|
||||||
|
import {
|
||||||
|
getErrorMessage,
|
||||||
|
loadServerHierarchicalMemory,
|
||||||
|
type FileDiscoveryService,
|
||||||
|
} from '@google/gemini-cli-core';
|
||||||
|
|
||||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||||
const original =
|
const original =
|
||||||
|
@ -20,9 +25,12 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||||
if (error instanceof Error) return error.message;
|
if (error instanceof Error) return error.message;
|
||||||
return String(error);
|
return String(error);
|
||||||
}),
|
}),
|
||||||
|
loadServerHierarchicalMemory: vi.fn(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mockLoadServerHierarchicalMemory = loadServerHierarchicalMemory as Mock;
|
||||||
|
|
||||||
describe('memoryCommand', () => {
|
describe('memoryCommand', () => {
|
||||||
let mockContext: CommandContext;
|
let mockContext: CommandContext;
|
||||||
|
|
||||||
|
@ -139,19 +147,37 @@ describe('memoryCommand', () => {
|
||||||
|
|
||||||
describe('/memory refresh', () => {
|
describe('/memory refresh', () => {
|
||||||
let refreshCommand: SlashCommand;
|
let refreshCommand: SlashCommand;
|
||||||
let mockRefreshMemory: Mock;
|
let mockSetUserMemory: Mock;
|
||||||
|
let mockSetGeminiMdFileCount: Mock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
refreshCommand = getSubCommand('refresh');
|
refreshCommand = getSubCommand('refresh');
|
||||||
mockRefreshMemory = vi.fn();
|
mockSetUserMemory = vi.fn();
|
||||||
|
mockSetGeminiMdFileCount = vi.fn();
|
||||||
|
const mockConfig = {
|
||||||
|
setUserMemory: mockSetUserMemory,
|
||||||
|
setGeminiMdFileCount: mockSetGeminiMdFileCount,
|
||||||
|
getWorkingDir: () => '/test/dir',
|
||||||
|
getDebugMode: () => false,
|
||||||
|
getFileService: () => ({}) as FileDiscoveryService,
|
||||||
|
getExtensionContextFilePaths: () => [],
|
||||||
|
getFileFilteringOptions: () => ({
|
||||||
|
ignore: [],
|
||||||
|
include: [],
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
mockContext = createMockCommandContext({
|
mockContext = createMockCommandContext({
|
||||||
services: {
|
services: {
|
||||||
config: {
|
config: Promise.resolve(mockConfig),
|
||||||
refreshMemory: mockRefreshMemory,
|
settings: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
merged: {
|
||||||
} as any,
|
memoryDiscoveryMaxDirs: 1000,
|
||||||
|
},
|
||||||
|
} as LoadedSettings,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
mockLoadServerHierarchicalMemory.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display success message when memory is refreshed with content', async () => {
|
it('should display success message when memory is refreshed with content', async () => {
|
||||||
|
@ -161,7 +187,7 @@ describe('memoryCommand', () => {
|
||||||
memoryContent: 'new memory content',
|
memoryContent: 'new memory content',
|
||||||
fileCount: 2,
|
fileCount: 2,
|
||||||
};
|
};
|
||||||
mockRefreshMemory.mockResolvedValue(refreshResult);
|
mockLoadServerHierarchicalMemory.mockResolvedValue(refreshResult);
|
||||||
|
|
||||||
await refreshCommand.action(mockContext, '');
|
await refreshCommand.action(mockContext, '');
|
||||||
|
|
||||||
|
@ -173,7 +199,13 @@ describe('memoryCommand', () => {
|
||||||
expect.any(Number),
|
expect.any(Number),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mockRefreshMemory).toHaveBeenCalledOnce();
|
expect(loadServerHierarchicalMemory).toHaveBeenCalledOnce();
|
||||||
|
expect(mockSetUserMemory).toHaveBeenCalledWith(
|
||||||
|
refreshResult.memoryContent,
|
||||||
|
);
|
||||||
|
expect(mockSetGeminiMdFileCount).toHaveBeenCalledWith(
|
||||||
|
refreshResult.fileCount,
|
||||||
|
);
|
||||||
|
|
||||||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
|
@ -188,11 +220,13 @@ describe('memoryCommand', () => {
|
||||||
if (!refreshCommand.action) throw new Error('Command has no action');
|
if (!refreshCommand.action) throw new Error('Command has no action');
|
||||||
|
|
||||||
const refreshResult = { memoryContent: '', fileCount: 0 };
|
const refreshResult = { memoryContent: '', fileCount: 0 };
|
||||||
mockRefreshMemory.mockResolvedValue(refreshResult);
|
mockLoadServerHierarchicalMemory.mockResolvedValue(refreshResult);
|
||||||
|
|
||||||
await refreshCommand.action(mockContext, '');
|
await refreshCommand.action(mockContext, '');
|
||||||
|
|
||||||
expect(mockRefreshMemory).toHaveBeenCalledOnce();
|
expect(loadServerHierarchicalMemory).toHaveBeenCalledOnce();
|
||||||
|
expect(mockSetUserMemory).toHaveBeenCalledWith('');
|
||||||
|
expect(mockSetGeminiMdFileCount).toHaveBeenCalledWith(0);
|
||||||
|
|
||||||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
|
@ -207,11 +241,13 @@ describe('memoryCommand', () => {
|
||||||
if (!refreshCommand.action) throw new Error('Command has no action');
|
if (!refreshCommand.action) throw new Error('Command has no action');
|
||||||
|
|
||||||
const error = new Error('Failed to read memory files.');
|
const error = new Error('Failed to read memory files.');
|
||||||
mockRefreshMemory.mockRejectedValue(error);
|
mockLoadServerHierarchicalMemory.mockRejectedValue(error);
|
||||||
|
|
||||||
await refreshCommand.action(mockContext, '');
|
await refreshCommand.action(mockContext, '');
|
||||||
|
|
||||||
expect(mockRefreshMemory).toHaveBeenCalledOnce();
|
expect(loadServerHierarchicalMemory).toHaveBeenCalledOnce();
|
||||||
|
expect(mockSetUserMemory).not.toHaveBeenCalled();
|
||||||
|
expect(mockSetGeminiMdFileCount).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
|
@ -243,7 +279,7 @@ describe('memoryCommand', () => {
|
||||||
expect.any(Number),
|
expect.any(Number),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mockRefreshMemory).not.toHaveBeenCalled();
|
expect(loadServerHierarchicalMemory).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getErrorMessage } from '@google/gemini-cli-core';
|
import {
|
||||||
|
getErrorMessage,
|
||||||
|
loadServerHierarchicalMemory,
|
||||||
|
} from '@google/gemini-cli-core';
|
||||||
import { MessageType } from '../types.js';
|
import { MessageType } from '../types.js';
|
||||||
import {
|
import {
|
||||||
CommandKind,
|
CommandKind,
|
||||||
|
@ -81,10 +84,20 @@ export const memoryCommand: SlashCommand = {
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await context.services.config?.refreshMemory();
|
const config = await context.services.config;
|
||||||
|
if (config) {
|
||||||
|
const { memoryContent, fileCount } =
|
||||||
|
await loadServerHierarchicalMemory(
|
||||||
|
config.getWorkingDir(),
|
||||||
|
config.getDebugMode(),
|
||||||
|
config.getFileService(),
|
||||||
|
config.getExtensionContextFilePaths(),
|
||||||
|
config.getFileFilteringOptions(),
|
||||||
|
context.services.settings.merged.memoryDiscoveryMaxDirs,
|
||||||
|
);
|
||||||
|
config.setUserMemory(memoryContent);
|
||||||
|
config.setGeminiMdFileCount(fileCount);
|
||||||
|
|
||||||
if (result) {
|
|
||||||
const { memoryContent, fileCount } = result;
|
|
||||||
const successMessage =
|
const successMessage =
|
||||||
memoryContent.length > 0
|
memoryContent.length > 0
|
||||||
? `Memory refreshed successfully. Loaded ${memoryContent.length} characters from ${fileCount} file(s).`
|
? `Memory refreshed successfully. Loaded ${memoryContent.length} characters from ${fileCount} file(s).`
|
||||||
|
|
|
@ -18,7 +18,6 @@ import {
|
||||||
} from '../core/contentGenerator.js';
|
} from '../core/contentGenerator.js';
|
||||||
import { GeminiClient } from '../core/client.js';
|
import { GeminiClient } from '../core/client.js';
|
||||||
import { GitService } from '../services/gitService.js';
|
import { GitService } from '../services/gitService.js';
|
||||||
import { loadServerHierarchicalMemory } from '../utils/memoryDiscovery.js';
|
|
||||||
|
|
||||||
// Mock dependencies that might be called during Config construction or createServerConfig
|
// Mock dependencies that might be called during Config construction or createServerConfig
|
||||||
vi.mock('../tools/tool-registry', () => {
|
vi.mock('../tools/tool-registry', () => {
|
||||||
|
@ -313,39 +312,4 @@ describe('Server Config (config.ts)', () => {
|
||||||
expect(config.getTelemetryOtlpEndpoint()).toBe(DEFAULT_OTLP_ENDPOINT);
|
expect(config.getTelemetryOtlpEndpoint()).toBe(DEFAULT_OTLP_ENDPOINT);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('refreshMemory', () => {
|
|
||||||
it('should update memory and file count on successful refresh', async () => {
|
|
||||||
const config = new Config(baseParams);
|
|
||||||
const mockMemoryData = {
|
|
||||||
memoryContent: 'new memory content',
|
|
||||||
fileCount: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
(loadServerHierarchicalMemory as Mock).mockResolvedValue(mockMemoryData);
|
|
||||||
|
|
||||||
const result = await config.refreshMemory();
|
|
||||||
|
|
||||||
expect(loadServerHierarchicalMemory).toHaveBeenCalledWith(
|
|
||||||
config.getWorkingDir(),
|
|
||||||
config.getDebugMode(),
|
|
||||||
config.getFileService(),
|
|
||||||
config.getExtensionContextFilePaths(),
|
|
||||||
config.getFileFilteringOptions(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(config.getUserMemory()).toBe(mockMemoryData.memoryContent);
|
|
||||||
expect(config.getGeminiMdFileCount()).toBe(mockMemoryData.fileCount);
|
|
||||||
expect(result).toEqual(mockMemoryData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should propagate errors from loadServerHierarchicalMemory', async () => {
|
|
||||||
const config = new Config(baseParams);
|
|
||||||
const testError = new Error('Failed to load memory');
|
|
||||||
|
|
||||||
(loadServerHierarchicalMemory as Mock).mockRejectedValue(testError);
|
|
||||||
|
|
||||||
await expect(config.refreshMemory()).rejects.toThrow(testError);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,6 @@ import { WebSearchTool } from '../tools/web-search.js';
|
||||||
import { GeminiClient } from '../core/client.js';
|
import { GeminiClient } from '../core/client.js';
|
||||||
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
||||||
import { GitService } from '../services/gitService.js';
|
import { GitService } from '../services/gitService.js';
|
||||||
import { loadServerHierarchicalMemory } from '../utils/memoryDiscovery.js';
|
|
||||||
import { getProjectTempDir } from '../utils/paths.js';
|
import { getProjectTempDir } from '../utils/paths.js';
|
||||||
import {
|
import {
|
||||||
initializeTelemetry,
|
initializeTelemetry,
|
||||||
|
@ -577,21 +576,6 @@ export class Config {
|
||||||
return this.gitService;
|
return this.gitService;
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshMemory(): Promise<{ memoryContent: string; fileCount: number }> {
|
|
||||||
const { memoryContent, fileCount } = await loadServerHierarchicalMemory(
|
|
||||||
this.getWorkingDir(),
|
|
||||||
this.getDebugMode(),
|
|
||||||
this.getFileService(),
|
|
||||||
this.getExtensionContextFilePaths(),
|
|
||||||
this.getFileFilteringOptions(),
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setUserMemory(memoryContent);
|
|
||||||
this.setGeminiMdFileCount(fileCount);
|
|
||||||
|
|
||||||
return { memoryContent, fileCount };
|
|
||||||
}
|
|
||||||
|
|
||||||
async createToolRegistry(): Promise<ToolRegistry> {
|
async createToolRegistry(): Promise<ToolRegistry> {
|
||||||
const registry = new ToolRegistry(this);
|
const registry = new ToolRegistry(this);
|
||||||
|
|
||||||
|
|
|
@ -319,18 +319,35 @@ My code memory
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should respect MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY during downward scan', async () => {
|
it('should respect the maxDirs parameter during downward scan', async () => {
|
||||||
// the max depth is 200 so it will give up before searching all these.
|
const consoleDebugSpy = vi
|
||||||
for (let i = 0; i < 250; i++) {
|
.spyOn(console, 'debug')
|
||||||
|
.mockImplementation(() => {});
|
||||||
|
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
await createEmptyDir(path.join(cwd, `deep_dir_${i}`));
|
await createEmptyDir(path.join(cwd, `deep_dir_${i}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
// "much_deeper" is alphabetically after "deep_dir_*" so it won't be loaded
|
// Pass the custom limit directly to the function
|
||||||
await createTestFile(
|
await loadServerHierarchicalMemory(
|
||||||
path.join(cwd, 'much_deeper', DEFAULT_CONTEXT_FILENAME),
|
cwd,
|
||||||
'Ignored memory',
|
true,
|
||||||
|
new FileDiscoveryService(projectRoot),
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
respectGitIgnore: true,
|
||||||
|
respectGeminiIgnore: true,
|
||||||
|
},
|
||||||
|
50, // maxDirs
|
||||||
);
|
);
|
||||||
|
|
||||||
|
expect(consoleDebugSpy).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('[DEBUG] [BfsFileSearch]'),
|
||||||
|
expect.stringContaining('Scanning [50/50]:'),
|
||||||
|
);
|
||||||
|
|
||||||
|
vi.mocked(console.debug).mockRestore();
|
||||||
|
|
||||||
const result = await loadServerHierarchicalMemory(
|
const result = await loadServerHierarchicalMemory(
|
||||||
cwd,
|
cwd,
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -33,8 +33,6 @@ const logger = {
|
||||||
console.error('[ERROR] [MemoryDiscovery]', ...args),
|
console.error('[ERROR] [MemoryDiscovery]', ...args),
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY = 200;
|
|
||||||
|
|
||||||
interface GeminiFileContent {
|
interface GeminiFileContent {
|
||||||
filePath: string;
|
filePath: string;
|
||||||
content: string | null;
|
content: string | null;
|
||||||
|
@ -90,6 +88,7 @@ async function getGeminiMdFilePathsInternal(
|
||||||
fileService: FileDiscoveryService,
|
fileService: FileDiscoveryService,
|
||||||
extensionContextFilePaths: string[] = [],
|
extensionContextFilePaths: string[] = [],
|
||||||
fileFilteringOptions: FileFilteringOptions,
|
fileFilteringOptions: FileFilteringOptions,
|
||||||
|
maxDirs: number,
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const allPaths = new Set<string>();
|
const allPaths = new Set<string>();
|
||||||
const geminiMdFilenames = getAllGeminiMdFilenames();
|
const geminiMdFilenames = getAllGeminiMdFilenames();
|
||||||
|
@ -194,7 +193,7 @@ async function getGeminiMdFilePathsInternal(
|
||||||
|
|
||||||
const downwardPaths = await bfsFileSearch(resolvedCwd, {
|
const downwardPaths = await bfsFileSearch(resolvedCwd, {
|
||||||
fileName: geminiMdFilename,
|
fileName: geminiMdFilename,
|
||||||
maxDirs: MAX_DIRECTORIES_TO_SCAN_FOR_MEMORY,
|
maxDirs,
|
||||||
debug: debugMode,
|
debug: debugMode,
|
||||||
fileService,
|
fileService,
|
||||||
fileFilteringOptions: mergedOptions, // Pass merged options as fileFilter
|
fileFilteringOptions: mergedOptions, // Pass merged options as fileFilter
|
||||||
|
@ -295,6 +294,7 @@ export async function loadServerHierarchicalMemory(
|
||||||
fileService: FileDiscoveryService,
|
fileService: FileDiscoveryService,
|
||||||
extensionContextFilePaths: string[] = [],
|
extensionContextFilePaths: string[] = [],
|
||||||
fileFilteringOptions?: FileFilteringOptions,
|
fileFilteringOptions?: FileFilteringOptions,
|
||||||
|
maxDirs: number = 200,
|
||||||
): Promise<{ memoryContent: string; fileCount: number }> {
|
): Promise<{ memoryContent: string; fileCount: number }> {
|
||||||
if (debugMode)
|
if (debugMode)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
@ -311,6 +311,7 @@ export async function loadServerHierarchicalMemory(
|
||||||
fileService,
|
fileService,
|
||||||
extensionContextFilePaths,
|
extensionContextFilePaths,
|
||||||
fileFilteringOptions || DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
|
fileFilteringOptions || DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
|
||||||
|
maxDirs,
|
||||||
);
|
);
|
||||||
if (filePaths.length === 0) {
|
if (filePaths.length === 0) {
|
||||||
if (debugMode) logger.debug('No GEMINI.md files found in hierarchy.');
|
if (debugMode) logger.debug('No GEMINI.md files found in hierarchy.');
|
||||||
|
|
Loading…
Reference in New Issue