Skip to main content

systemprompt_cli/commands/analytics/agents/
mod.rs

1//! Agent performance analytics: stats, listing, trends, and per-agent deep
2//! dives.
3//!
4//! Defines the [`AgentsCommands`] subcommand tree and the typed output rows
5//! ([`AgentStatsOutput`], [`AgentListOutput`], [`AgentTrendsOutput`],
6//! [`AgentShowOutput`]) rendered by the `analytics agents` commands.
7//!
8//! Copyright (c) systemprompt.io — Business Source License 1.1.
9//! See <https://systemprompt.io> for licensing details.
10
11mod list;
12mod show;
13mod stats;
14mod trends;
15
16use anyhow::Result;
17use clap::Subcommand;
18use schemars::JsonSchema;
19use serde::{Deserialize, Serialize};
20
21use crate::context::CommandContext;
22use crate::shared::render_result;
23
24#[derive(Debug, Subcommand)]
25pub enum AgentsCommands {
26    #[command(about = "Aggregate agent statistics")]
27    Stats(stats::StatsArgs),
28
29    #[command(about = "List agents with metrics")]
30    List(list::ListArgs),
31
32    #[command(about = "Agent usage trends over time")]
33    Trends(trends::TrendsArgs),
34
35    #[command(about = "Deep dive into specific agent")]
36    Show(show::ShowArgs),
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
40pub struct AgentStatsOutput {
41    pub period: String,
42    pub total_agents: i64,
43    pub total_tasks: i64,
44    pub completed_tasks: i64,
45    pub failed_tasks: i64,
46    pub success_rate: f64,
47    pub avg_execution_time_ms: i64,
48    pub total_ai_requests: i64,
49    pub total_cost_microdollars: i64,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
53pub struct AgentListRow {
54    pub agent_name: String,
55    pub task_count: i64,
56    pub success_rate: f64,
57    pub avg_execution_time_ms: i64,
58    pub total_cost_microdollars: i64,
59    pub last_active: String,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
63pub struct AgentListOutput {
64    pub agents: Vec<AgentListRow>,
65    pub total: i64,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
69pub struct AgentTrendPoint {
70    pub timestamp: String,
71    pub task_count: i64,
72    pub success_rate: f64,
73    pub avg_execution_time_ms: i64,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
77pub struct AgentTrendsOutput {
78    pub agent: Option<String>,
79    pub period: String,
80    pub group_by: String,
81    pub points: Vec<AgentTrendPoint>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
85pub struct AgentShowOutput {
86    pub agent_name: String,
87    pub period: String,
88    pub summary: AgentStatsOutput,
89    pub status_breakdown: Vec<StatusBreakdownItem>,
90    pub top_errors: Vec<ErrorBreakdownItem>,
91    pub hourly_distribution: Vec<HourlyDistributionItem>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
95pub struct StatusBreakdownItem {
96    pub status: String,
97    pub count: i64,
98    pub percentage: f64,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
102pub struct ErrorBreakdownItem {
103    pub error_type: String,
104    pub count: i64,
105}
106
107#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
108pub struct HourlyDistributionItem {
109    pub hour: i32,
110    pub count: i64,
111}
112
113pub async fn execute(command: AgentsCommands, ctx: &CommandContext) -> Result<()> {
114    let db_ctx = ctx.database().await?;
115    match command {
116        AgentsCommands::Stats(args) => {
117            let result = stats::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
118            render_result(&result, &ctx.cli);
119            Ok(())
120        },
121        AgentsCommands::List(args) => {
122            let result = list::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
123            render_result(&result, &ctx.cli);
124            Ok(())
125        },
126        AgentsCommands::Trends(args) => {
127            let result = trends::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
128            render_result(&result, &ctx.cli);
129            Ok(())
130        },
131        AgentsCommands::Show(args) => {
132            let result = show::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
133            render_result(&result, &ctx.cli);
134            Ok(())
135        },
136    }
137}