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