From db115c468a894e7bf203e18577f1b698e939aef0 Mon Sep 17 00:00:00 2001 From: Vachan <52260220+vachan-shetty@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:57:40 -0700 Subject: [PATCH] Updates error handling in case of incorrect tool calling. (#2304) --- packages/cli/src/nonInteractiveCli.test.ts | 65 ++++++++++++++++++++++ packages/cli/src/nonInteractiveCli.ts | 7 ++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/nonInteractiveCli.test.ts b/packages/cli/src/nonInteractiveCli.test.ts index 54d57ae2..01ef5782 100644 --- a/packages/cli/src/nonInteractiveCli.test.ts +++ b/packages/cli/src/nonInteractiveCli.test.ts @@ -218,4 +218,69 @@ describe('runNonInteractive', () => { '[API Error: API connection failed]', ); }); + + it('should not exit if a tool is not found, and should send error back to model', async () => { + const functionCall: FunctionCall = { + id: 'fcNotFound', + name: 'nonExistentTool', + args: {}, + }; + const errorResponsePart: Part = { + functionResponse: { + name: 'nonExistentTool', + id: 'fcNotFound', + response: { error: 'Tool "nonExistentTool" not found in registry.' }, + }, + }; + + const { executeToolCall: mockCoreExecuteToolCall } = await import( + '@google/gemini-cli-core' + ); + vi.mocked(mockCoreExecuteToolCall).mockResolvedValue({ + callId: 'fcNotFound', + responseParts: [errorResponsePart], + resultDisplay: 'Tool "nonExistentTool" not found in registry.', + error: new Error('Tool "nonExistentTool" not found in registry.'), + }); + + const stream1 = (async function* () { + yield { functionCalls: [functionCall] } as GenerateContentResponse; + })(); + const stream2 = (async function* () { + yield { + candidates: [ + { + content: { + parts: [{ text: 'Unfortunately the tool does not exist.' }], + }, + }, + ], + } as GenerateContentResponse; + })(); + mockChat.sendMessageStream + .mockResolvedValueOnce(stream1) + .mockResolvedValueOnce(stream2); + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + await runNonInteractive(mockConfig, 'Trigger tool not found'); + + expect(consoleErrorSpy).toHaveBeenCalledWith( + 'Error executing tool nonExistentTool: Tool "nonExistentTool" not found in registry.', + ); + + expect(mockProcessExit).not.toHaveBeenCalled(); + + expect(mockChat.sendMessageStream).toHaveBeenCalledTimes(2); + expect(mockChat.sendMessageStream).toHaveBeenLastCalledWith( + expect.objectContaining({ + message: [errorResponsePart], + }), + ); + + expect(mockProcessStdoutWrite).toHaveBeenCalledWith( + 'Unfortunately the tool does not exist.', + ); + }); }); diff --git a/packages/cli/src/nonInteractiveCli.ts b/packages/cli/src/nonInteractiveCli.ts index 95a9c51c..64a87162 100644 --- a/packages/cli/src/nonInteractiveCli.ts +++ b/packages/cli/src/nonInteractiveCli.ts @@ -110,10 +110,15 @@ export async function runNonInteractive( ); if (toolResponse.error) { + const isToolNotFound = toolResponse.error.message.includes( + 'not found in registry', + ); console.error( `Error executing tool ${fc.name}: ${toolResponse.resultDisplay || toolResponse.error.message}`, ); - process.exit(1); + if (!isToolNotFound) { + process.exit(1); + } } if (toolResponse.responseParts) {