Skip to main content

adk_ui/tools/
render_confirm.rs

1use crate::schema::*;
2use crate::tools::{LegacyProtocolOptions, render_ui_response_with_protocol};
3use adk_core::{Result, Tool, ToolContext};
4use async_trait::async_trait;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::sync::Arc;
9
10/// Parameters for the render_confirm tool
11#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
12pub struct RenderConfirmParams {
13    /// Confirmation title
14    pub title: String,
15    /// Message explaining what the user is confirming
16    pub message: String,
17    /// Action ID triggered when user confirms
18    pub confirm_action: String,
19    /// Optional cancel action ID (defaults to dismissing)
20    #[serde(default)]
21    pub cancel_action: Option<String>,
22    /// Confirm button label
23    #[serde(default = "default_confirm_label")]
24    pub confirm_label: String,
25    /// Cancel button label
26    #[serde(default = "default_cancel_label")]
27    pub cancel_label: String,
28    /// Whether this is a destructive action (shows danger button)
29    #[serde(default)]
30    pub destructive: bool,
31    /// Optional protocol output configuration.
32    #[serde(flatten)]
33    pub protocol: LegacyProtocolOptions,
34}
35
36fn default_confirm_label() -> String {
37    "Confirm".to_string()
38}
39
40fn default_cancel_label() -> String {
41    "Cancel".to_string()
42}
43
44/// Tool for rendering confirmation dialogs
45pub struct RenderConfirmTool;
46
47impl RenderConfirmTool {
48    pub fn new() -> Self {
49        Self
50    }
51}
52
53impl Default for RenderConfirmTool {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59#[async_trait]
60impl Tool for RenderConfirmTool {
61    fn name(&self) -> &str {
62        "render_confirm"
63    }
64
65    fn description(&self) -> &str {
66        "Render a confirmation dialog to get user approval before proceeding. Use this for destructive actions, important decisions, or when you need explicit user consent."
67    }
68
69    fn parameters_schema(&self) -> Option<Value> {
70        Some(super::generate_gemini_schema::<RenderConfirmParams>())
71    }
72
73    async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value> {
74        let params: RenderConfirmParams = serde_json::from_value(args)
75            .map_err(|e| adk_core::AdkError::Tool(format!("Invalid parameters: {}", e)))?;
76        let protocol_options = params.protocol.clone();
77
78        let confirm_variant =
79            if params.destructive { ButtonVariant::Danger } else { ButtonVariant::Primary };
80
81        let footer = vec![
82            Component::Button(Button {
83                id: None,
84                label: params.cancel_label,
85                action_id: params.cancel_action.unwrap_or_else(|| "cancel".to_string()),
86                variant: ButtonVariant::Ghost,
87                disabled: false,
88                icon: None,
89            }),
90            Component::Button(Button {
91                id: None,
92                label: params.confirm_label,
93                action_id: params.confirm_action,
94                variant: confirm_variant,
95                disabled: false,
96                icon: None,
97            }),
98        ];
99
100        let ui = UiResponse::new(vec![Component::Card(Card {
101            id: None,
102            title: Some(params.title),
103            description: None,
104            content: vec![Component::Text(Text {
105                id: None,
106                content: params.message,
107                variant: TextVariant::Body,
108            })],
109            footer: Some(footer),
110        })]);
111
112        render_ui_response_with_protocol(ui, &protocol_options, "confirm")
113    }
114}