steer_tui/tui/widgets/formatters/
mod.rs

1use crate::tui::theme::Theme;
2use lazy_static::lazy_static;
3use ratatui::text::Line;
4use serde_json::Value;
5use std::collections::HashMap;
6use steer_core::app::conversation::ToolResult;
7
8pub mod astgrep;
9pub mod bash;
10pub mod default;
11pub mod dispatch_agent;
12pub mod edit;
13pub mod external;
14pub mod fetch;
15pub mod glob;
16pub mod grep;
17pub mod helpers;
18pub mod ls;
19pub mod replace;
20pub mod todo_read;
21pub mod todo_write;
22pub mod view;
23
24// Import the formatters
25use self::astgrep::AstGrepFormatter;
26use self::bash::BashFormatter;
27use self::default::DefaultFormatter;
28use self::dispatch_agent::DispatchAgentFormatter;
29use self::edit::EditFormatter;
30use self::external::ExternalFormatter;
31use self::fetch::FetchFormatter;
32use self::glob::GlobFormatter;
33use self::grep::GrepFormatter;
34use self::ls::LsFormatter;
35use self::replace::ReplaceFormatter;
36
37use self::todo_read::TodoReadFormatter;
38use self::todo_write::TodoWriteFormatter;
39use self::view::ViewFormatter;
40
41/// Trait for formatting tool calls and results
42pub trait ToolFormatter: Send + Sync {
43    /// Format tool call and result in compact mode (single line summary)
44    fn compact(
45        &self,
46        params: &Value,
47        result: &Option<ToolResult>,
48        wrap_width: usize,
49        theme: &Theme,
50    ) -> Vec<Line<'static>>;
51
52    /// Format tool call and result in detailed mode (full parameters and output)
53    fn detailed(
54        &self,
55        params: &Value,
56        result: &Option<ToolResult>,
57        wrap_width: usize,
58        theme: &Theme,
59    ) -> Vec<Line<'static>>;
60
61    /// Format tool call for approval request (shows what the tool will do)
62    fn approval(&self, params: &Value, wrap_width: usize, theme: &Theme) -> Vec<Line<'static>> {
63        // Default implementation just wraps compact() without result
64        self.compact(params, &None, wrap_width, theme)
65    }
66}
67
68lazy_static! {
69    static ref FORMATTERS: HashMap<&'static str, Box<dyn ToolFormatter>> = {
70        use steer_tools::tools::*;
71
72        let mut map: HashMap<&'static str, Box<dyn ToolFormatter>> = HashMap::new();
73
74        map.insert(BASH_TOOL_NAME, Box::new(BashFormatter));
75        map.insert(GREP_TOOL_NAME, Box::new(GrepFormatter));
76        map.insert(LS_TOOL_NAME, Box::new(LsFormatter));
77        map.insert(GLOB_TOOL_NAME, Box::new(GlobFormatter));
78        map.insert(VIEW_TOOL_NAME, Box::new(ViewFormatter));
79        map.insert(EDIT_TOOL_NAME, Box::new(EditFormatter));
80        map.insert(edit::multi_edit::MULTI_EDIT_TOOL_NAME, Box::new(EditFormatter)); // Multi-edit uses same formatter
81        map.insert(REPLACE_TOOL_NAME, Box::new(ReplaceFormatter));
82        map.insert(TODO_READ_TOOL_NAME, Box::new(TodoReadFormatter));
83        map.insert(TODO_WRITE_TOOL_NAME, Box::new(TodoWriteFormatter));
84        map.insert(AST_GREP_TOOL_NAME, Box::new(AstGrepFormatter));
85        map.insert(steer_core::tools::fetch::FETCH_TOOL_NAME, Box::new(FetchFormatter));
86        map.insert(steer_core::tools::dispatch_agent::DISPATCH_AGENT_TOOL_NAME, Box::new(DispatchAgentFormatter));
87
88        // Catch-all formatter for external/MCP tools (name prefix "mcp__") will be handled in get_formatter
89
90        map
91    };
92
93    static ref DEFAULT_FORMATTER: Box<dyn ToolFormatter> = Box::new(DefaultFormatter);
94    static ref EXTERNAL_FORMATTER: Box<dyn ToolFormatter> = Box::new(ExternalFormatter);
95}
96
97pub fn get_formatter(tool_name: &str) -> &'static dyn ToolFormatter {
98    if let Some(fmt) = FORMATTERS.get(tool_name) {
99        fmt.as_ref()
100    } else if tool_name.starts_with("mcp__") {
101        EXTERNAL_FORMATTER.as_ref()
102    } else {
103        DEFAULT_FORMATTER.as_ref()
104    }
105}