From de83b7fa4c680886667af206d150c0dd9478e39d Mon Sep 17 00:00:00 2001 From: "Dhanji R. Prasanna" Date: Mon, 12 Jan 2026 20:20:41 +0530 Subject: [PATCH] Add visual spacing between text and tool calls in compact output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds blank line separation between text and tool calls for better readability: - Text → Tool: blank line before tool call - Tool → Text: blank line before text - Tool → Tool: no gap (stays tight) Implemented via two state tracking flags in ConsoleUiWriter: - last_output_was_text - last_output_was_tool Updated print_tool_output_header(), print_tool_compact(), and print_agent_response() to check and set these flags appropriately. --- crates/g3-cli/src/ui_writer_impl.rs | 37 ++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/crates/g3-cli/src/ui_writer_impl.rs b/crates/g3-cli/src/ui_writer_impl.rs index d6a0c4a..976784d 100644 --- a/crates/g3-cli/src/ui_writer_impl.rs +++ b/crates/g3-cli/src/ui_writer_impl.rs @@ -16,6 +16,10 @@ pub struct ConsoleUiWriter { is_shell_compact: std::sync::Mutex, /// Streaming markdown formatter for agent responses markdown_formatter: Mutex>, + /// Track if the last output was text (for spacing between text and tool calls) + last_output_was_text: std::sync::Mutex, + /// Track if the last output was a tool call (for spacing between tool calls and text) + last_output_was_tool: std::sync::Mutex, } impl ConsoleUiWriter { @@ -28,6 +32,8 @@ impl ConsoleUiWriter { is_agent_mode: std::sync::Mutex::new(false), is_shell_compact: std::sync::Mutex::new(false), markdown_formatter: Mutex::new(None), + last_output_was_text: std::sync::Mutex::new(false), + last_output_was_tool: std::sync::Mutex::new(false), } } } @@ -115,7 +121,15 @@ impl UiWriter for ConsoleUiWriter { } fn print_tool_output_header(&self) { - println!(); + // Add blank line if last output was text (for visual separation) + let mut last_was_text = self.last_output_was_text.lock().unwrap(); + if *last_was_text { + println!(); + } + *last_was_text = false; // We're now outputting a tool call + *self.last_output_was_tool.lock().unwrap() = true; + drop(last_was_text); // Release lock early + // Reset output_line_printed at the start of a new tool output // This ensures the header isn't cleared by update_tool_output_line *self.output_line_printed.lock().unwrap() = false; @@ -272,6 +286,14 @@ impl UiWriter for ConsoleUiWriter { return false; } + // Add blank line if last output was text (for visual separation) + let mut last_was_text = self.last_output_was_text.lock().unwrap(); + if *last_was_text { + println!(); + } + *last_was_text = false; // We're now outputting a tool call + *self.last_output_was_tool.lock().unwrap() = true; + let args = self.current_tool_args.lock().unwrap(); let is_agent_mode = *self.is_agent_mode.lock().unwrap(); @@ -447,8 +469,21 @@ impl UiWriter for ConsoleUiWriter { // Process the chunk through the formatter if let Some(ref mut formatter) = *formatter_guard { + // Add blank line if last output was a tool call (for visual separation) + // Only do this once at the start of new text content + let mut last_was_tool = self.last_output_was_tool.lock().unwrap(); + if *last_was_tool && !content.trim().is_empty() { + println!(); + *last_was_tool = false; + } + drop(last_was_tool); + let formatted = formatter.process(content); print!("{}", formatted); + // Track that we just output text (only if non-empty) + if !content.trim().is_empty() { + *self.last_output_was_text.lock().unwrap() = true; + } let _ = io::stdout().flush(); } }