Improve tool output formatting

1. str_replace: Show insertion/deletion counts with colors
   " +N insertions | -M deletions" (green/red)

2. write_file: Compact format with human-readable sizes
   " wrote N lines | Xk chars"

3. read_file: Cleaner format
   "🔍 N lines read" instead of "📄 File content (N lines)"

4. webdriver_quit: Show correct driver name (safaridriver vs chromedriver)

5. read_file: When start position exceeds file length, read last 100 chars
   with explanation instead of failing

6. shell: Remove redundant "Command failed:" prefix from error messages
This commit is contained in:
Dhanji R. Prasanna
2026-01-11 19:52:00 +05:30
parent 7c960875ef
commit ed1c31dd70
3 changed files with 45 additions and 17 deletions

View File

@@ -99,10 +99,16 @@ pub async fn execute_read_file<W: UiWriter>(
// Validate user-specified range // Validate user-specified range
let user_start = start_char.unwrap_or(0); let user_start = start_char.unwrap_or(0);
if user_start > total_file_len { if user_start > total_file_len {
// Start exceeds file length - read last 100 chars instead
let fallback_start = total_file_len.saturating_sub(100);
let fallback_content = &content[fallback_start..];
let line_count = fallback_content.lines().count();
return Ok(format!( return Ok(format!(
" Start position {} exceeds file length {}", "⚠️ Start position {} exceeds file length {}. Reading last {} chars instead.\n\
user_start, 🔍 {} lines read (chars {}-{}):\n{}",
total_file_len user_start, total_file_len,
total_file_len - fallback_start,
line_count, fallback_start, total_file_len, fallback_content
)); ));
} }
@@ -158,18 +164,18 @@ pub async fn execute_read_file<W: UiWriter>(
// Token-aware truncation header // Token-aware truncation header
let context_pct = (ctx.context_used_tokens as f32 / ctx.context_total_tokens as f32 * 100.0) as u32; let context_pct = (ctx.context_used_tokens as f32 / ctx.context_total_tokens as f32 * 100.0) as u32;
Ok(format!( Ok(format!(
"⚠️ FILE TRUNCATED: Reading chars {}-{} of {} total (file exceeds 20% context window threshold, context at {}%)\n\ "⚠️ TRUNCATED: chars {}-{} of {} (exceeds 20% context, at {}%)\n\
📄 File content ({} lines of {} total):\n{}", 🔍 {} lines read:\n{}",
start_boundary, end_boundary, total_file_len, context_pct, start_boundary, end_boundary, total_file_len, context_pct,
line_count, total_lines, partial_content line_count, partial_content
)) ))
} else if start_char.is_some() || end_char.is_some() { } else if start_char.is_some() || end_char.is_some() {
Ok(format!( Ok(format!(
"📄 File content (chars {}-{}, {} lines of {} total):\n{}", "🔍 {} lines read (chars {}-{}):\n{}",
start_boundary, end_boundary, line_count, total_lines, partial_content line_count, start_boundary, end_boundary, partial_content
)) ))
} else { } else {
Ok(format!("📄 File content ({} lines):\n{}", line_count, content)) Ok(format!("🔍 {} lines read:\n{}", line_count, content))
} }
} }
Err(e) => Ok(format!("❌ Failed to read file '{}': {}", path_str, e)), Err(e) => Ok(format!("❌ Failed to read file '{}': {}", path_str, e)),
@@ -331,9 +337,14 @@ pub async fn execute_write_file<W: UiWriter>(
Ok(()) => { Ok(()) => {
let line_count = content.lines().count(); let line_count = content.lines().count();
let char_count = content.len(); let char_count = content.len();
let char_display = if char_count >= 1000 {
format!("{:.1}k", char_count as f64 / 1000.0)
} else {
format!("{}", char_count)
};
Ok(format!( Ok(format!(
" Successfully wrote {} lines ({} characters)", "✅ wrote {} lines | {} chars",
line_count, char_count line_count, char_display
)) ))
} }
Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", path, e)), Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", path, e)),
@@ -405,9 +416,20 @@ pub async fn execute_str_replace<W: UiWriter>(
Err(e) => return Ok(format!("{}", e)), Err(e) => return Ok(format!("{}", e)),
}; };
// Count insertions and deletions from the diff
let mut insertions = 0;
let mut deletions = 0;
for line in diff.lines() {
if line.starts_with('+') && !line.starts_with("+++") {
insertions += 1;
} else if line.starts_with('-') && !line.starts_with("---") {
deletions += 1;
}
}
// Write the result back to the file // Write the result back to the file
match std::fs::write(&file_path, &result) { match std::fs::write(&file_path, &result) {
Ok(()) => Ok("✅ applied unified diff".to_string()), Ok(()) => Ok(format!("\x1b[32m+{} insertions\x1b[0m | \x1b[31m-{} deletions\x1b[0m", insertions, deletions)),
Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", file_path, e)), Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", file_path, e)),
} }
} }

View File

@@ -61,7 +61,7 @@ pub async fn execute_shell<W: UiWriter>(tool_call: &ToolCall, ctx: &ToolContext<
result.stdout.trim().to_string() result.stdout.trim().to_string()
}) })
} else { } else {
Ok(format!(" Command failed: {}", result.stderr.trim())) Ok(format!("{}", result.stderr.trim()))
} }
} }
Err(e) => Ok(format!("❌ Execution error: {}", e)), Err(e) => Ok(format!("❌ Execution error: {}", e)),

View File

@@ -599,16 +599,22 @@ pub async fn execute_webdriver_quit<W: UiWriter>(
Ok(_) => { Ok(_) => {
debug!("WebDriver session closed successfully"); debug!("WebDriver session closed successfully");
// Kill the safaridriver process // Kill the driver process
if let Some(mut process) = ctx.webdriver_process.write().await.take() { if let Some(mut process) = ctx.webdriver_process.write().await.take() {
if let Err(e) = process.kill().await { if let Err(e) = process.kill().await {
warn!("Failed to kill safaridriver process: {}", e); warn!("Failed to kill driver process: {}", e);
} else { } else {
debug!("Safaridriver process terminated"); debug!("Driver process terminated");
} }
} }
Ok("✅ WebDriver session closed and safaridriver stopped".to_string()) // Return appropriate message based on browser type
use g3_config::WebDriverBrowser;
let driver_name = match &ctx.config.webdriver.browser {
WebDriverBrowser::Safari => "safaridriver",
WebDriverBrowser::ChromeHeadless => "chromedriver",
};
Ok(format!("✅ WebDriver session closed and {} stopped", driver_name))
} }
Err(e) => Ok(format!("❌ Failed to quit WebDriver: {}", e)), Err(e) => Ok(format!("❌ Failed to quit WebDriver: {}", e)),
} }