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
This commit is contained in:
Taylor Mullen 2025-05-18 00:23:57 -07:00 committed by N. Taylor Mullen
parent a0eb8e67c7
commit 3aaeb44739
1 changed files with 24 additions and 2 deletions

View File

@ -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<ShellToolParams, ToolResult> {
].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 };
}
}