adk_ui/tools/
render_table.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::collections::HashMap;
8use std::sync::Arc;
9
10#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
12pub struct RenderTableParams {
13 #[serde(default)]
15 pub title: Option<String>,
16 pub columns: Vec<ColumnDef>,
18 pub data: Vec<HashMap<String, Value>>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
23pub struct ColumnDef {
24 pub header: String,
26 pub accessor_key: String,
28}
29
30pub struct RenderTableTool;
52
53impl RenderTableTool {
54 pub fn new() -> Self {
55 Self
56 }
57}
58
59impl Default for RenderTableTool {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65#[async_trait]
66impl Tool for RenderTableTool {
67 fn name(&self) -> &str {
68 "render_table"
69 }
70
71 fn description(&self) -> &str {
72 r#"Render a data table. Output example:
73┌───────┬─────────────────────┬───────┐
74│ Name │ Email │ Role │
75├───────┼─────────────────────┼───────┤
76│ Alice │ alice@example.com │ Admin │
77│ Bob │ bob@example.com │ User │
78└───────┴─────────────────────┴───────┘
79Set sortable=true for clickable column headers. Set page_size for pagination. Set striped=true for alternating row colors."#
80 }
81
82 fn parameters_schema(&self) -> Option<Value> {
83 Some(super::generate_gemini_schema::<RenderTableParams>())
84 }
85
86 async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value> {
87 let params: RenderTableParams = serde_json::from_value(args)
88 .map_err(|e| adk_core::AdkError::Tool(format!("Invalid parameters: {}", e)))?;
89
90 let columns: Vec<TableColumn> = params
91 .columns
92 .into_iter()
93 .map(|c| TableColumn { header: c.header, accessor_key: c.accessor_key, sortable: true })
94 .collect();
95
96 let mut components = Vec::new();
97
98 if let Some(title) = params.title {
100 components.push(Component::Text(Text {
101 id: None,
102 content: title,
103 variant: TextVariant::H3,
104 }));
105 }
106
107 components.push(Component::Table(Table {
108 id: None,
109 columns,
110 data: params.data,
111 sortable: false,
112 page_size: None,
113 striped: false,
114 }));
115
116 let ui = UiResponse::new(components);
117 serde_json::to_value(ui)
118 .map_err(|e| adk_core::AdkError::Tool(format!("Failed to serialize UI: {}", e)))
119 }
120}