steer_tui/tui/widgets/formatters/
external.rs1use super::{
2 ToolFormatter,
3 helpers::{json_preview, separator_line, tool_error_user_message, truncate_middle, wrap_lines},
4};
5use crate::tui::theme::Theme;
6use ratatui::{
7 style::Style,
8 text::{Line, Span},
9};
10use serde_json::Value;
11use steer_grpc::client_api::ToolResult;
12use textwrap;
13
14pub struct ExternalFormatter;
17
18impl ToolFormatter for ExternalFormatter {
19 fn compact(
20 &self,
21 params: &Value,
22 result: &Option<ToolResult>,
23 _wrap_width: usize,
24 theme: &Theme,
25 ) -> Vec<Line<'static>> {
26 let mut spans = Vec::new();
28
29 let preview = json_preview(params, 30);
31 spans.push(Span::styled(preview.clone(), theme.dim_text()));
32
33 if let Some(result) = result {
34 match result {
35 ToolResult::External(ext) => {
36 let payload_preview = truncate_middle(&ext.payload, 40);
37 spans.push(Span::raw(" → "));
38 spans.push(Span::styled(payload_preview, Style::default()));
39 }
40 ToolResult::Error(err) => {
41 spans.push(Span::raw(" ✗ "));
42 spans.push(Span::styled(
43 tool_error_user_message(err).into_owned(),
44 theme.error_text(),
45 ));
46 }
47 _ => {}
48 }
49 }
50
51 vec![Line::from(spans)]
52 }
53
54 fn detailed(
55 &self,
56 params: &Value,
57 result: &Option<ToolResult>,
58 wrap_width: usize,
59 theme: &Theme,
60 ) -> Vec<Line<'static>> {
61 let mut lines = Vec::new();
62
63 lines.push(Line::from(Span::styled("Parameters:", theme.text())));
65
66 let pretty_params = serde_json::to_string_pretty(params).unwrap_or_default();
67 for line in wrap_lines(pretty_params.lines(), wrap_width) {
68 lines.push(Line::from(Span::styled(line, theme.dim_text())));
69 }
70
71 if let Some(result) = result {
73 lines.push(separator_line(wrap_width, theme.dim_text()));
74 match result {
75 ToolResult::External(ext) => {
76 if let Ok(json_val) = serde_json::from_str::<serde_json::Value>(&ext.payload) {
78 if let Ok(pretty) = serde_json::to_string_pretty(&json_val) {
79 for ln in wrap_lines(pretty.lines(), wrap_width) {
80 lines.push(Line::from(Span::raw(ln)));
81 }
82 } else {
83 for wrapped in textwrap::wrap(&ext.payload, wrap_width) {
85 lines.push(Line::from(Span::raw(wrapped.to_string())));
86 }
87 }
88 } else {
89 for wrapped in textwrap::wrap(&ext.payload, wrap_width) {
91 lines.push(Line::from(Span::raw(wrapped.to_string())));
92 }
93 }
94 }
95 ToolResult::Error(err) => {
96 for wrapped in textwrap::wrap(&tool_error_user_message(err), wrap_width) {
97 lines.push(Line::from(Span::styled(
98 wrapped.to_string(),
99 theme.error_text(),
100 )));
101 }
102 }
103 _ => {}
104 }
105 }
106
107 lines
108 }
109}