Skip to main content

systemprompt_cli/commands/analytics/
mod.rs

1//! Top-level `analytics` command group spanning all metric domains.
2//!
3//! [`AnalyticsCommands`] routes to the per-domain subcommand trees (overview,
4//! conversations, agents, tools, requests, sessions, content, traffic, costs).
5//! Each variant dispatches to its module's `execute` against the invocation's
6//! [`CommandContext`]. The [`shared`] module holds the time-range and output
7//! formatting helpers used across all domains.
8//!
9//! Copyright (c) systemprompt.io — Business Source License 1.1.
10//! See <https://systemprompt.io> for licensing details.
11
12pub mod agents;
13pub mod content;
14pub mod conversations;
15pub mod costs;
16pub mod overview;
17pub mod projection;
18pub mod requests;
19pub mod sessions;
20pub mod shared;
21pub mod tools;
22pub mod traffic;
23
24use anyhow::{Context, Result};
25use clap::Subcommand;
26
27use crate::context::CommandContext;
28use crate::shared::render_result;
29
30#[derive(Debug, Subcommand)]
31pub enum AnalyticsCommands {
32    #[command(subcommand, about = "Reporting projection status and recovery")]
33    Projection(projection::ProjectionCommands),
34    #[command(about = "Dashboard overview of all analytics")]
35    Overview(overview::OverviewArgs),
36
37    #[command(subcommand, about = "Conversation analytics")]
38    Conversations(conversations::ConversationsCommands),
39
40    #[command(subcommand, about = "Agent performance analytics")]
41    Agents(agents::AgentsCommands),
42
43    #[command(subcommand, about = "Tool usage analytics")]
44    Tools(tools::ToolsCommands),
45
46    #[command(about = "AI request analytics; defaults to the stats aggregate")]
47    Requests(requests::RequestsArgs),
48
49    #[command(subcommand, about = "Session analytics")]
50    Sessions(sessions::SessionsCommands),
51
52    #[command(subcommand, about = "Content performance analytics")]
53    Content(content::ContentCommands),
54
55    #[command(subcommand, about = "Traffic analytics")]
56    Traffic(traffic::TrafficCommands),
57
58    #[command(about = "Cost analytics; defaults to the spend summary")]
59    Costs(costs::CostsArgs),
60}
61
62pub async fn execute(command: AnalyticsCommands, ctx: &CommandContext) -> Result<()> {
63    if !matches!(&command, AnalyticsCommands::Projection(_)) {
64        let database = ctx.database().await?;
65        let status = systemprompt_runtime::reporting::status(database.db_pool())
66            .await
67            .context("Reporting schema unavailable; apply database migrations first")?;
68        anyhow::ensure!(
69            status.initialized,
70            "Reporting baseline is not initialized; run analytics projection rebuild"
71        );
72    }
73    match command {
74        AnalyticsCommands::Projection(command) => projection::execute(command, ctx).await,
75        AnalyticsCommands::Overview(args) => {
76            let result =
77                overview::execute_with_pool(args, &ctx.database().await?, &ctx.cli).await?;
78            render_result(&result, &ctx.cli);
79            Ok(())
80        },
81        AnalyticsCommands::Conversations(cmd) => conversations::execute(cmd, ctx).await,
82        AnalyticsCommands::Agents(cmd) => agents::execute(cmd, ctx).await,
83        AnalyticsCommands::Tools(cmd) => tools::execute(cmd, ctx).await,
84        AnalyticsCommands::Requests(cmd) => requests::execute(cmd, ctx).await,
85        AnalyticsCommands::Sessions(cmd) => sessions::execute(cmd, ctx).await,
86        AnalyticsCommands::Content(cmd) => content::execute(cmd, ctx).await,
87        AnalyticsCommands::Traffic(cmd) => traffic::execute(cmd, ctx).await,
88        AnalyticsCommands::Costs(cmd) => costs::execute(cmd, ctx).await,
89    }
90}