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:
@@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)),
|
||||||
|
|||||||
@@ -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)),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user