adk_ui/
toolset.rs

1use crate::tools::*;
2use adk_core::{ReadonlyContext, Result, Tool, Toolset};
3use async_trait::async_trait;
4use std::sync::Arc;
5
6/// A toolset containing all UI rendering tools.
7///
8/// Use this to easily add UI capabilities to an agent:
9///
10/// ```rust,ignore
11/// use adk_ui::UiToolset;
12/// use adk_agent::LlmAgentBuilder;
13///
14/// let ui_tools = UiToolset::new().tools(&ctx).await?;
15/// let agent = LlmAgentBuilder::new("assistant")
16///     .tools(ui_tools)
17///     .build()?;
18/// ```
19pub struct UiToolset {
20    include_form: bool,
21    include_card: bool,
22    include_alert: bool,
23    include_confirm: bool,
24    include_table: bool,
25    include_chart: bool,
26    include_layout: bool,
27    include_progress: bool,
28    include_modal: bool,
29    include_toast: bool,
30}
31
32impl UiToolset {
33    /// Create a new UiToolset with all tools enabled
34    pub fn new() -> Self {
35        Self {
36            include_form: true,
37            include_card: true,
38            include_alert: true,
39            include_confirm: true,
40            include_table: true,
41            include_chart: true,
42            include_layout: true,
43            include_progress: true,
44            include_modal: true,
45            include_toast: true,
46        }
47    }
48
49    /// Create a toolset with only form rendering
50    pub fn forms_only() -> Self {
51        Self {
52            include_form: true,
53            include_card: false,
54            include_alert: false,
55            include_confirm: false,
56            include_table: false,
57            include_chart: false,
58            include_layout: false,
59            include_progress: false,
60            include_modal: false,
61            include_toast: false,
62        }
63    }
64
65    /// Disable form rendering
66    pub fn without_form(mut self) -> Self {
67        self.include_form = false;
68        self
69    }
70
71    /// Disable card rendering
72    pub fn without_card(mut self) -> Self {
73        self.include_card = false;
74        self
75    }
76
77    /// Disable alert rendering
78    pub fn without_alert(mut self) -> Self {
79        self.include_alert = false;
80        self
81    }
82
83    /// Disable confirm rendering
84    pub fn without_confirm(mut self) -> Self {
85        self.include_confirm = false;
86        self
87    }
88
89    /// Disable table rendering
90    pub fn without_table(mut self) -> Self {
91        self.include_table = false;
92        self
93    }
94
95    /// Disable chart rendering
96    pub fn without_chart(mut self) -> Self {
97        self.include_chart = false;
98        self
99    }
100
101    /// Disable layout rendering
102    pub fn without_layout(mut self) -> Self {
103        self.include_layout = false;
104        self
105    }
106
107    /// Disable progress rendering
108    pub fn without_progress(mut self) -> Self {
109        self.include_progress = false;
110        self
111    }
112
113    /// Disable modal rendering
114    pub fn without_modal(mut self) -> Self {
115        self.include_modal = false;
116        self
117    }
118
119    /// Disable toast rendering
120    pub fn without_toast(mut self) -> Self {
121        self.include_toast = false;
122        self
123    }
124
125    /// Get all tools as a Vec for use with LlmAgentBuilder
126    pub fn all_tools() -> Vec<Arc<dyn Tool>> {
127        vec![
128            Arc::new(RenderFormTool::new()) as Arc<dyn Tool>,
129            Arc::new(RenderCardTool::new()),
130            Arc::new(RenderAlertTool::new()),
131            Arc::new(RenderConfirmTool::new()),
132            Arc::new(RenderTableTool::new()),
133            Arc::new(RenderChartTool::new()),
134            Arc::new(RenderLayoutTool::new()),
135            Arc::new(RenderProgressTool::new()),
136            Arc::new(RenderModalTool::new()),
137            Arc::new(RenderToastTool::new()),
138        ]
139    }
140}
141
142impl Default for UiToolset {
143    fn default() -> Self {
144        Self::new()
145    }
146}
147
148#[async_trait]
149impl Toolset for UiToolset {
150    fn name(&self) -> &str {
151        "ui"
152    }
153
154    async fn tools(&self, _ctx: Arc<dyn ReadonlyContext>) -> Result<Vec<Arc<dyn Tool>>> {
155        let mut tools: Vec<Arc<dyn Tool>> = Vec::new();
156
157        if self.include_form {
158            tools.push(Arc::new(RenderFormTool::new()));
159        }
160        if self.include_card {
161            tools.push(Arc::new(RenderCardTool::new()));
162        }
163        if self.include_alert {
164            tools.push(Arc::new(RenderAlertTool::new()));
165        }
166        if self.include_confirm {
167            tools.push(Arc::new(RenderConfirmTool::new()));
168        }
169        if self.include_table {
170            tools.push(Arc::new(RenderTableTool::new()));
171        }
172        if self.include_chart {
173            tools.push(Arc::new(RenderChartTool::new()));
174        }
175        if self.include_layout {
176            tools.push(Arc::new(RenderLayoutTool::new()));
177        }
178        if self.include_progress {
179            tools.push(Arc::new(RenderProgressTool::new()));
180        }
181        if self.include_modal {
182            tools.push(Arc::new(RenderModalTool::new()));
183        }
184        if self.include_toast {
185            tools.push(Arc::new(RenderToastTool::new()));
186        }
187
188        Ok(tools)
189    }
190}
191
192#[cfg(test)]
193mod tests {
194    use super::*;
195
196    #[test]
197    fn test_all_tools_returns_10_tools() {
198        let tools = UiToolset::all_tools();
199        assert_eq!(tools.len(), 10);
200
201        let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
202        assert!(names.contains(&"render_form"));
203        assert!(names.contains(&"render_card"));
204        assert!(names.contains(&"render_alert"));
205        assert!(names.contains(&"render_confirm"));
206        assert!(names.contains(&"render_table"));
207        assert!(names.contains(&"render_chart"));
208        assert!(names.contains(&"render_layout"));
209        assert!(names.contains(&"render_progress"));
210        assert!(names.contains(&"render_modal"));
211        assert!(names.contains(&"render_toast"));
212    }
213
214    #[test]
215    fn test_forms_only() {
216        let toolset = UiToolset::forms_only();
217        assert!(toolset.include_form);
218        assert!(!toolset.include_card);
219        assert!(!toolset.include_alert);
220        assert!(!toolset.include_table);
221    }
222
223    #[test]
224    fn test_without_methods() {
225        let toolset = UiToolset::new().without_chart().without_table().without_progress();
226
227        assert!(toolset.include_form);
228        assert!(toolset.include_card);
229        assert!(!toolset.include_chart);
230        assert!(!toolset.include_table);
231        assert!(!toolset.include_progress);
232    }
233
234    #[test]
235    fn test_toolset_name() {
236        let toolset = UiToolset::new();
237        assert_eq!(toolset.name(), "ui");
238    }
239
240    #[test]
241    fn test_default_is_new() {
242        let default = UiToolset::default();
243        let new = UiToolset::new();
244        assert_eq!(default.include_form, new.include_form);
245        assert_eq!(default.include_card, new.include_card);
246        assert_eq!(default.include_chart, new.include_chart);
247    }
248}