adk_ui/tools/
render_card.rs1use 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#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
11pub struct RenderCardParams {
12 pub title: String,
14 #[serde(default)]
16 pub description: Option<String>,
17 pub content: String,
19 #[serde(default)]
21 pub actions: Vec<CardAction>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
25pub struct CardAction {
26 pub label: String,
28 pub action_id: String,
30 #[serde(default = "default_variant")]
32 pub variant: String,
33}
34
35fn default_variant() -> String {
36 "primary".to_string()
37}
38
39pub struct RenderCardTool;
57
58impl RenderCardTool {
59 pub fn new() -> Self {
60 Self
61 }
62}
63
64impl Default for RenderCardTool {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70#[async_trait]
71impl Tool for RenderCardTool {
72 fn name(&self) -> &str {
73 "render_card"
74 }
75
76 fn description(&self) -> &str {
77 r#"Render an information card. Output example:
78┌─────────────────────────────┐
79│ Welcome │
80│ Your account is ready │
81│ ─────────────────────────── │
82│ Click below to get started. │
83│ [Get Started] │
84└─────────────────────────────┘
85Use for status updates, summaries, or any structured info with optional action buttons."#
86 }
87
88 fn parameters_schema(&self) -> Option<Value> {
89 Some(super::generate_gemini_schema::<RenderCardParams>())
90 }
91
92 async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value> {
93 let params: RenderCardParams = serde_json::from_value(args)
94 .map_err(|e| adk_core::AdkError::Tool(format!("Invalid parameters: {}", e)))?;
95
96 let content = vec![Component::Text(Text {
98 id: None,
99 content: params.content,
100 variant: TextVariant::Body,
101 })];
102
103 let footer = if params.actions.is_empty() {
105 None
106 } else {
107 Some(
108 params
109 .actions
110 .into_iter()
111 .map(|action| {
112 let variant = match action.variant.as_str() {
113 "secondary" => ButtonVariant::Secondary,
114 "danger" => ButtonVariant::Danger,
115 "ghost" => ButtonVariant::Ghost,
116 "outline" => ButtonVariant::Outline,
117 _ => ButtonVariant::Primary,
118 };
119 Component::Button(Button {
120 id: None,
121 label: action.label,
122 action_id: action.action_id,
123 variant,
124 disabled: false,
125 icon: None,
126 })
127 })
128 .collect(),
129 )
130 };
131
132 let ui = UiResponse::new(vec![Component::Card(Card {
133 id: None,
134 title: Some(params.title),
135 description: params.description,
136 content,
137 footer,
138 })]);
139
140 serde_json::to_value(ui)
141 .map_err(|e| adk_core::AdkError::Tool(format!("Failed to serialize UI: {}", e)))
142 }
143}