Skip to main content

adk_ui/tools/
render_table.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::collections::HashMap;
9use std::sync::Arc;
10
11/// Parameters for the render_table tool
12#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
13pub struct RenderTableParams {
14    /// Table title
15    #[serde(default)]
16    pub title: Option<String>,
17    /// Column definitions
18    pub columns: Vec<ColumnDef>,
19    /// Row data - array of objects with keys matching accessor_key
20    pub data: Vec<HashMap<String, Value>>,
21    /// Optional protocol output configuration.
22    #[serde(flatten)]
23    pub protocol: LegacyProtocolOptions,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct ColumnDef {
28    /// Column header text
29    pub header: String,
30    /// Key to access data from row objects
31    pub accessor_key: String,
32}
33
34/// Tool for rendering data tables.
35///
36/// Creates tabular displays for structured data with customizable columns.
37/// Supports optional title, sorting, pagination, and striped styling.
38///
39/// # Example JSON Parameters
40///
41/// ```json
42/// {
43///   "title": "User List",
44///   "columns": [
45///     { "header": "Name", "accessor_key": "name" },
46///     { "header": "Email", "accessor_key": "email" },
47///     { "header": "Role", "accessor_key": "role" }
48///   ],
49///   "data": [
50///     { "name": "Alice", "email": "alice@example.com", "role": "Admin" },
51///     { "name": "Bob", "email": "bob@example.com", "role": "User" }
52///   ]
53/// }
54/// ```
55pub 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        // Add title if provided
104        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}