systemprompt_cli/commands/analytics/tools/
mod.rs1mod list;
9mod show;
10mod stats;
11mod trends;
12
13use anyhow::Result;
14use clap::Subcommand;
15use schemars::JsonSchema;
16use serde::{Deserialize, Serialize};
17use systemprompt_runtime::DatabaseContext;
18
19use crate::CliConfig;
20use crate::shared::render_result;
21
22#[derive(Debug, Subcommand)]
23pub enum ToolsCommands {
24 #[command(about = "Aggregate tool statistics")]
25 Stats(stats::StatsArgs),
26
27 #[command(about = "List tools with metrics")]
28 List(list::ListArgs),
29
30 #[command(about = "Tool usage trends over time")]
31 Trends(trends::TrendsArgs),
32
33 #[command(about = "Deep dive into specific tool")]
34 Show(show::ShowArgs),
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
38pub struct ToolStatsOutput {
39 pub period: String,
40 pub total_tools: i64,
41 pub total_executions: i64,
42 pub successful: i64,
43 pub failed: i64,
44 pub timeout: i64,
45 pub success_rate: f64,
46 pub avg_execution_time_ms: i64,
47 pub p95_execution_time_ms: i64,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
51pub struct ToolListRow {
52 pub tool_name: String,
53 pub server_name: String,
54 pub execution_count: i64,
55 pub success_rate: f64,
56 pub avg_execution_time_ms: i64,
57 pub last_used: String,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
61pub struct ToolListOutput {
62 pub tools: Vec<ToolListRow>,
63 pub total: i64,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
67pub struct ToolTrendPoint {
68 pub timestamp: String,
69 pub execution_count: i64,
70 pub success_rate: f64,
71 pub avg_execution_time_ms: i64,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
75pub struct ToolTrendsOutput {
76 pub tool: Option<String>,
77 pub period: String,
78 pub group_by: String,
79 pub points: Vec<ToolTrendPoint>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
83pub struct ToolShowOutput {
84 pub tool_name: String,
85 pub period: String,
86 pub summary: ToolStatsOutput,
87 pub status_breakdown: Vec<StatusBreakdownItem>,
88 pub top_errors: Vec<ErrorItem>,
89 pub usage_by_agent: Vec<AgentUsageItem>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
93pub struct StatusBreakdownItem {
94 pub status: String,
95 pub count: i64,
96 pub percentage: f64,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
100pub struct ErrorItem {
101 pub error_message: String,
102 pub count: i64,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
106pub struct AgentUsageItem {
107 pub agent_name: String,
108 pub count: i64,
109 pub percentage: f64,
110}
111
112pub async fn execute(command: ToolsCommands, config: &CliConfig) -> Result<()> {
113 match command {
114 ToolsCommands::Stats(args) => {
115 let result = stats::execute(args, config).await?;
116 render_result(&result);
117 Ok(())
118 },
119 ToolsCommands::List(args) => {
120 let result = list::execute(args, config).await?;
121 render_result(&result);
122 Ok(())
123 },
124 ToolsCommands::Trends(args) => {
125 let result = trends::execute(args, config).await?;
126 render_result(&result);
127 Ok(())
128 },
129 ToolsCommands::Show(args) => {
130 let result = show::execute(args, config).await?;
131 render_result(&result);
132 Ok(())
133 },
134 }
135}
136
137pub async fn execute_with_pool(
138 command: ToolsCommands,
139 db_ctx: &DatabaseContext,
140 config: &CliConfig,
141) -> Result<()> {
142 match command {
143 ToolsCommands::Stats(args) => {
144 let result = stats::execute_with_pool(args, db_ctx, config).await?;
145 render_result(&result);
146 Ok(())
147 },
148 ToolsCommands::List(args) => {
149 let result = list::execute_with_pool(args, db_ctx, config).await?;
150 render_result(&result);
151 Ok(())
152 },
153 ToolsCommands::Trends(args) => {
154 let result = trends::execute_with_pool(args, db_ctx, config).await?;
155 render_result(&result);
156 Ok(())
157 },
158 ToolsCommands::Show(args) => {
159 let result = show::execute_with_pool(args, db_ctx, config).await?;
160 render_result(&result);
161 Ok(())
162 },
163 }
164}