Skip to main content

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 tools = UiToolset::all_tools();
15/// let mut builder = LlmAgentBuilder::new("assistant");
16/// for tool in tools {
17///     builder = builder.tool(tool);
18/// }
19/// let agent = builder.build()?;
20/// ```
21pub struct UiToolset {
22    include_screen: bool,
23    include_page: bool,
24    include_kit: bool,
25    include_form: bool,
26    include_card: bool,
27    include_alert: bool,
28    include_confirm: bool,
29    include_table: bool,
30    include_chart: bool,
31    include_layout: bool,
32    include_progress: bool,
33    include_modal: bool,
34    include_toast: bool,
35}
36
37impl UiToolset {
38    /// Create a new UiToolset with all tools enabled
39    pub fn new() -> Self {
40        Self {
41            include_screen: true,
42            include_page: true,
43            include_kit: true,
44            include_form: true,
45            include_card: true,
46            include_alert: true,
47            include_confirm: true,
48            include_table: true,
49            include_chart: true,
50            include_layout: true,
51            include_progress: true,
52            include_modal: true,
53            include_toast: true,
54        }
55    }
56
57    /// Create a toolset with only form rendering
58    pub fn forms_only() -> Self {
59        Self {
60            include_screen: false,
61            include_page: false,
62            include_kit: false,
63            include_form: true,
64            include_card: false,
65            include_alert: false,
66            include_confirm: false,
67            include_table: false,
68            include_chart: false,
69            include_layout: false,
70            include_progress: false,
71            include_modal: false,
72            include_toast: false,
73        }
74    }
75
76    /// Disable form rendering
77    pub fn without_form(mut self) -> Self {
78        self.include_form = false;
79        self
80    }
81
82    /// Disable screen rendering
83    pub fn without_screen(mut self) -> Self {
84        self.include_screen = false;
85        self
86    }
87
88    /// Disable page rendering
89    pub fn without_page(mut self) -> Self {
90        self.include_page = false;
91        self
92    }
93
94    /// Disable kit rendering
95    pub fn without_kit(mut self) -> Self {
96        self.include_kit = false;
97        self
98    }
99
100    /// Disable card rendering
101    pub fn without_card(mut self) -> Self {
102        self.include_card = false;
103        self
104    }
105
106    /// Disable alert rendering
107    pub fn without_alert(mut self) -> Self {
108        self.include_alert = false;
109        self
110    }
111
112    /// Disable confirm rendering
113    pub fn without_confirm(mut self) -> Self {
114        self.include_confirm = false;
115        self
116    }
117
118    /// Disable table rendering
119    pub fn without_table(mut self) -> Self {
120        self.include_table = false;
121        self
122    }
123
124    /// Disable chart rendering
125    pub fn without_chart(mut self) -> Self {
126        self.include_chart = false;
127        self
128    }
129
130    /// Disable layout rendering
131    pub fn without_layout(mut self) -> Self {
132        self.include_layout = false;
133        self
134    }
135
136    /// Disable progress rendering
137    pub fn without_progress(mut self) -> Self {
138        self.include_progress = false;
139        self
140    }
141
142    /// Disable modal rendering
143    pub fn without_modal(mut self) -> Self {
144        self.include_modal = false;
145        self
146    }
147
148    /// Disable toast rendering
149    pub fn without_toast(mut self) -> Self {
150        self.include_toast = false;
151        self
152    }
153
154    /// Get all tools as a Vec for use with LlmAgentBuilder
155    pub fn all_tools() -> Vec<Arc<dyn Tool>> {
156        vec![
157            Arc::new(RenderScreenTool::new()) as Arc<dyn Tool>,
158            Arc::new(RenderPageTool::new()),
159            Arc::new(RenderKitTool::new()),
160            Arc::new(RenderFormTool::new()) as Arc<dyn Tool>,
161            Arc::new(RenderCardTool::new()),
162            Arc::new(RenderAlertTool::new()),
163            Arc::new(RenderConfirmTool::new()),
164            Arc::new(RenderTableTool::new()),
165            Arc::new(RenderChartTool::new()),
166            Arc::new(RenderLayoutTool::new()),
167            Arc::new(RenderProgressTool::new()),
168            Arc::new(RenderModalTool::new()),
169            Arc::new(RenderToastTool::new()),
170        ]
171    }
172}
173
174impl Default for UiToolset {
175    fn default() -> Self {
176        Self::new()
177    }
178}
179
180#[async_trait]
181impl Toolset for UiToolset {
182    fn name(&self) -> &str {
183        "ui"
184    }
185
186    async fn tools(&self, _ctx: Arc<dyn ReadonlyContext>) -> Result<Vec<Arc<dyn Tool>>> {
187        let mut tools: Vec<Arc<dyn Tool>> = Vec::new();
188
189        if self.include_screen {
190            tools.push(Arc::new(RenderScreenTool::new()));
191        }
192        if self.include_page {
193            tools.push(Arc::new(RenderPageTool::new()));
194        }
195        if self.include_kit {
196            tools.push(Arc::new(RenderKitTool::new()));
197        }
198        if self.include_form {
199            tools.push(Arc::new(RenderFormTool::new()));
200        }
201        if self.include_card {
202            tools.push(Arc::new(RenderCardTool::new()));
203        }
204        if self.include_alert {
205            tools.push(Arc::new(RenderAlertTool::new()));
206        }
207        if self.include_confirm {
208            tools.push(Arc::new(RenderConfirmTool::new()));
209        }
210        if self.include_table {
211            tools.push(Arc::new(RenderTableTool::new()));
212        }
213        if self.include_chart {
214            tools.push(Arc::new(RenderChartTool::new()));
215        }
216        if self.include_layout {
217            tools.push(Arc::new(RenderLayoutTool::new()));
218        }
219        if self.include_progress {
220            tools.push(Arc::new(RenderProgressTool::new()));
221        }
222        if self.include_modal {
223            tools.push(Arc::new(RenderModalTool::new()));
224        }
225        if self.include_toast {
226            tools.push(Arc::new(RenderToastTool::new()));
227        }
228
229        Ok(tools)
230    }
231}
232
233#[cfg(test)]
234mod tests {
235    use super::*;
236
237    #[test]
238    fn test_all_tools_returns_13_tools() {
239        let tools = UiToolset::all_tools();
240        assert_eq!(tools.len(), 13);
241
242        let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
243        assert!(names.contains(&"render_screen"));
244        assert!(names.contains(&"render_page"));
245        assert!(names.contains(&"render_kit"));
246        assert!(names.contains(&"render_form"));
247        assert!(names.contains(&"render_card"));
248        assert!(names.contains(&"render_alert"));
249        assert!(names.contains(&"render_confirm"));
250        assert!(names.contains(&"render_table"));
251        assert!(names.contains(&"render_chart"));
252        assert!(names.contains(&"render_layout"));
253        assert!(names.contains(&"render_progress"));
254        assert!(names.contains(&"render_modal"));
255        assert!(names.contains(&"render_toast"));
256    }
257
258    #[test]
259    fn test_forms_only() {
260        let toolset = UiToolset::forms_only();
261        assert!(!toolset.include_screen);
262        assert!(!toolset.include_page);
263        assert!(!toolset.include_kit);
264        assert!(toolset.include_form);
265        assert!(!toolset.include_card);
266        assert!(!toolset.include_alert);
267        assert!(!toolset.include_table);
268    }
269
270    #[test]
271    fn test_without_methods() {
272        let toolset = UiToolset::new().without_chart().without_table().without_progress();
273
274        assert!(toolset.include_form);
275        assert!(toolset.include_card);
276        assert!(!toolset.include_chart);
277        assert!(!toolset.include_table);
278        assert!(!toolset.include_progress);
279    }
280
281    #[test]
282    fn test_toolset_name() {
283        let toolset = UiToolset::new();
284        assert_eq!(toolset.name(), "ui");
285    }
286
287    #[test]
288    fn test_default_is_new() {
289        let default = UiToolset::default();
290        let new = UiToolset::new();
291        assert_eq!(default.include_screen, new.include_screen);
292        assert_eq!(default.include_page, new.include_page);
293        assert_eq!(default.include_kit, new.include_kit);
294        assert_eq!(default.include_form, new.include_form);
295        assert_eq!(default.include_card, new.include_card);
296        assert_eq!(default.include_chart, new.include_chart);
297    }
298}