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};
20use systemprompt_identifiers::AgentName;
21
22use crate::context::CommandContext;
23use crate::shared::render_result;
24
25#[derive(Debug, Subcommand)]
26pub enum AgentsCommands {
27    #[command(about = "Aggregate agent statistics")]
28    Stats(stats::StatsArgs),
29
30    #[command(about = "List agents with metrics")]
31    List(list::ListArgs),
32
33    #[command(about = "Agent usage trends over time")]
34    Trends(trends::TrendsArgs),
35
36    #[command(about = "Deep dive into specific agent")]
37    Show(show::ShowArgs),
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
41pub struct AgentStatsOutput {
42    pub period: String,
43    pub total_agents: i64,
44    pub total_tasks: i64,
45    pub completed_tasks: i64,
46    pub failed_tasks: i64,
47    pub success_rate: f64,
48    pub avg_execution_time_ms: i64,
49    pub total_ai_requests: i64,
50    pub total_cost_microdollars: i64,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
54pub struct AgentListRow {
55    pub agent_name: AgentName,
56    pub task_count: i64,
57    pub success_rate: f64,
58    pub avg_execution_time_ms: i64,
59    pub total_cost_microdollars: i64,
60    pub last_active: String,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
64pub struct AgentListOutput {
65    pub agents: Vec<AgentListRow>,
66    pub total: i64,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
70pub struct AgentTrendPoint {
71    pub timestamp: String,
72    pub task_count: i64,
73    pub success_rate: f64,
74    pub avg_execution_time_ms: i64,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
78pub struct AgentTrendsOutput {
79    pub agent: Option<String>,
80    pub period: String,
81    pub group_by: String,
82    pub points: Vec<AgentTrendPoint>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
86pub struct AgentShowOutput {
87    pub agent_name: AgentName,
88    pub period: String,
89    pub summary: AgentStatsOutput,
90    pub status_breakdown: Vec<StatusBreakdownItem>,
91    pub top_errors: Vec<ErrorBreakdownItem>,
92    pub hourly_distribution: Vec<HourlyDistributionItem>,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
96pub struct StatusBreakdownItem {
97    pub status: String,
98    pub count: i64,
99    pub percentage: f64,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
103pub struct ErrorBreakdownItem {
104    pub error_type: String,
105    pub count: i64,
106}
107
108#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
109pub struct HourlyDistributionItem {
110    pub hour: i32,
111    pub count: i64,
112}
113
114pub async fn execute(command: AgentsCommands, ctx: &CommandContext) -> Result<()> {
115    let db_ctx = ctx.database().await?;
116    match command {
117        AgentsCommands::Stats(args) => {
118            let result = stats::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
119            render_result(&result, &ctx.cli);
120            Ok(())
121        },
122        AgentsCommands::List(args) => {
123            let result = list::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
124            render_result(&result, &ctx.cli);
125            Ok(())
126        },
127        AgentsCommands::Trends(args) => {
128            let result = trends::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
129            render_result(&result, &ctx.cli);
130            Ok(())
131        },
132        AgentsCommands::Show(args) => {
133            let result = show::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
134            render_result(&result, &ctx.cli);
135            Ok(())
136        },
137    }
138}