adk_ui/tools/
render_progress.rs

1use crate::schema::*;
2use adk_core::{Result, Tool, ToolContext};
3use async_trait::async_trait;
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::sync::Arc;
8
9/// Parameters for the render_progress tool
10#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
11pub struct RenderProgressParams {
12    /// Title or label for the progress
13    pub title: String,
14    /// Progress percentage (0-100)
15    pub value: u8,
16    /// Optional description of current step
17    #[serde(default)]
18    pub description: Option<String>,
19    /// List of steps with their completion status
20    #[serde(default)]
21    pub steps: Option<Vec<ProgressStep>>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
25pub struct ProgressStep {
26    /// Step label
27    pub label: String,
28    /// Whether step is completed
29    #[serde(default)]
30    pub completed: bool,
31    /// Whether this is the current step
32    #[serde(default)]
33    pub current: bool,
34}
35
36/// Tool for rendering progress indicators and loading states
37pub struct RenderProgressTool;
38
39impl RenderProgressTool {
40    pub fn new() -> Self {
41        Self
42    }
43}
44
45impl Default for RenderProgressTool {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51#[async_trait]
52impl Tool for RenderProgressTool {
53    fn name(&self) -> &str {
54        "render_progress"
55    }
56
57    fn description(&self) -> &str {
58        "Render a progress indicator to show task completion status. Use this when performing multi-step operations or to show loading progress. Can show a progress bar with optional steps."
59    }
60
61    fn parameters_schema(&self) -> Option<Value> {
62        Some(super::generate_gemini_schema::<RenderProgressParams>())
63    }
64
65    async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value> {
66        let params: RenderProgressParams = serde_json::from_value(args)
67            .map_err(|e| adk_core::AdkError::Tool(format!("Invalid parameters: {}", e)))?;
68
69        let mut components = Vec::new();
70
71        // Title
72        components.push(Component::Text(Text {
73            id: None,
74            content: params.title,
75            variant: TextVariant::H3,
76        }));
77
78        // Description
79        if let Some(desc) = params.description {
80            components.push(Component::Text(Text {
81                id: None,
82                content: desc,
83                variant: TextVariant::Caption,
84            }));
85        }
86
87        // Progress bar
88        components.push(Component::Progress(Progress {
89            id: None,
90            value: params.value,
91            label: Some(format!("{}%", params.value)),
92        }));
93
94        // Steps if provided
95        if let Some(steps) = params.steps {
96            for step in steps {
97                let prefix = if step.completed {
98                    "✅"
99                } else if step.current {
100                    "⏳"
101                } else {
102                    "⬜"
103                };
104                components.push(Component::Text(Text {
105                    id: None,
106                    content: format!("{} {}", prefix, step.label),
107                    variant: TextVariant::Body,
108                }));
109            }
110        }
111
112        let ui = UiResponse::new(vec![Component::Card(Card {
113            id: None,
114            title: None,
115            description: None,
116            content: components,
117            footer: None,
118        })]);
119
120        serde_json::to_value(ui)
121            .map_err(|e| adk_core::AdkError::Tool(format!("Failed to serialize UI: {}", e)))
122    }
123}