diff --git a/crates/g3-cli/src/lib.rs b/crates/g3-cli/src/lib.rs index 10251d4..d68083a 100644 --- a/crates/g3-cli/src/lib.rs +++ b/crates/g3-cli/src/lib.rs @@ -768,6 +768,8 @@ async fn run_agent_mode( // Create agent with custom system prompt let ui_writer = ConsoleUiWriter::new(); + // Set agent mode on UI writer for visual differentiation (royal blue tool names) + ui_writer.set_agent_mode(true); let mut agent = Agent::new_with_custom_prompt( config, ui_writer, @@ -1407,11 +1409,20 @@ fn read_project_readme(workspace_dir: &Path) -> Option { /// Extract the main heading or title from README content fn extract_readme_heading(readme_content: &str) -> Option { - // Process the content line by line, skipping the prefix line if present - let lines_iter = readme_content.lines(); - let mut content_lines = Vec::new(); + // Find the README section in the combined content + // The README section starts with "📚 Project README (from" + let readme_start = readme_content.find("📚 Project README (from"); - for line in lines_iter { + // If we can't find the README marker, the content might be just README + // or might not contain README at all + let content_to_search = match readme_start { + Some(pos) => &readme_content[pos..], + None => readme_content, + }; + + // Process the content line by line, skipping the prefix line + let mut content_lines = Vec::new(); + for line in content_to_search.lines() { // Skip the "📚 Project README (from ...):" line if line.starts_with("📚 Project README") { continue; diff --git a/crates/g3-cli/src/ui_writer_impl.rs b/crates/g3-cli/src/ui_writer_impl.rs index eabbab3..1f7f97f 100644 --- a/crates/g3-cli/src/ui_writer_impl.rs +++ b/crates/g3-cli/src/ui_writer_impl.rs @@ -9,6 +9,7 @@ pub struct ConsoleUiWriter { current_tool_args: std::sync::Mutex>, current_output_line: std::sync::Mutex>, output_line_printed: std::sync::Mutex, + is_agent_mode: std::sync::Mutex, } impl ConsoleUiWriter { @@ -18,6 +19,7 @@ impl ConsoleUiWriter { current_tool_args: std::sync::Mutex::new(Vec::new()), current_output_line: std::sync::Mutex::new(None), output_line_printed: std::sync::Mutex::new(false), + is_agent_mode: std::sync::Mutex::new(false), } } } @@ -109,7 +111,11 @@ impl UiWriter for ConsoleUiWriter { // 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; - // Now print the tool header with the most important arg in bold green + // Now print the tool header with the most important arg + // Use royal blue in agent mode, bold green otherwise + let is_agent_mode = *self.is_agent_mode.lock().unwrap(); + // Royal blue: \x1b[38;5;69m, Bold green: \x1b[1;32m + let tool_color = if is_agent_mode { "\x1b[1;38;5;69m" } else { "\x1b[1;32m" }; if let Some(tool_name) = self.current_tool_name.lock().unwrap().as_ref() { let args = self.current_tool_args.lock().unwrap(); @@ -162,14 +168,14 @@ impl UiWriter for ConsoleUiWriter { String::new() }; - // Print with bold green tool name, purple (non-bold) for pipe and args + // Print with tool name in color (royal blue for agent mode, green otherwise) println!( - "┌─\x1b[1;32m {}\x1b[0m\x1b[35m | {}{}\x1b[0m", - tool_name, display_value, header_suffix + "┌─{} {}\x1b[0m\x1b[35m | {}{}\x1b[0m", + tool_color, tool_name, display_value, header_suffix ); } else { - // Print with bold green formatting using ANSI escape codes - println!("┌─\x1b[1;32m {}\x1b[0m", tool_name); + // Print with tool name in color + println!("┌─{} {}\x1b[0m", tool_color, tool_name); } } } @@ -361,4 +367,8 @@ impl UiWriter for ConsoleUiWriter { // Reset the filter state for a new response reset_json_tool_state(); } + + fn set_agent_mode(&self, is_agent_mode: bool) { + *self.is_agent_mode.lock().unwrap() = is_agent_mode; + } } diff --git a/crates/g3-core/src/ui_writer.rs b/crates/g3-core/src/ui_writer.rs index ea69375..348b609 100644 --- a/crates/g3-core/src/ui_writer.rs +++ b/crates/g3-core/src/ui_writer.rs @@ -81,6 +81,11 @@ pub trait UiWriter: Send + Sync { /// Called at the start of a new response to clear any partial state. /// Default implementation does nothing. fn reset_json_filter(&self) {} + + /// Set whether the UI is in agent mode. + /// When in agent mode, tool names may be displayed differently (e.g., different color). + /// Default implementation does nothing. + fn set_agent_mode(&self, _is_agent_mode: bool) {} } /// A no-op implementation for when UI output is not needed