diff --git a/packages/core/src/core/__snapshots__/prompts.test.ts.snap b/packages/core/src/core/__snapshots__/prompts.test.ts.snap index 79278fbf..07ec166a 100644 --- a/packages/core/src/core/__snapshots__/prompts.test.ts.snap +++ b/packages/core/src/core/__snapshots__/prompts.test.ts.snap @@ -13,6 +13,7 @@ exports[`Core System Prompt (prompts.ts) > should append userMemory with separat - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -92,7 +93,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -132,7 +133,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -193,6 +194,7 @@ exports[`Core System Prompt (prompts.ts) > should include git instructions when - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -287,7 +289,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -327,7 +329,7 @@ Would you like me to write a commit message and commit these changes? user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -383,6 +385,7 @@ exports[`Core System Prompt (prompts.ts) > should include non-sandbox instructio - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -462,7 +465,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -502,7 +505,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -558,6 +561,7 @@ exports[`Core System Prompt (prompts.ts) > should include sandbox-specific instr - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -637,7 +641,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -677,7 +681,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -733,6 +737,7 @@ exports[`Core System Prompt (prompts.ts) > should include seatbelt-specific inst - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -812,7 +817,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -852,7 +857,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -908,6 +913,7 @@ exports[`Core System Prompt (prompts.ts) > should not include git instructions w - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -987,7 +993,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -1027,7 +1033,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -1083,6 +1089,7 @@ exports[`Core System Prompt (prompts.ts) > should return the base prompt when no - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -1162,7 +1169,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -1202,7 +1209,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -1258,6 +1265,7 @@ exports[`Core System Prompt (prompts.ts) > should return the base prompt when us - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -1337,7 +1345,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -1377,7 +1385,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -1433,6 +1441,7 @@ exports[`Core System Prompt (prompts.ts) > should return the base prompt when us - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., read_file' or 'write_file'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -1512,7 +1521,7 @@ model: true user: list files here. -model: [tool_call: list_directory for path '.'] +model: [tool_call: list_directory for path '/path/to/project'] @@ -1552,7 +1561,7 @@ All checks passed. This is a stable checkpoint. user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. diff --git a/packages/core/src/core/prompts.ts b/packages/core/src/core/prompts.ts index 509864f8..f5caee05 100644 --- a/packages/core/src/core/prompts.ts +++ b/packages/core/src/core/prompts.ts @@ -22,12 +22,12 @@ export function getCoreSystemPrompt(userMemory?: string): string { // if GEMINI_SYSTEM_MD is set (and not 0|false), override system prompt from file // default path is .gemini/system.md but can be modified via custom path in GEMINI_SYSTEM_MD let systemMdEnabled = false; - let systemMdPath = path.join(GEMINI_CONFIG_DIR, 'system.md'); + let systemMdPath = path.resolve(path.join(GEMINI_CONFIG_DIR, 'system.md')); const systemMdVar = process.env.GEMINI_SYSTEM_MD?.toLowerCase(); if (systemMdVar && !['0', 'false'].includes(systemMdVar)) { systemMdEnabled = true; // enable system prompt override if (!['1', 'true'].includes(systemMdVar)) { - systemMdPath = systemMdVar; // use custom path from GEMINI_SYSTEM_MD + systemMdPath = path.resolve(systemMdVar); // use custom path from GEMINI_SYSTEM_MD } // require file to exist when override is enabled if (!fs.existsSync(systemMdPath)) { @@ -49,6 +49,7 @@ You are an interactive CLI agent specializing in software engineering tasks. You - **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions. - **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it. - **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked. +- **Path Construction:** Before using any file system tool (e.g., ${ReadFileTool.Name}' or '${WriteFileTool.Name}'), you must construct the full absolute path for the file_path argument. Always combine the absolute path of the project's root directory with the file's path relative to the root. For example, if the project root is /path/to/project/ and the file is foo/bar/baz.txt, the final path you must use is /path/to/project/foo/bar/baz.txt. If the user provides a relative path, you must resolve it against the root directory to create an absolute path. - **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes. # Primary Workflows @@ -166,7 +167,7 @@ model: true user: list files here. -model: [tool_call: ${LSTool.Name} for path '.'] +model: [tool_call: ${LSTool.Name} for path '/path/to/project'] @@ -211,7 +212,7 @@ ${(function () { user: Delete the temp directory. -model: I can run \`rm -rf ./temp\`. This will permanently delete the directory and all its contents. +model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete the directory and all its contents. @@ -260,7 +261,7 @@ Your core function is efficient and safe assistance. Balance extreme conciseness if (['1', 'true'].includes(writeSystemMdVar)) { fs.writeFileSync(systemMdPath, basePrompt); // write to default path, can be modified via GEMINI_SYSTEM_MD } else { - fs.writeFileSync(writeSystemMdVar, basePrompt); // write to custom path from GEMINI_WRITE_SYSTEM_MD + fs.writeFileSync(path.resolve(writeSystemMdVar), basePrompt); // write to custom path from GEMINI_WRITE_SYSTEM_MD } } diff --git a/packages/core/src/tools/read-file.ts b/packages/core/src/tools/read-file.ts index dd173813..5c37f45b 100644 --- a/packages/core/src/tools/read-file.ts +++ b/packages/core/src/tools/read-file.ts @@ -101,11 +101,7 @@ export class ReadFileTool extends BaseTool { const fileService = this.config.getFileService(); if (fileService.shouldGeminiIgnoreFile(params.absolute_path)) { - const relativePath = makeRelative( - params.absolute_path, - this.rootDirectory, - ); - return `File path '${shortenPath(relativePath)}' is ignored by .geminiignore pattern(s).`; + return `File path '${filePath}' is ignored by .geminiignore pattern(s).`; } return null; diff --git a/packages/core/src/tools/read-many-files.test.ts b/packages/core/src/tools/read-many-files.test.ts index ef42d8b6..d2591a8b 100644 --- a/packages/core/src/tools/read-many-files.test.ts +++ b/packages/core/src/tools/read-many-files.test.ts @@ -195,8 +195,9 @@ describe('ReadManyFilesTool', () => { createFile('file1.txt', 'Content of file1'); const params = { paths: ['file1.txt'] }; const result = await tool.execute(params, new AbortController().signal); + const expectedPath = path.join(tempRootDir, 'file1.txt'); expect(result.llmContent).toEqual([ - '--- file1.txt ---\n\nContent of file1\n\n', + `--- ${expectedPath} ---\n\nContent of file1\n\n`, ]); expect(result.returnDisplay).toContain( 'Successfully read and concatenated content from **1 file(s)**', @@ -209,12 +210,16 @@ describe('ReadManyFilesTool', () => { const params = { paths: ['file1.txt', 'subdir/file2.js'] }; const result = await tool.execute(params, new AbortController().signal); const content = result.llmContent as string[]; + const expectedPath1 = path.join(tempRootDir, 'file1.txt'); + const expectedPath2 = path.join(tempRootDir, 'subdir/file2.js'); expect( - content.some((c) => c.includes('--- file1.txt ---\n\nContent1\n\n')), + content.some((c) => + c.includes(`--- ${expectedPath1} ---\n\nContent1\n\n`), + ), ).toBe(true); expect( content.some((c) => - c.includes('--- subdir/file2.js ---\n\nContent2\n\n'), + c.includes(`--- ${expectedPath2} ---\n\nContent2\n\n`), ), ).toBe(true); expect(result.returnDisplay).toContain( @@ -229,12 +234,16 @@ describe('ReadManyFilesTool', () => { const params = { paths: ['*.txt'] }; const result = await tool.execute(params, new AbortController().signal); const content = result.llmContent as string[]; + const expectedPath1 = path.join(tempRootDir, 'file.txt'); + const expectedPath2 = path.join(tempRootDir, 'another.txt'); expect( - content.some((c) => c.includes('--- file.txt ---\n\nText file\n\n')), + content.some((c) => + c.includes(`--- ${expectedPath1} ---\n\nText file\n\n`), + ), ).toBe(true); expect( content.some((c) => - c.includes('--- another.txt ---\n\nAnother text\n\n'), + c.includes(`--- ${expectedPath2} ---\n\nAnother text\n\n`), ), ).toBe(true); expect(content.find((c) => c.includes('sub/data.json'))).toBeUndefined(); @@ -249,7 +258,8 @@ describe('ReadManyFilesTool', () => { const params = { paths: ['src/**/*.ts'], exclude: ['**/*.test.ts'] }; const result = await tool.execute(params, new AbortController().signal); const content = result.llmContent as string[]; - expect(content).toEqual(['--- src/main.ts ---\n\nMain content\n\n']); + const expectedPath = path.join(tempRootDir, 'src/main.ts'); + expect(content).toEqual([`--- ${expectedPath} ---\n\nMain content\n\n`]); expect( content.find((c) => c.includes('src/main.test.ts')), ).toBeUndefined(); @@ -275,7 +285,8 @@ describe('ReadManyFilesTool', () => { const params = { paths: ['**/*.js'] }; const result = await tool.execute(params, new AbortController().signal); const content = result.llmContent as string[]; - expect(content).toEqual(['--- src/app.js ---\n\napp code\n\n']); + const expectedPath = path.join(tempRootDir, 'src/app.js'); + expect(content).toEqual([`--- ${expectedPath} ---\n\napp code\n\n`]); expect( content.find((c) => c.includes('node_modules/some-lib/index.js')), ).toBeUndefined(); @@ -290,13 +301,20 @@ describe('ReadManyFilesTool', () => { const params = { paths: ['**/*.js'], useDefaultExcludes: false }; const result = await tool.execute(params, new AbortController().signal); const content = result.llmContent as string[]; + const expectedPath1 = path.join( + tempRootDir, + 'node_modules/some-lib/index.js', + ); + const expectedPath2 = path.join(tempRootDir, 'src/app.js'); expect( content.some((c) => - c.includes('--- node_modules/some-lib/index.js ---\n\nlib code\n\n'), + c.includes(`--- ${expectedPath1} ---\n\nlib code\n\n`), ), ).toBe(true); expect( - content.some((c) => c.includes('--- src/app.js ---\n\napp code\n\n')), + content.some((c) => + c.includes(`--- ${expectedPath2} ---\n\napp code\n\n`), + ), ).toBe(true); expect(result.returnDisplay).toContain( 'Successfully read and concatenated content from **2 file(s)**', @@ -350,9 +368,12 @@ describe('ReadManyFilesTool', () => { const params = { paths: ['*'] }; // Generic glob, not specific to .pdf const result = await tool.execute(params, new AbortController().signal); const content = result.llmContent as string[]; + const expectedPath = path.join(tempRootDir, 'notes.txt'); expect( content.some( - (c) => typeof c === 'string' && c.includes('--- notes.txt ---'), + (c) => + typeof c === 'string' && + c.includes(`--- ${expectedPath} ---\n\ntext notes\n\n`), ), ).toBe(true); expect(result.returnDisplay).toContain('**Skipped 1 item(s):**'); diff --git a/packages/core/src/tools/read-many-files.ts b/packages/core/src/tools/read-many-files.ts index 38cecc16..5557dc43 100644 --- a/packages/core/src/tools/read-many-files.ts +++ b/packages/core/src/tools/read-many-files.ts @@ -390,7 +390,7 @@ Use this tool when the user's query implies needing the content of several files if (typeof fileReadResult.llmContent === 'string') { const separator = DEFAULT_OUTPUT_SEPARATOR_FORMAT.replace( '{filePath}', - relativePathForDisplay, + filePath, ); contentParts.push(`${separator}\n\n${fileReadResult.llmContent}\n\n`); } else {