tool headers working
This commit is contained in:
@@ -40,6 +40,16 @@ pub enum TuiMessage {
|
|||||||
caption: String,
|
caption: String,
|
||||||
content: String,
|
content: String,
|
||||||
},
|
},
|
||||||
|
ToolDetailUpdate {
|
||||||
|
name: String,
|
||||||
|
content: String,
|
||||||
|
},
|
||||||
|
ToolComplete {
|
||||||
|
name: String,
|
||||||
|
success: bool,
|
||||||
|
duration_ms: u128,
|
||||||
|
caption: String,
|
||||||
|
},
|
||||||
SystemStatus(String),
|
SystemStatus(String),
|
||||||
ContextUpdate {
|
ContextUpdate {
|
||||||
used: u32,
|
used: u32,
|
||||||
@@ -60,6 +70,10 @@ struct TerminalState {
|
|||||||
scroll_offset: usize,
|
scroll_offset: usize,
|
||||||
/// Cursor blink state
|
/// Cursor blink state
|
||||||
cursor_blink: bool,
|
cursor_blink: bool,
|
||||||
|
/// Tool activity history (left side of activity box)
|
||||||
|
tool_activity: Vec<String>,
|
||||||
|
/// Tool activity scroll offset
|
||||||
|
tool_activity_scroll: usize,
|
||||||
/// Last known visible height of output area
|
/// Last known visible height of output area
|
||||||
last_visible_height: usize,
|
last_visible_height: usize,
|
||||||
/// User has manually scrolled (disable auto-scroll)
|
/// User has manually scrolled (disable auto-scroll)
|
||||||
@@ -80,6 +94,8 @@ struct TerminalState {
|
|||||||
is_processing: bool,
|
is_processing: bool,
|
||||||
/// Should exit
|
/// Should exit
|
||||||
should_exit: bool,
|
should_exit: bool,
|
||||||
|
/// Track the last tool header line index for updating it
|
||||||
|
last_tool_header_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalState {
|
impl TerminalState {
|
||||||
@@ -96,6 +112,8 @@ impl TerminalState {
|
|||||||
],
|
],
|
||||||
scroll_offset: 0,
|
scroll_offset: 0,
|
||||||
cursor_blink: true,
|
cursor_blink: true,
|
||||||
|
tool_activity: Vec::new(),
|
||||||
|
tool_activity_scroll: 0,
|
||||||
last_visible_height: 0, // Will be set on first draw
|
last_visible_height: 0, // Will be set on first draw
|
||||||
manual_scroll: false,
|
manual_scroll: false,
|
||||||
last_blink: Instant::now(),
|
last_blink: Instant::now(),
|
||||||
@@ -106,82 +124,31 @@ impl TerminalState {
|
|||||||
last_status_blink: Instant::now(),
|
last_status_blink: Instant::now(),
|
||||||
is_processing: false,
|
is_processing: false,
|
||||||
should_exit: false,
|
should_exit: false,
|
||||||
|
last_tool_header_index: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format tool call output with a box
|
/// Format tool call output
|
||||||
fn format_tool_output(&mut self, tool_name: &str, caption: &str, content: &str) {
|
fn format_tool_output(&mut self, tool_name: &str, caption: &str, content: &str) {
|
||||||
// Calculate box width (use a reasonable width, accounting for terminal size)
|
// Add tool header bar to main output
|
||||||
let box_width = 80;
|
|
||||||
let border_char = "─";
|
|
||||||
let corner_tl = "┌";
|
|
||||||
let corner_tr = "┐";
|
|
||||||
let corner_bl = "└";
|
|
||||||
let corner_br = "┘";
|
|
||||||
let vertical = "│";
|
|
||||||
|
|
||||||
// Add top border
|
|
||||||
self.output_history.push(format!(
|
|
||||||
"{}{}{}",
|
|
||||||
corner_tl,
|
|
||||||
border_char.repeat(box_width - 2),
|
|
||||||
corner_tr
|
|
||||||
));
|
|
||||||
|
|
||||||
// Add header with tool name (will be styled with green background in draw)
|
|
||||||
let header_text = format!(" {} | {}", tool_name.to_uppercase(), caption);
|
let header_text = format!(" {} | {}", tool_name.to_uppercase(), caption);
|
||||||
let padding = box_width - 2 - header_text.len();
|
|
||||||
self.output_history.push(format!(
|
|
||||||
"{}[TOOL_HEADER]{}{}{}",
|
|
||||||
vertical,
|
|
||||||
header_text,
|
|
||||||
" ".repeat(padding),
|
|
||||||
vertical
|
|
||||||
));
|
|
||||||
|
|
||||||
// Add separator between header and content
|
// Add marker for special styling
|
||||||
self.output_history.push(format!(
|
self.output_history.push(format!("[TOOL_HEADER]{}", header_text));
|
||||||
"{}{}{}",
|
|
||||||
"├",
|
|
||||||
border_char.repeat(box_width - 2),
|
|
||||||
"┤"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Add content lines
|
// Track the index of this tool header for later updates
|
||||||
|
self.last_tool_header_index = Some(self.output_history.len() - 1);
|
||||||
|
|
||||||
|
self.output_history.push(String::new()); // Empty line after header
|
||||||
|
|
||||||
|
// Add the actual tool content to the tool detail panel
|
||||||
|
self.tool_activity.clear(); // Clear previous activity
|
||||||
|
self.tool_activity.push(format!("[{}] {}", tool_name.to_uppercase(), caption));
|
||||||
|
self.tool_activity.push(String::new());
|
||||||
for line in content.lines() {
|
for line in content.lines() {
|
||||||
// Wrap long lines if needed
|
self.tool_activity.push(line.to_string());
|
||||||
let max_content_width = box_width - 4; // Account for borders and padding
|
|
||||||
if line.len() <= max_content_width {
|
|
||||||
self.output_history.push(format!(
|
|
||||||
"{} {:<width$} {}",
|
|
||||||
vertical,
|
|
||||||
line,
|
|
||||||
vertical,
|
|
||||||
width = max_content_width
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// Simple word wrapping for long lines
|
|
||||||
for chunk in line.chars().collect::<Vec<_>>().chunks(max_content_width) {
|
|
||||||
let chunk_str: String = chunk.iter().collect();
|
|
||||||
self.output_history.push(format!(
|
|
||||||
"{} {:<width$} {}",
|
|
||||||
vertical,
|
|
||||||
chunk_str,
|
|
||||||
vertical,
|
|
||||||
width = max_content_width
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
self.tool_activity_scroll = 0; // Reset scroll when new content arrives
|
||||||
}
|
|
||||||
|
|
||||||
// Add bottom border
|
|
||||||
self.output_history.push(format!(
|
|
||||||
"{}{}{}",
|
|
||||||
corner_bl,
|
|
||||||
border_char.repeat(box_width - 2),
|
|
||||||
corner_br
|
|
||||||
));
|
|
||||||
self.output_history.push(String::new()); // Empty line after box
|
|
||||||
|
|
||||||
// Auto-scroll to bottom only if user hasn't manually scrolled
|
// Auto-scroll to bottom only if user hasn't manually scrolled
|
||||||
if !self.manual_scroll {
|
if !self.manual_scroll {
|
||||||
@@ -203,6 +170,46 @@ impl TerminalState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update tool header with completion status and timing
|
||||||
|
fn update_tool_completion(&mut self, name: &str, success: bool, duration_ms: u128, caption: &str) {
|
||||||
|
// Find and update the last tool header in place
|
||||||
|
if let Some(index) = self.last_tool_header_index {
|
||||||
|
if index < self.output_history.len() {
|
||||||
|
// Format the timing info
|
||||||
|
let timing = if duration_ms < 1000 {
|
||||||
|
format!("{}ms", duration_ms)
|
||||||
|
} else {
|
||||||
|
format!("{:.2}s", duration_ms as f64 / 1000.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the updated header with status marker and timing
|
||||||
|
let status_marker = if success { "[SUCCESS]" } else { "[FAILED]" };
|
||||||
|
let header_text = format!(" {} | {} | {}", name.to_uppercase(), caption, timing);
|
||||||
|
|
||||||
|
// Replace the existing header line with the updated one
|
||||||
|
self.output_history[index] = format!("{}{}", status_marker, header_text);
|
||||||
|
|
||||||
|
// Clear the tracking index
|
||||||
|
self.last_tool_header_index = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update tool detail panel without changing the header
|
||||||
|
fn update_tool_detail(&mut self, name: &str, content: &str) {
|
||||||
|
// Update the tool detail panel with the complete content
|
||||||
|
self.tool_activity.clear();
|
||||||
|
self.tool_activity.push(format!("[{}] Complete", name.to_uppercase()));
|
||||||
|
self.tool_activity.push(String::new());
|
||||||
|
|
||||||
|
// Add all the content lines
|
||||||
|
for line in content.lines() {
|
||||||
|
self.tool_activity.push(line.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tool_activity_scroll = 0; // Reset scroll when new content arrives
|
||||||
|
}
|
||||||
|
|
||||||
/// Add text to output history
|
/// Add text to output history
|
||||||
fn add_output(&mut self, text: &str) {
|
fn add_output(&mut self, text: &str) {
|
||||||
let mut lines = text.lines();
|
let mut lines = text.lines();
|
||||||
@@ -319,6 +326,20 @@ impl RetroTui {
|
|||||||
} => {
|
} => {
|
||||||
state.format_tool_output(&name, &caption, &content);
|
state.format_tool_output(&name, &caption, &content);
|
||||||
}
|
}
|
||||||
|
TuiMessage::ToolDetailUpdate {
|
||||||
|
name,
|
||||||
|
content,
|
||||||
|
} => {
|
||||||
|
state.update_tool_detail(&name, &content);
|
||||||
|
}
|
||||||
|
TuiMessage::ToolComplete {
|
||||||
|
name,
|
||||||
|
success,
|
||||||
|
duration_ms,
|
||||||
|
caption,
|
||||||
|
} => {
|
||||||
|
state.update_tool_completion(&name, success, duration_ms, &caption);
|
||||||
|
}
|
||||||
TuiMessage::SystemStatus(status) => {
|
TuiMessage::SystemStatus(status) => {
|
||||||
let was_processing = state.status_line == "PROCESSING";
|
let was_processing = state.status_line == "PROCESSING";
|
||||||
state.status_line = status;
|
state.status_line = status;
|
||||||
@@ -418,7 +439,8 @@ impl RetroTui {
|
|||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([
|
.constraints([
|
||||||
Constraint::Length(5), // Header/input area
|
Constraint::Length(5), // Header/input area
|
||||||
Constraint::Min(10), // Main output area
|
Constraint::Min(10), // Main output area (will be further split)
|
||||||
|
Constraint::Length(8), // Activity area
|
||||||
Constraint::Length(1), // Status bar
|
Constraint::Length(1), // Status bar
|
||||||
])
|
])
|
||||||
.split(size);
|
.split(size);
|
||||||
@@ -449,10 +471,13 @@ impl RetroTui {
|
|||||||
// Draw main output area
|
// Draw main output area
|
||||||
Self::draw_output_area(f, chunks[1], &state.output_history, state.scroll_offset);
|
Self::draw_output_area(f, chunks[1], &state.output_history, state.scroll_offset);
|
||||||
|
|
||||||
|
// Draw activity area (tool output)
|
||||||
|
Self::draw_activity_area(f, chunks[2], &state.tool_activity, state.tool_activity_scroll);
|
||||||
|
|
||||||
// Draw status bar
|
// Draw status bar
|
||||||
Self::draw_status_bar(
|
Self::draw_status_bar(
|
||||||
f,
|
f,
|
||||||
chunks[2],
|
chunks[3],
|
||||||
&state.status_line,
|
&state.status_line,
|
||||||
state.context_info,
|
state.context_info,
|
||||||
&state.provider_info,
|
&state.provider_info,
|
||||||
@@ -521,10 +546,21 @@ impl RetroTui {
|
|||||||
.take(visible_height)
|
.take(visible_height)
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
// Check if this is a tool header line
|
// Check if this is a tool header line
|
||||||
if line.contains("[TOOL_HEADER]") {
|
if line.starts_with("[TOOL_HEADER]") {
|
||||||
// Extract the actual header text
|
// Extract the actual header text
|
||||||
let cleaned = line.replace("[TOOL_HEADER]", "");
|
let cleaned = line.replace("[TOOL_HEADER]", "");
|
||||||
// Style with green background and black text
|
// Style with amber background and black text
|
||||||
|
return Line::from(Span::styled(
|
||||||
|
format!(" {}", cleaned),
|
||||||
|
Style::default()
|
||||||
|
.bg(TERMINAL_AMBER)
|
||||||
|
.fg(Color::Black)
|
||||||
|
.add_modifier(Modifier::BOLD),
|
||||||
|
));
|
||||||
|
} else if line.starts_with("[SUCCESS]") {
|
||||||
|
// Extract the actual header text
|
||||||
|
let cleaned = line.replace("[SUCCESS]", "");
|
||||||
|
// Style with green background for successful tool completion
|
||||||
return Line::from(Span::styled(
|
return Line::from(Span::styled(
|
||||||
format!(" {}", cleaned),
|
format!(" {}", cleaned),
|
||||||
Style::default()
|
Style::default()
|
||||||
@@ -532,6 +568,17 @@ impl RetroTui {
|
|||||||
.fg(Color::Black)
|
.fg(Color::Black)
|
||||||
.add_modifier(Modifier::BOLD),
|
.add_modifier(Modifier::BOLD),
|
||||||
));
|
));
|
||||||
|
} else if line.starts_with("[FAILED]") {
|
||||||
|
// Extract the actual header text
|
||||||
|
let cleaned = line.replace("[FAILED]", "");
|
||||||
|
// Style with red background for failed tool completion
|
||||||
|
return Line::from(Span::styled(
|
||||||
|
format!(" {}", cleaned),
|
||||||
|
Style::default()
|
||||||
|
.bg(TERMINAL_RED)
|
||||||
|
.fg(Color::Black)
|
||||||
|
.add_modifier(Modifier::BOLD),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a box border line
|
// Check if this is a box border line
|
||||||
@@ -610,6 +657,88 @@ impl RetroTui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw the activity area with tool output
|
||||||
|
fn draw_activity_area(
|
||||||
|
f: &mut Frame,
|
||||||
|
area: Rect,
|
||||||
|
tool_activity: &[String],
|
||||||
|
scroll_offset: usize,
|
||||||
|
) {
|
||||||
|
// Split the activity area into left and right halves
|
||||||
|
let chunks = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints([
|
||||||
|
Constraint::Percentage(50), // Left half for tool output
|
||||||
|
Constraint::Percentage(50), // Right half (reserved for future use)
|
||||||
|
])
|
||||||
|
.split(area);
|
||||||
|
|
||||||
|
// Draw left half - Tool Activity
|
||||||
|
let visible_height = chunks[0].height.saturating_sub(2) as usize; // Account for borders
|
||||||
|
let total_lines = tool_activity.len();
|
||||||
|
|
||||||
|
// Calculate scroll position
|
||||||
|
let scroll = if total_lines <= visible_height {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
scroll_offset.min(total_lines.saturating_sub(visible_height))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get visible lines for tool activity
|
||||||
|
let visible_lines: Vec<Line> = if tool_activity.is_empty() {
|
||||||
|
vec![Line::from(Span::styled(
|
||||||
|
" No tool activity yet",
|
||||||
|
Style::default().fg(TERMINAL_DIM_GREEN).add_modifier(Modifier::ITALIC),
|
||||||
|
))]
|
||||||
|
} else {
|
||||||
|
tool_activity
|
||||||
|
.iter()
|
||||||
|
.skip(scroll)
|
||||||
|
.take(visible_height)
|
||||||
|
.map(|line| {
|
||||||
|
// Style the header lines differently
|
||||||
|
let style = if line.starts_with('[') && line.contains(']') {
|
||||||
|
Style::default().fg(TERMINAL_CYAN).add_modifier(Modifier::BOLD)
|
||||||
|
} else if line.is_empty() {
|
||||||
|
Style::default()
|
||||||
|
} else {
|
||||||
|
Style::default().fg(TERMINAL_GREEN)
|
||||||
|
};
|
||||||
|
Line::from(Span::styled(format!(" {}", line), style))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
let tool_output = Paragraph::new(visible_lines)
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.title(" TOOL DETAIL ")
|
||||||
|
.title_alignment(Alignment::Center)
|
||||||
|
.borders(Borders::ALL)
|
||||||
|
.border_style(Style::default().fg(TERMINAL_DIM_GREEN))
|
||||||
|
.style(Style::default().bg(TERMINAL_BG)),
|
||||||
|
)
|
||||||
|
.wrap(Wrap { trim: false });
|
||||||
|
|
||||||
|
f.render_widget(tool_output, chunks[0]);
|
||||||
|
|
||||||
|
// Draw right half - Activity
|
||||||
|
let reserved = Paragraph::new(vec![Line::from(Span::styled(
|
||||||
|
" Activity log will appear here",
|
||||||
|
Style::default().fg(TERMINAL_DIM_GREEN).add_modifier(Modifier::ITALIC),
|
||||||
|
))])
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.title(" ACTIVITY ")
|
||||||
|
.title_alignment(Alignment::Center)
|
||||||
|
.borders(Borders::ALL)
|
||||||
|
.border_style(Style::default().fg(TERMINAL_DIM_GREEN))
|
||||||
|
.style(Style::default().bg(TERMINAL_BG)),
|
||||||
|
);
|
||||||
|
|
||||||
|
f.render_widget(reserved, chunks[1]);
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw the status bar
|
/// Draw the status bar
|
||||||
fn draw_status_bar(
|
fn draw_status_bar(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
@@ -706,6 +835,24 @@ impl RetroTui {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update tool detail panel without changing the header
|
||||||
|
pub fn update_tool_detail(&self, name: &str, content: &str) {
|
||||||
|
let _ = self.tx.send(TuiMessage::ToolDetailUpdate {
|
||||||
|
name: name.to_string(),
|
||||||
|
content: content.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send tool completion status to the terminal
|
||||||
|
pub fn tool_complete(&self, name: &str, success: bool, duration_ms: u128, caption: &str) {
|
||||||
|
let _ = self.tx.send(TuiMessage::ToolComplete {
|
||||||
|
name: name.to_string(),
|
||||||
|
success,
|
||||||
|
duration_ms,
|
||||||
|
caption: caption.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Update system status
|
/// Update system status
|
||||||
pub fn status(&self, status: &str) {
|
pub fn status(&self, status: &str) {
|
||||||
let _ = self.tx.send(TuiMessage::SystemStatus(status.to_string()));
|
let _ = self.tx.send(TuiMessage::SystemStatus(status.to_string()));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::retro_tui::RetroTui;
|
use crate::retro_tui::RetroTui;
|
||||||
use g3_core::ui_writer::UiWriter;
|
use g3_core::ui_writer::UiWriter;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use std::time::Instant;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
/// Console implementation of UiWriter that prints to stdout
|
/// Console implementation of UiWriter that prints to stdout
|
||||||
@@ -87,6 +88,8 @@ pub struct RetroTuiWriter {
|
|||||||
tui: RetroTui,
|
tui: RetroTui,
|
||||||
current_tool_name: Mutex<Option<String>>,
|
current_tool_name: Mutex<Option<String>>,
|
||||||
current_tool_output: Mutex<Vec<String>>,
|
current_tool_output: Mutex<Vec<String>>,
|
||||||
|
current_tool_start: Mutex<Option<Instant>>,
|
||||||
|
current_tool_caption: Mutex<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RetroTuiWriter {
|
impl RetroTuiWriter {
|
||||||
@@ -95,6 +98,8 @@ impl RetroTuiWriter {
|
|||||||
tui,
|
tui,
|
||||||
current_tool_name: Mutex::new(None),
|
current_tool_name: Mutex::new(None),
|
||||||
current_tool_output: Mutex::new(Vec::new()),
|
current_tool_output: Mutex::new(Vec::new()),
|
||||||
|
current_tool_start: Mutex::new(None),
|
||||||
|
current_tool_caption: Mutex::new(String::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,12 +134,16 @@ impl UiWriter for RetroTuiWriter {
|
|||||||
|
|
||||||
fn print_tool_header(&self, tool_name: &str) {
|
fn print_tool_header(&self, tool_name: &str) {
|
||||||
// Start collecting tool output
|
// Start collecting tool output
|
||||||
|
*self.current_tool_start.lock().unwrap() = Some(Instant::now());
|
||||||
*self.current_tool_name.lock().unwrap() = Some(tool_name.to_string());
|
*self.current_tool_name.lock().unwrap() = Some(tool_name.to_string());
|
||||||
self.current_tool_output.lock().unwrap().clear();
|
self.current_tool_output.lock().unwrap().clear();
|
||||||
self.current_tool_output
|
self.current_tool_output
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push(format!("Tool: {}", tool_name));
|
.push(format!("Tool: {}", tool_name));
|
||||||
|
|
||||||
|
// Initialize caption
|
||||||
|
*self.current_tool_caption.lock().unwrap() = String::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_arg(&self, key: &str, value: &str) {
|
fn print_tool_arg(&self, key: &str, value: &str) {
|
||||||
@@ -142,9 +151,31 @@ impl UiWriter for RetroTuiWriter {
|
|||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push(format!("{}: {}", key, value));
|
.push(format!("{}: {}", key, value));
|
||||||
|
|
||||||
|
// Build caption from first argument (usually the most important one)
|
||||||
|
let mut caption = self.current_tool_caption.lock().unwrap();
|
||||||
|
if caption.is_empty() && (key == "file_path" || key == "command" || key == "path") {
|
||||||
|
// Truncate long values for the caption
|
||||||
|
let truncated = if value.len() > 50 { format!("{}...", &value[..47]) } else { value.to_string() };
|
||||||
|
*caption = truncated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_output_header(&self) {
|
fn print_tool_output_header(&self) {
|
||||||
|
// This is called right before tool execution starts
|
||||||
|
// Send the initial tool header to the TUI now
|
||||||
|
if let Some(tool_name) = self.current_tool_name.lock().unwrap().as_ref() {
|
||||||
|
let caption = self.current_tool_caption.lock().unwrap().clone();
|
||||||
|
let caption = if caption.is_empty() { "Executing...".to_string() } else { caption };
|
||||||
|
|
||||||
|
// Send the tool output with initial header
|
||||||
|
self.tui.tool_output(
|
||||||
|
tool_name,
|
||||||
|
&caption,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
self.current_tool_output.lock().unwrap().push(String::new());
|
self.current_tool_output.lock().unwrap().push(String::new());
|
||||||
self.current_tool_output
|
self.current_tool_output
|
||||||
.lock()
|
.lock()
|
||||||
@@ -173,15 +204,36 @@ impl UiWriter for RetroTuiWriter {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.push(format!("⚡️ {}", duration_str));
|
.push(format!("⚡️ {}", duration_str));
|
||||||
|
|
||||||
// Now send the complete tool output as a box
|
// Calculate the actual duration
|
||||||
|
let duration_ms = if let Some(start) = *self.current_tool_start.lock().unwrap() {
|
||||||
|
start.elapsed().as_millis()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the tool name and caption
|
||||||
if let Some(tool_name) = self.current_tool_name.lock().unwrap().as_ref() {
|
if let Some(tool_name) = self.current_tool_name.lock().unwrap().as_ref() {
|
||||||
let content = self.current_tool_output.lock().unwrap().join("\n");
|
let content = self.current_tool_output.lock().unwrap().join("\n");
|
||||||
self.tui.tool_output(tool_name, "...", &content);
|
let caption = self.current_tool_caption.lock().unwrap().clone();
|
||||||
|
let caption = if caption.is_empty() { "Completed".to_string() } else { caption };
|
||||||
|
|
||||||
|
// Update the tool detail panel with the complete output without adding a new header
|
||||||
|
// This keeps the original header in place to be updated by tool_complete
|
||||||
|
self.tui.update_tool_detail(tool_name, &content);
|
||||||
|
|
||||||
|
// Determine success based on whether there's an error in the output
|
||||||
|
// This is a simple heuristic - you might want to make this more sophisticated
|
||||||
|
let success = !content.contains("error") && !content.contains("Error") && !content.contains("ERROR");
|
||||||
|
|
||||||
|
// Send the completion status to update the header
|
||||||
|
self.tui.tool_complete(tool_name, success, duration_ms, &caption);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the buffers
|
// Clear the buffers
|
||||||
*self.current_tool_name.lock().unwrap() = None;
|
*self.current_tool_name.lock().unwrap() = None;
|
||||||
self.current_tool_output.lock().unwrap().clear();
|
self.current_tool_output.lock().unwrap().clear();
|
||||||
|
*self.current_tool_start.lock().unwrap() = None;
|
||||||
|
*self.current_tool_caption.lock().unwrap() = String::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_agent_prompt(&self) {
|
fn print_agent_prompt(&self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user