diff options
| author | joshualitt <[email protected]> | 2025-08-18 13:28:15 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-18 20:28:15 +0000 |
| commit | d66ddcd82e09d7b6fbc0226e31d73d38db5cff2a (patch) | |
| tree | d78d3437feffc7eb3620f5e02f5489453b3766aa /packages/cli/src | |
| parent | 91cd0db2b3e99f5829dbb6d09696333e9198cc9d (diff) | |
bug(core): Do not throw validation errors when building tools in `nonInteractiveToolExecutor`. (#6363)
Diffstat (limited to 'packages/cli/src')
| -rw-r--r-- | packages/cli/src/nonInteractiveCli.test.ts | 48 | ||||
| -rw-r--r-- | packages/cli/src/nonInteractiveCli.ts | 3 |
2 files changed, 40 insertions, 11 deletions
diff --git a/packages/cli/src/nonInteractiveCli.test.ts b/packages/cli/src/nonInteractiveCli.test.ts index 3e4ce037..79ee2d0d 100644 --- a/packages/cli/src/nonInteractiveCli.test.ts +++ b/packages/cli/src/nonInteractiveCli.test.ts @@ -150,7 +150,7 @@ describe('runNonInteractive', () => { expect(processStdoutSpy).toHaveBeenCalledWith('\n'); }); - it('should handle error during tool execution', async () => { + it('should handle error during tool execution and should send error back to the model', async () => { const toolCallEvent: ServerGeminiStreamEvent = { type: GeminiEventType.ToolCallRequest, value: { @@ -162,20 +162,52 @@ describe('runNonInteractive', () => { }, }; mockCoreExecuteToolCall.mockResolvedValue({ - error: new Error('Tool execution failed badly'), - errorType: ToolErrorType.UNHANDLED_EXCEPTION, + error: new Error('Execution failed'), + errorType: ToolErrorType.EXECUTION_FAILED, + responseParts: { + functionResponse: { + name: 'errorTool', + response: { + output: 'Error: Execution failed', + }, + }, + }, + resultDisplay: 'Execution failed', }); - mockGeminiClient.sendMessageStream.mockReturnValue( - createStreamFromEvents([toolCallEvent]), - ); + const finalResponse: ServerGeminiStreamEvent[] = [ + { + type: GeminiEventType.Content, + value: 'Sorry, let me try again.', + }, + ]; + mockGeminiClient.sendMessageStream + .mockReturnValueOnce(createStreamFromEvents([toolCallEvent])) + .mockReturnValueOnce(createStreamFromEvents(finalResponse)); await runNonInteractive(mockConfig, 'Trigger tool error', 'prompt-id-3'); expect(mockCoreExecuteToolCall).toHaveBeenCalled(); expect(consoleErrorSpy).toHaveBeenCalledWith( - 'Error executing tool errorTool: Tool execution failed badly', + 'Error executing tool errorTool: Execution failed', ); - expect(processExitSpy).toHaveBeenCalledWith(1); + expect(processExitSpy).not.toHaveBeenCalled(); + expect(mockGeminiClient.sendMessageStream).toHaveBeenCalledTimes(2); + expect(mockGeminiClient.sendMessageStream).toHaveBeenNthCalledWith( + 2, + [ + { + functionResponse: { + name: 'errorTool', + response: { + output: 'Error: Execution failed', + }, + }, + }, + ], + expect.any(AbortSignal), + 'prompt-id-3', + ); + expect(processStdoutSpy).toHaveBeenCalledWith('Sorry, let me try again.'); }); it('should exit with error if sendMessageStream throws initially', async () => { diff --git a/packages/cli/src/nonInteractiveCli.ts b/packages/cli/src/nonInteractiveCli.ts index f2efe8fc..b65bf15d 100644 --- a/packages/cli/src/nonInteractiveCli.ts +++ b/packages/cli/src/nonInteractiveCli.ts @@ -12,7 +12,6 @@ import { shutdownTelemetry, isTelemetrySdkInitialized, GeminiEventType, - ToolErrorType, parseAndFormatApiError, } from '@google/gemini-cli-core'; import { Content, Part, FunctionCall } from '@google/genai'; @@ -109,8 +108,6 @@ export async function runNonInteractive( console.error( `Error executing tool ${fc.name}: ${toolResponse.resultDisplay || toolResponse.error.message}`, ); - if (toolResponse.errorType === ToolErrorType.UNHANDLED_EXCEPTION) - process.exit(1); } if (toolResponse.responseParts) { |
