From 3aaeb447396008ef098f09a5f633fd4a9620ccc4 Mon Sep 17 00:00:00 2001 From: Taylor Mullen Date: Sun, 18 May 2025 00:23:57 -0700 Subject: [PATCH] fix(shell): Improve error reporting for shell command failures This commit enhances the tool to provide more informative feedback to the user when a shell command fails, especially in non-debug mode. Previously, if a command terminated due to a signal (e.g., SIGPIPE during a with no upstream) or failed without producing stdout/stderr, the user would see no output, making it difficult to diagnose the issue. Changes: - Modified to update the logic. - If a command produces no direct output but results in an error, signal, non-zero exit code, or user cancellation, a concise message indicating this outcome is now shown in . - Utilized the existing utility from for consistent error message formatting, which also resolved previous TypeScript type inference issues. This ensures users receive clearer feedback on command execution status, improving the tool's usability and aiding in troubleshooting. Fixes https://b.corp.google.com/issues/417998119 --- packages/server/src/tools/shell.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/server/src/tools/shell.ts b/packages/server/src/tools/shell.ts index 7851b76a..8a1baa2a 100644 --- a/packages/server/src/tools/shell.ts +++ b/packages/server/src/tools/shell.ts @@ -17,6 +17,7 @@ import { ToolConfirmationOutcome, } from './tools.js'; import { SchemaValidator } from '../utils/schemaValidator.js'; +import { getErrorMessage } from '../utils/errors.js'; export interface ShellToolParams { command: string; description?: string; @@ -249,8 +250,29 @@ export class ShellTool extends BaseTool { ].join('\n'); } - const returnDisplay = this.config.getDebugMode() ? llmContent : output; + let returnDisplayMessage = ''; + if (this.config.getDebugMode()) { + returnDisplayMessage = llmContent; + } else { + if (output.trim()) { + returnDisplayMessage = output; + } else { + // Output is empty, let's provide a reason if the command failed or was cancelled + if (abortSignal.aborted) { + returnDisplayMessage = 'Command cancelled by user.'; + } else if (processSignal) { + returnDisplayMessage = `Command terminated by signal: ${processSignal}`; + } else if (error) { + // If error is not null, it's an Error object (or other truthy value) + returnDisplayMessage = `Command failed: ${getErrorMessage(error)}`; + } else if (code !== null && code !== 0) { + returnDisplayMessage = `Command exited with code: ${code}`; + } + // If output is empty and command succeeded (code 0, no error/signal/abort), + // returnDisplayMessage will remain empty, which is fine. + } + } - return { llmContent, returnDisplay }; + return { llmContent, returnDisplay: returnDisplayMessage }; } }