shared active tools: Agent writes, TUI reads directly
Move active tool tracking from TUI message-passing to shared Arc<RwLock> state. Agent pushes on dispatch, removes on apply_tool_result. TUI reads during render. Background tasks show as active until drained at next turn start. Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
d25033b9f4
commit
474b66c834
6 changed files with 62 additions and 49 deletions
|
|
@ -168,7 +168,7 @@ impl App {
|
|||
)));
|
||||
lines.push(Line::raw(format!(" Reasoning: {}", self.reasoning_effort)));
|
||||
lines.push(Line::raw(format!(" Running processes: {}", self.running_processes)));
|
||||
lines.push(Line::raw(format!(" Active tools: {}", self.active_tools.len())));
|
||||
lines.push(Line::raw(format!(" Active tools: {}", self.active_tools.read().unwrap().len())));
|
||||
|
||||
let block = Block::default()
|
||||
.title_top(Line::from(SCREEN_LEGEND).left_aligned())
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ impl App {
|
|||
/// Draw the main (F1) screen — four-pane layout with status bar.
|
||||
pub(crate) fn draw_main(&mut self, frame: &mut Frame, size: Rect) {
|
||||
// Main layout: content area + active tools overlay + status bar
|
||||
let tool_lines = self.active_tools.len() as u16;
|
||||
let active_tools = self.active_tools.read().unwrap();
|
||||
let tool_lines = active_tools.len() as u16;
|
||||
let main_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
|
|
@ -107,9 +108,9 @@ impl App {
|
|||
frame.render_widget(&self.textarea, input_chunks[1]);
|
||||
|
||||
// Draw active tools overlay
|
||||
if !self.active_tools.is_empty() {
|
||||
if !active_tools.is_empty() {
|
||||
let tool_style = Style::default().fg(Color::Yellow).add_modifier(Modifier::DIM);
|
||||
let tool_text: Vec<Line> = self.active_tools.iter().map(|t| {
|
||||
let tool_text: Vec<Line> = active_tools.iter().map(|t| {
|
||||
let elapsed = t.started.elapsed().as_secs();
|
||||
let line = if t.detail.is_empty() {
|
||||
format!(" [{}] ({}s)", t.name, elapsed)
|
||||
|
|
|
|||
|
|
@ -308,12 +308,8 @@ pub(crate) fn parse_markdown(md: &str) -> Vec<Line<'static>> {
|
|||
}
|
||||
|
||||
/// A tool call currently in flight — shown above the status bar.
|
||||
pub(crate) struct ActiveTool {
|
||||
pub(crate) id: String,
|
||||
pub(crate) name: String,
|
||||
pub(crate) detail: String,
|
||||
pub(crate) started: std::time::Instant,
|
||||
}
|
||||
// ActiveTool moved to ui_channel — shared between Agent and TUI
|
||||
pub(crate) use crate::user::ui_channel::ActiveTool;
|
||||
|
||||
/// Main TUI application state.
|
||||
pub struct App {
|
||||
|
|
@ -335,7 +331,7 @@ pub struct App {
|
|||
pub running_processes: u32,
|
||||
/// Current reasoning effort level (for status display).
|
||||
pub reasoning_effort: String,
|
||||
pub(crate) active_tools: Vec<ActiveTool>,
|
||||
pub(crate) active_tools: crate::user::ui_channel::SharedActiveTools,
|
||||
pub(crate) active_pane: ActivePane,
|
||||
/// User input editor (handles wrapping, cursor positioning).
|
||||
pub textarea: tui_textarea::TextArea<'static>,
|
||||
|
|
@ -422,7 +418,7 @@ pub enum HotkeyAction {
|
|||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(model: String, shared_context: SharedContextState) -> Self {
|
||||
pub fn new(model: String, shared_context: SharedContextState, active_tools: crate::user::ui_channel::SharedActiveTools) -> Self {
|
||||
Self {
|
||||
autonomous: PaneState::new(true), // markdown
|
||||
conversation: PaneState::new(true), // markdown
|
||||
|
|
@ -444,7 +440,7 @@ impl App {
|
|||
needs_assistant_marker: false,
|
||||
running_processes: 0,
|
||||
reasoning_effort: "none".to_string(),
|
||||
active_tools: Vec::new(),
|
||||
active_tools,
|
||||
active_pane: ActivePane::Conversation,
|
||||
textarea: new_textarea(vec![String::new()]),
|
||||
input_history: Vec::new(),
|
||||
|
|
@ -548,17 +544,8 @@ impl App {
|
|||
self.autonomous.current_color = Color::DarkGray;
|
||||
self.autonomous.append_text(&text);
|
||||
}
|
||||
UiMessage::ToolStarted { id, name, detail } => {
|
||||
self.active_tools.push(ActiveTool {
|
||||
id,
|
||||
name,
|
||||
detail,
|
||||
started: std::time::Instant::now(),
|
||||
});
|
||||
}
|
||||
UiMessage::ToolFinished { id } => {
|
||||
self.active_tools.retain(|t| t.id != id);
|
||||
}
|
||||
UiMessage::ToolStarted { .. } => {} // handled by shared active_tools
|
||||
UiMessage::ToolFinished { .. } => {}
|
||||
UiMessage::Debug(text) => {
|
||||
self.tools.push_line(format!("[debug] {}", text), Color::DarkGray);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,22 @@ pub fn shared_context_state() -> SharedContextState {
|
|||
Arc::new(RwLock::new(Vec::new()))
|
||||
}
|
||||
|
||||
/// Active tool info for TUI display.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ActiveTool {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub detail: String,
|
||||
pub started: std::time::Instant,
|
||||
}
|
||||
|
||||
/// Shared active tools — agent writes, TUI reads.
|
||||
pub type SharedActiveTools = Arc<RwLock<Vec<ActiveTool>>>;
|
||||
|
||||
pub fn shared_active_tools() -> SharedActiveTools {
|
||||
Arc::new(RwLock::new(Vec::new()))
|
||||
}
|
||||
|
||||
/// Which pane streaming text should go to.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum StreamTarget {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue