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