UI writer abstraction instead of printlns everywhere

This commit is contained in:
Dhanji Prasanna
2025-10-02 11:06:14 +10:00
parent e324ddd99d
commit 8c7dd146f8
5 changed files with 200 additions and 49 deletions

View File

@@ -1,7 +1,7 @@
use anyhow::Result;
use clap::Parser;
use g3_config::Config;
use g3_core::{project::Project, Agent};
use g3_core::{project::Project, Agent, ui_writer::UiWriter};
use rustyline::error::ReadlineError;
use rustyline::DefaultEditor;
use std::path::PathBuf;
@@ -9,7 +9,9 @@ use tokio_util::sync::CancellationToken;
use tracing::{error, info};
mod tui;
mod ui_writer_impl;
use tui::SimpleOutput;
use ui_writer_impl::ConsoleUiWriter;
#[derive(Parser)]
#[command(name = "g3")]
@@ -108,7 +110,8 @@ pub async fn run() -> Result<()> {
let config = Config::load(cli.config.as_deref())?;
// Initialize agent
let mut agent = Agent::new(config).await?;
let ui_writer = ConsoleUiWriter::new();
let mut agent = Agent::new(config, ui_writer).await?;
// Execute task, autonomous mode, or start interactive mode
if cli.autonomous {
@@ -141,7 +144,7 @@ pub async fn run() -> Result<()> {
Ok(())
}
async fn run_interactive(mut agent: Agent, show_prompt: bool, show_code: bool) -> Result<()> {
async fn run_interactive<W: UiWriter>(mut agent: Agent<W>, show_prompt: bool, show_code: bool) -> Result<()> {
let output = SimpleOutput::new();
output.print("");
@@ -278,7 +281,7 @@ async fn run_interactive(mut agent: Agent, show_prompt: bool, show_code: bool) -
Ok(())
}
async fn execute_task(agent: &mut Agent, input: &str, show_prompt: bool, show_code: bool, output: &SimpleOutput) {
async fn execute_task<W: UiWriter>(agent: &mut Agent<W>, input: &str, show_prompt: bool, show_code: bool, output: &SimpleOutput) {
// Show thinking indicator immediately
output.print("🤔 Thinking...");
// Note: flush is handled internally by println
@@ -337,7 +340,7 @@ async fn execute_task(agent: &mut Agent, input: &str, show_prompt: bool, show_co
}
}
fn display_context_progress(agent: &Agent, output: &SimpleOutput) {
fn display_context_progress<W: UiWriter>(agent: &Agent<W>, output: &SimpleOutput) {
let context = agent.get_context_window();
output.print_context(context.used_tokens, context.total_tokens, context.percentage_used());
}
@@ -369,7 +372,7 @@ fn setup_workspace_directory() -> Result<PathBuf> {
// Simplified autonomous mode implementation
async fn run_autonomous(
mut agent: Agent,
mut agent: Agent<ConsoleUiWriter>,
project: Project,
show_prompt: bool,
show_code: bool,
@@ -443,7 +446,8 @@ async fn run_autonomous(
// Create a new agent instance for coach mode to ensure fresh context
let config = g3_config::Config::load(None)?;
let mut coach_agent = Agent::new(config).await?;
let ui_writer = ConsoleUiWriter::new();
let mut coach_agent = Agent::new(config, ui_writer).await?;
// Ensure coach agent is also in the workspace directory
project.enter_workspace()?;

View File

@@ -0,0 +1,81 @@
use g3_core::ui_writer::UiWriter;
use std::io::{self, Write};
/// Console implementation of UiWriter that prints to stdout
pub struct ConsoleUiWriter;
impl ConsoleUiWriter {
pub fn new() -> Self {
Self
}
}
impl UiWriter for ConsoleUiWriter {
fn print(&self, message: &str) {
println!("{}", message);
}
fn println(&self, message: &str) {
println!("{}", message);
}
fn print_inline(&self, message: &str) {
print!("{}", message);
let _ = io::stdout().flush();
}
fn print_system_prompt(&self, prompt: &str) {
println!("🔍 System Prompt:");
println!("================");
println!("{}", prompt);
println!("================");
println!();
}
fn print_context_status(&self, message: &str) {
println!("{}", message);
}
fn print_tool_header(&self, tool_name: &str) {
println!("┌─ {}", tool_name);
}
fn print_tool_arg(&self, key: &str, value: &str) {
println!("{}: {}", key, value);
}
fn print_tool_output_header(&self) {
println!("├─ output:");
}
fn print_tool_output_line(&self, line: &str) {
println!("{}", line);
}
fn print_tool_output_summary(&self, hidden_count: usize) {
println!(
"│ ... ({} more line{} hidden)",
hidden_count,
if hidden_count == 1 { "" } else { "s" }
);
}
fn print_tool_timing(&self, duration_str: &str) {
println!("└─ ⚡️ {}", duration_str);
println!();
}
fn print_agent_prompt(&self) {
print!("🤖 ");
let _ = io::stdout().flush();
}
fn print_agent_response(&self, content: &str) {
print!("{}", content);
let _ = io::stdout().flush();
}
fn flush(&self) {
let _ = io::stdout().flush();
}
}