adk_ui/tools/
render_confirm.rs1use crate::compat::{Result, Tool, ToolContext};
2use crate::schema::*;
3use crate::tools::{LegacyProtocolOptions, render_ui_response_with_protocol};
4use async_trait::async_trait;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::sync::Arc;
9
10#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
12pub struct RenderConfirmParams {
13 pub title: String,
15 pub message: String,
17 pub confirm_action: String,
19 #[serde(default)]
21 pub cancel_action: Option<String>,
22 #[serde(default = "default_confirm_label")]
24 pub confirm_label: String,
25 #[serde(default = "default_cancel_label")]
27 pub cancel_label: String,
28 #[serde(default)]
30 pub destructive: bool,
31 #[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
44pub 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| crate::compat::AdkError::tool(format!("Invalid parameters: {}", e)))?;
76 let protocol_options = params.protocol.clone();
77
78 let confirm_variant = if params.destructive {
79 ButtonVariant::Danger
80 } else {
81 ButtonVariant::Primary
82 };
83
84 let footer = vec![
85 Component::Button(Button {
86 id: None,
87 label: params.cancel_label,
88 action_id: params.cancel_action.unwrap_or_else(|| "cancel".to_string()),
89 variant: ButtonVariant::Ghost,
90 disabled: false,
91 icon: None,
92 }),
93 Component::Button(Button {
94 id: None,
95 label: params.confirm_label,
96 action_id: params.confirm_action,
97 variant: confirm_variant,
98 disabled: false,
99 icon: None,
100 }),
101 ];
102
103 let ui = UiResponse::new(vec![Component::Card(Card {
104 id: None,
105 title: Some(params.title),
106 description: None,
107 content: vec![Component::Text(Text {
108 id: None,
109 content: params.message,
110 variant: TextVariant::Body,
111 })],
112 footer: Some(footer),
113 })]);
114
115 let surface_id = protocol_options.resolved_surface_id("confirm");
116 let output = render_ui_response_with_protocol(ui, &protocol_options, "confirm")?;
117 let surface_ref = crate::surface_runtime::next_surface_ref(&ctx, surface_id);
118 crate::surface_runtime::record_surface_ref(&ctx, &surface_ref);
119 Ok(output)
120 }
121}