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};
17
18use crate::context::CommandContext;
19use crate::shared::render_result;
20
21#[derive(Debug, Subcommand)]
22pub enum ToolsCommands {
23 #[command(about = "Aggregate tool statistics")]
24 Stats(stats::StatsArgs),
25
26 #[command(about = "List tools with metrics")]
27 List(list::ListArgs),
28
29 #[command(about = "Tool usage trends over time")]
30 Trends(trends::TrendsArgs),
31
32 #[command(about = "Deep dive into specific tool")]
33 Show(show::ShowArgs),
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
37pub struct ToolStatsOutput {
38 pub period: String,
39 pub total_tools: i64,
40 pub total_executions: i64,
41 pub successful: i64,
42 pub failed: i64,
43 pub timeout: i64,
44 pub success_rate: f64,
45 pub avg_execution_time_ms: i64,
46 pub p95_execution_time_ms: i64,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
50pub struct ToolListRow {
51 pub tool_name: String,
52 pub server_name: String,
53 pub execution_count: i64,
54 pub success_rate: f64,
55 pub avg_execution_time_ms: i64,
56 pub last_used: String,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
60pub struct ToolListOutput {
61 pub tools: Vec<ToolListRow>,
62 pub total: i64,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
66pub struct ToolTrendPoint {
67 pub timestamp: String,
68 pub execution_count: i64,
69 pub success_rate: f64,
70 pub avg_execution_time_ms: i64,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
74pub struct ToolTrendsOutput {
75 pub tool: Option<String>,
76 pub period: String,
77 pub group_by: String,
78 pub points: Vec<ToolTrendPoint>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
82pub struct ToolShowOutput {
83 pub tool_name: String,
84 pub period: String,
85 pub summary: ToolStatsOutput,
86 pub status_breakdown: Vec<StatusBreakdownItem>,
87 pub top_errors: Vec<ErrorItem>,
88 pub usage_by_agent: Vec<AgentUsageItem>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
92pub struct StatusBreakdownItem {
93 pub status: String,
94 pub count: i64,
95 pub percentage: f64,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
99pub struct ErrorItem {
100 pub error_message: String,
101 pub count: i64,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
105pub struct AgentUsageItem {
106 pub agent_name: String,
107 pub count: i64,
108 pub percentage: f64,
109}
110
111pub async fn execute(command: ToolsCommands, ctx: &CommandContext) -> Result<()> {
112 let db_ctx = ctx.database().await?;
113 match command {
114 ToolsCommands::Stats(args) => {
115 let result = stats::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
116 render_result(&result, &ctx.cli);
117 Ok(())
118 },
119 ToolsCommands::List(args) => {
120 let result = list::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
121 render_result(&result, &ctx.cli);
122 Ok(())
123 },
124 ToolsCommands::Trends(args) => {
125 let result = trends::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
126 render_result(&result, &ctx.cli);
127 Ok(())
128 },
129 ToolsCommands::Show(args) => {
130 let result = show::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
131 render_result(&result, &ctx.cli);
132 Ok(())
133 },
134 }
135}