From 759024dfa38a70c801f3c5ef2fd3da5093b80daa Mon Sep 17 00:00:00 2001 From: gsehgal Date: Wed, 10 Dec 2025 05:50:12 +0000 Subject: [PATCH 1/4] Add clarity to error messages --- packages/cli/src/nonInteractiveCli.ts | 4 +- .../src/ui/hooks/atCommandProcessor.test.ts | 53 ++++++++++++++++++- .../cli/src/ui/hooks/atCommandProcessor.ts | 27 ++++++++-- 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/nonInteractiveCli.ts b/packages/cli/src/nonInteractiveCli.ts index 07a2bf5ca9c..c2a0613d905 100644 --- a/packages/cli/src/nonInteractiveCli.ts +++ b/packages/cli/src/nonInteractiveCli.ts @@ -230,7 +230,7 @@ export async function runNonInteractive({ } if (!query) { - const { processedQuery, shouldProceed } = await handleAtCommand({ + const { processedQuery, shouldProceed, error } = await handleAtCommand({ query: input, config, addItem: (_item, _timestamp) => 0, @@ -243,7 +243,7 @@ export async function runNonInteractive({ // An error occurred during @include processing (e.g., file not found). // The error message is already logged by handleAtCommand. throw new FatalInputError( - 'Exiting due to an error processing the @ command.', + error || 'Exiting due to an error processing the @ command.', ); } query = processedQuery as Part[]; diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts index 68eaa423dee..36fceff42ae 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts @@ -11,12 +11,13 @@ import type { Config, DiscoveredMCPResource } from '@google/gemini-cli-core'; import { FileDiscoveryService, GlobTool, - ReadManyFilesTool, + ReadManyFilesTool, // Import a reference for mocking StandardFileSystemService, ToolRegistry, 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'; @@ -990,7 +991,7 @@ describe('handleAtCommand', () => { }); }); - 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'), @@ -1342,4 +1343,52 @@ describe('handleAtCommand', () => { ); }); }); + + it('should return shouldProceed: false 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, + shouldProceed: false, + 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, + ); + }); }); diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.ts b/packages/cli/src/ui/hooks/atCommandProcessor.ts index 6f620f3f4d3..17ee9acfd8e 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.ts @@ -36,6 +36,7 @@ interface HandleAtCommandParams { interface HandleAtCommandResult { processedQuery: PartListUnion | null; shouldProceed: boolean; + error?: string; } interface AtCommandPart { @@ -172,7 +173,11 @@ export async function handleAtCommand({ { type: 'error', text: 'Error: read_many_files tool not found.' }, userMessageTimestamp, ); - return { processedQuery: null, shouldProceed: false }; + return { + processedQuery: null, + shouldProceed: false, + error: 'Error: read_many_files tool not found.', + }; } for (const atPathPart of atPathCommandParts) { @@ -189,16 +194,17 @@ export async function handleAtCommand({ if (!pathName) { // This case should ideally not be hit if parseAllAtCommands ensures content after @ // but as a safeguard: + const errMsg = `Error: Invalid @ command '${originalAtPath}'. No path specified.`; addItem( { type: 'error', - text: `Error: Invalid @ command '${originalAtPath}'. No path specified.`, + text: errMsg, }, userMessageTimestamp, ); // Decide if this is a fatal error for the whole command or just skip this @ part // For now, let's be strict and fail the command if one @path is malformed. - return { processedQuery: null, shouldProceed: false }; + return { processedQuery: null, shouldProceed: false, error: errMsg }; } // Check if this is an MCP resource reference (serverName:uri format) @@ -494,8 +500,15 @@ export async function handleAtCommand({ >, userMessageTimestamp, ); - return { processedQuery: null, shouldProceed: false }; + const firstError = resourceReadDisplays.find( + (d) => d.status === ToolCallStatus.Error, + ); + const errorMsg = firstError + ? `Exiting due to an error processing the @ command: ${firstError.resultDisplay}` + : 'Exiting due to an error processing the @ command.'; + return { processedQuery: null, shouldProceed: false, error: errorMsg }; } + // Find the first error to report if (pathSpecsToRead.length === 0) { if (resourceReadDisplays.length > 0) { @@ -612,7 +625,11 @@ export async function handleAtCommand({ } as Omit, userMessageTimestamp, ); - return { processedQuery: null, shouldProceed: false }; + return { + processedQuery: null, + shouldProceed: false, + error: `Exiting due to an error processing the @ command: ${readManyFilesDisplay.resultDisplay}`, + }; } } From e97421e65c4077f097c149ad9ebea0591272d372 Mon Sep 17 00:00:00 2001 From: gsehgal Date: Wed, 10 Dec 2025 06:17:51 +0000 Subject: [PATCH 2/4] Addressed review comment --- packages/cli/src/ui/hooks/atCommandProcessor.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.ts b/packages/cli/src/ui/hooks/atCommandProcessor.ts index 17ee9acfd8e..88f3f815916 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.ts @@ -502,10 +502,8 @@ export async function handleAtCommand({ ); const firstError = resourceReadDisplays.find( (d) => d.status === ToolCallStatus.Error, - ); - const errorMsg = firstError - ? `Exiting due to an error processing the @ command: ${firstError.resultDisplay}` - : 'Exiting due to an error processing the @ command.'; + )!; + const errorMsg = `Exiting due to an error processing the @ command: ${firstError.resultDisplay}`; return { processedQuery: null, shouldProceed: false, error: errorMsg }; } // Find the first error to report From fb1fdf7a1b8b2d01ebd0a2beb645e0ad11850377 Mon Sep 17 00:00:00 2001 From: gsehgal Date: Thu, 11 Dec 2025 05:07:51 +0000 Subject: [PATCH 3/4] Addressed review comments --- packages/cli/src/ui/hooks/atCommandProcessor.test.ts | 2 +- packages/cli/src/ui/hooks/atCommandProcessor.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts index 36fceff42ae..684a41dd65a 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts @@ -11,7 +11,7 @@ import type { Config, DiscoveredMCPResource } from '@google/gemini-cli-core'; import { FileDiscoveryService, GlobTool, - ReadManyFilesTool, // Import a reference for mocking + ReadManyFilesTool, StandardFileSystemService, ToolRegistry, COMMON_IGNORE_PATTERNS, diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.ts b/packages/cli/src/ui/hooks/atCommandProcessor.ts index 88f3f815916..c7e8ce19bdc 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.ts @@ -500,13 +500,17 @@ export async function handleAtCommand({ >, userMessageTimestamp, ); + // Find the first error to report const firstError = resourceReadDisplays.find( (d) => d.status === ToolCallStatus.Error, )!; + const errorMessages = resourceReadDisplays + .filter((d) => d.status === ToolCallStatus.Error) + .map((d) => d.resultDisplay); + console.error(errorMessages); const errorMsg = `Exiting due to an error processing the @ command: ${firstError.resultDisplay}`; return { processedQuery: null, shouldProceed: false, error: errorMsg }; } - // Find the first error to report if (pathSpecsToRead.length === 0) { if (resourceReadDisplays.length > 0) { From 409e940d08db5e9e2a6b71c9b23f857eca9b6c71 Mon Sep 17 00:00:00 2001 From: gsehgal Date: Fri, 12 Dec 2025 14:20:44 +0000 Subject: [PATCH 4/4] Adressed review comments --- packages/cli/src/nonInteractiveCli.test.ts | 2 - packages/cli/src/nonInteractiveCli.ts | 4 +- .../src/ui/hooks/atCommandProcessor.test.ts | 41 ++++--------------- .../cli/src/ui/hooks/atCommandProcessor.ts | 22 ++++------ packages/cli/src/ui/hooks/useGeminiStream.ts | 3 +- 5 files changed, 19 insertions(+), 53 deletions(-) diff --git a/packages/cli/src/nonInteractiveCli.test.ts b/packages/cli/src/nonInteractiveCli.test.ts index f40dc68cbd6..388f3e64545 100644 --- a/packages/cli/src/nonInteractiveCli.test.ts +++ b/packages/cli/src/nonInteractiveCli.test.ts @@ -198,7 +198,6 @@ describe('runNonInteractive', () => { ); vi.mocked(handleAtCommand).mockImplementation(async ({ query }) => ({ processedQuery: [{ text: query }], - shouldProceed: true, })); }); @@ -573,7 +572,6 @@ describe('runNonInteractive', () => { // 3. Setup the mock to return the processed parts mockHandleAtCommand.mockResolvedValue({ processedQuery: processedParts, - shouldProceed: true, }); // Mock a simple stream response from the Gemini client diff --git a/packages/cli/src/nonInteractiveCli.ts b/packages/cli/src/nonInteractiveCli.ts index c2a0613d905..084b59c2d95 100644 --- a/packages/cli/src/nonInteractiveCli.ts +++ b/packages/cli/src/nonInteractiveCli.ts @@ -230,7 +230,7 @@ export async function runNonInteractive({ } if (!query) { - const { processedQuery, shouldProceed, error } = await handleAtCommand({ + const { processedQuery, error } = await handleAtCommand({ query: input, config, addItem: (_item, _timestamp) => 0, @@ -239,7 +239,7 @@ export async function runNonInteractive({ signal: abortController.signal, }); - if (!shouldProceed || !processedQuery) { + if (error || !processedQuery) { // An error occurred during @include processing (e.g., file not found). // The error message is already logged by handleAtCommand. throw new FatalInputError( diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts index 684a41dd65a..ae093ee56ca 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts @@ -121,7 +121,6 @@ describe('handleAtCommand', () => { expect(result).toEqual({ processedQuery: [{ text: query }], - shouldProceed: true, }); }); @@ -139,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.', @@ -172,7 +170,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); expect(mockAddItem).toHaveBeenCalledWith( expect.objectContaining({ @@ -212,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}`, @@ -247,7 +243,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -277,7 +272,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); expect(mockAddItem).toHaveBeenCalledWith( expect.objectContaining({ @@ -322,7 +316,6 @@ describe('handleAtCommand', () => { { text: content2 }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -363,7 +356,6 @@ describe('handleAtCommand', () => { { text: content2 }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -402,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.`, @@ -429,7 +420,6 @@ describe('handleAtCommand', () => { expect(result).toEqual({ processedQuery: [{ text: 'Check @nonexistent.txt and @ also' }], - shouldProceed: true, }); }); @@ -463,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.`, @@ -502,7 +491,6 @@ describe('handleAtCommand', () => { { text: 'console.log("Hello world");' }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -535,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.`, @@ -563,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.`, @@ -596,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(); }); }); @@ -623,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.`, @@ -661,7 +647,6 @@ describe('handleAtCommand', () => { { text: 'console.log("Hello world");' }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -697,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.`, @@ -825,7 +809,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }, ); @@ -864,7 +847,6 @@ describe('handleAtCommand', () => { { text: content2 }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -894,7 +876,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -925,7 +906,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -956,7 +936,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -987,7 +966,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -1018,7 +996,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -1047,7 +1024,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -1076,7 +1052,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); @@ -1105,7 +1080,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); }); }); @@ -1137,7 +1111,6 @@ describe('handleAtCommand', () => { { text: fileContent }, { text: '\n--- End of content ---' }, ], - shouldProceed: true, }); expect(mockOnDebugMessage).toHaveBeenCalledWith( @@ -1166,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.` }, @@ -1208,7 +1182,6 @@ describe('handleAtCommand', () => { expect(result).toEqual({ processedQuery: [{ text: `Check @${outsidePath} please.` }], - shouldProceed: true, }); expect(mockOnDebugMessage).toHaveBeenCalledWith( @@ -1327,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', @@ -1344,7 +1318,7 @@ describe('handleAtCommand', () => { }); }); - it('should return shouldProceed: false if the read_many_files tool is cancelled by user', async () => { + 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'), @@ -1379,7 +1353,6 @@ describe('handleAtCommand', () => { expect(result).toEqual({ processedQuery: null, - shouldProceed: false, error: `Exiting due to an error processing the @ command: Error reading files (file.txt): User cancelled operation`, }); diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.ts b/packages/cli/src/ui/hooks/atCommandProcessor.ts index c7e8ce19bdc..05b2f1542e3 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.ts @@ -35,7 +35,6 @@ interface HandleAtCommandParams { interface HandleAtCommandResult { processedQuery: PartListUnion | null; - shouldProceed: boolean; error?: string; } @@ -145,7 +144,7 @@ export async function handleAtCommand({ ); if (atPathCommandParts.length === 0) { - return { processedQuery: [{ text: query }], shouldProceed: true }; + return { processedQuery: [{ text: query }] }; } // Get centralized file discovery service @@ -175,7 +174,6 @@ export async function handleAtCommand({ ); return { processedQuery: null, - shouldProceed: false, error: 'Error: read_many_files tool not found.', }; } @@ -204,7 +202,7 @@ export async function handleAtCommand({ ); // Decide if this is a fatal error for the whole command or just skip this @ part // For now, let's be strict and fail the command if one @path is malformed. - return { processedQuery: null, shouldProceed: false, error: errMsg }; + return { processedQuery: null, error: errMsg }; } // Check if this is an MCP resource reference (serverName:uri format) @@ -423,16 +421,13 @@ export async function handleAtCommand({ onDebugMessage('No valid file paths found in @ commands to read.'); if (initialQueryText === '@' && query.trim() === '@') { // If the only thing was a lone @, pass original query (which might have spaces) - return { processedQuery: [{ text: query }], shouldProceed: true }; + return { processedQuery: [{ text: query }] }; } else if (!initialQueryText && query) { // If all @-commands were invalid and no surrounding text, pass original query - return { processedQuery: [{ text: query }], shouldProceed: true }; + return { processedQuery: [{ text: query }] }; } // Otherwise, proceed with the (potentially modified) query text that doesn't involve file reading - return { - processedQuery: [{ text: initialQueryText || query }], - shouldProceed: true, - }; + return { processedQuery: [{ text: initialQueryText || query }] }; } const processedQueryParts: PartListUnion = [{ text: initialQueryText }]; @@ -509,7 +504,7 @@ export async function handleAtCommand({ .map((d) => d.resultDisplay); console.error(errorMessages); const errorMsg = `Exiting due to an error processing the @ command: ${firstError.resultDisplay}`; - return { processedQuery: null, shouldProceed: false, error: errorMsg }; + return { processedQuery: null, error: errorMsg }; } if (pathSpecsToRead.length === 0) { @@ -522,7 +517,7 @@ export async function handleAtCommand({ userMessageTimestamp, ); } - return { processedQuery: processedQueryParts, shouldProceed: true }; + return { processedQuery: processedQueryParts }; } const toolArgs = { @@ -608,7 +603,7 @@ export async function handleAtCommand({ userMessageTimestamp, ); } - return { processedQuery: processedQueryParts, shouldProceed: true }; + return { processedQuery: processedQueryParts }; } catch (error: unknown) { readManyFilesDisplay = { callId: `client-read-${userMessageTimestamp}`, @@ -629,7 +624,6 @@ export async function handleAtCommand({ ); return { processedQuery: null, - shouldProceed: false, error: `Exiting due to an error processing the @ command: ${readManyFilesDisplay.resultDisplay}`, }; } diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index 47b97936f6b..86c4b6c1149 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -483,7 +483,8 @@ export const useGeminiStream = ( userMessageTimestamp, ); - if (!atCommandResult.shouldProceed) { + if (atCommandResult.error) { + onDebugMessage(atCommandResult.error); return { queryToSend: null, shouldProceed: false }; } localQueryToSendToGemini = atCommandResult.processedQuery;