mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-20 02:51:55 -07:00
Add clarity to error messages (#14879)
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
COMMON_IGNORE_PATTERNS,
|
||||
// DEFAULT_FILE_EXCLUDES,
|
||||
} from '@google/gemini-cli-core';
|
||||
import * as core from '@google/gemini-cli-core';
|
||||
import * as os from 'node:os';
|
||||
import { ToolCallStatus } from '../types.js';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
@@ -120,7 +121,6 @@ describe('handleAtCommand', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: [{ text: query }],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -138,7 +138,6 @@ describe('handleAtCommand', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: [{ text: queryWithSpaces }],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
'Lone @ detected, will be treated as text in the modified query.',
|
||||
@@ -171,7 +170,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@@ -211,7 +209,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
`Path ${dirPath} resolved to directory, using glob: ${resolvedGlob}`,
|
||||
@@ -246,7 +243,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -276,7 +272,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@@ -321,7 +316,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: content2 },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -362,7 +356,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: content2 },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -401,7 +394,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: content1 },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
`Path ${invalidFile} not found directly, attempting glob search.`,
|
||||
@@ -428,7 +420,6 @@ describe('handleAtCommand', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: [{ text: 'Check @nonexistent.txt and @ also' }],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -462,7 +453,6 @@ describe('handleAtCommand', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: [{ text: query }],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
`Path ${gitIgnoredFile} is git-ignored and will be skipped.`,
|
||||
@@ -501,7 +491,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: 'console.log("Hello world");' },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -534,7 +523,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: '# Project README' },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
`Path ${gitIgnoredFile} is git-ignored and will be skipped.`,
|
||||
@@ -562,7 +550,6 @@ describe('handleAtCommand', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: [{ text: query }],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
`Path ${gitFile} is git-ignored and will be skipped.`,
|
||||
@@ -595,7 +582,8 @@ describe('handleAtCommand', () => {
|
||||
`Glob tool not found. Path ${invalidFile} will be skipped.`,
|
||||
);
|
||||
expect(result.processedQuery).toEqual([{ text: query }]);
|
||||
expect(result.shouldProceed).toBe(true);
|
||||
expect(result.processedQuery).not.toBeNull();
|
||||
expect(result.error).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -622,7 +610,6 @@ describe('handleAtCommand', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: [{ text: query }],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
`Path ${geminiIgnoredFile} is gemini-ignored and will be skipped.`,
|
||||
@@ -660,7 +647,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: 'console.log("Hello world");' },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -696,7 +682,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: '// Main application entry' },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
`Path ${geminiIgnoredFile} is gemini-ignored and will be skipped.`,
|
||||
@@ -824,7 +809,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -863,7 +847,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: content2 },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -893,7 +876,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -924,7 +906,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -955,7 +936,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -986,11 +966,10 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not terminate at period within file name', async () => {
|
||||
it('should correctly handle file paths with multiple periods', async () => {
|
||||
const fileContent = 'Version info';
|
||||
const filePath = await createTestFile(
|
||||
path.join(testRootDir, 'version.1.2.3.txt'),
|
||||
@@ -1017,7 +996,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1046,7 +1024,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1075,7 +1052,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1104,7 +1080,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1136,7 +1111,6 @@ describe('handleAtCommand', () => {
|
||||
{ text: fileContent },
|
||||
{ text: '\n--- End of content ---' },
|
||||
],
|
||||
shouldProceed: true,
|
||||
});
|
||||
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
@@ -1165,7 +1139,8 @@ describe('handleAtCommand', () => {
|
||||
signal: abortController.signal,
|
||||
});
|
||||
|
||||
expect(result.shouldProceed).toBe(true);
|
||||
expect(result.processedQuery).not.toBeNull();
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.processedQuery).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: `Check @${path.join(subDirPath, '**')} please.` },
|
||||
@@ -1207,7 +1182,6 @@ describe('handleAtCommand', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: [{ text: `Check @${outsidePath} please.` }],
|
||||
shouldProceed: true,
|
||||
});
|
||||
|
||||
expect(mockOnDebugMessage).toHaveBeenCalledWith(
|
||||
@@ -1326,7 +1300,8 @@ describe('handleAtCommand', () => {
|
||||
signal: abortController.signal,
|
||||
});
|
||||
|
||||
expect(result.shouldProceed).toBe(false);
|
||||
expect(result.processedQuery).toBeNull();
|
||||
expect(result.error).toBeDefined();
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: 'tool_group',
|
||||
@@ -1342,4 +1317,51 @@ describe('handleAtCommand', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return error if the read_many_files tool is cancelled by user', async () => {
|
||||
const fileContent = 'Some content';
|
||||
const filePath = await createTestFile(
|
||||
path.join(testRootDir, 'file.txt'),
|
||||
fileContent,
|
||||
);
|
||||
const query = `@${filePath}`;
|
||||
|
||||
// Simulate user cancellation
|
||||
const mockToolInstance = {
|
||||
buildAndExecute: vi
|
||||
.fn()
|
||||
.mockRejectedValue(new Error('User cancelled operation')),
|
||||
displayName: 'Read Many Files',
|
||||
build: vi.fn(() => ({
|
||||
execute: mockToolInstance.buildAndExecute,
|
||||
getDescription: vi.fn(() => 'Mocked tool description'),
|
||||
})),
|
||||
};
|
||||
const viSpy = vi.spyOn(core, 'ReadManyFilesTool');
|
||||
viSpy.mockImplementation(
|
||||
() => mockToolInstance as unknown as core.ReadManyFilesTool,
|
||||
);
|
||||
|
||||
const result = await handleAtCommand({
|
||||
query,
|
||||
config: mockConfig,
|
||||
addItem: mockAddItem,
|
||||
onDebugMessage: mockOnDebugMessage,
|
||||
messageId: 134,
|
||||
signal: abortController.signal,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
processedQuery: null,
|
||||
error: `Exiting due to an error processing the @ command: Error reading files (file.txt): User cancelled operation`,
|
||||
});
|
||||
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: 'tool_group',
|
||||
tools: [expect.objectContaining({ status: ToolCallStatus.Error })],
|
||||
}),
|
||||
134,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user