Skip to main content

systemprompt_cli/commands/analytics/sessions/
mod.rs

1mod live;
2mod stats;
3mod trends;
4
5use anyhow::Result;
6use clap::Subcommand;
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use systemprompt_runtime::DatabaseContext;
10
11use crate::CliConfig;
12use crate::shared::render_result;
13
14#[derive(Debug, Subcommand)]
15pub enum SessionsCommands {
16    #[command(about = "Session statistics")]
17    Stats(stats::StatsArgs),
18
19    #[command(about = "Session trends over time")]
20    Trends(trends::TrendsArgs),
21
22    #[command(about = "Real-time active sessions")]
23    Live(live::LiveArgs),
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct SessionStatsOutput {
28    pub period: String,
29    #[serde(rename = "sessions_created_in_period")]
30    pub total_sessions: i64,
31    #[serde(rename = "sessions_currently_active")]
32    pub active_sessions: i64,
33    pub unique_users: i64,
34    pub avg_duration_seconds: i64,
35    pub avg_requests_per_session: f64,
36    pub conversion_rate: f64,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
40pub struct SessionTrendPoint {
41    pub timestamp: String,
42    pub session_count: i64,
43    pub active_users: i64,
44    pub avg_duration_seconds: i64,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
48pub struct SessionTrendsOutput {
49    pub period: String,
50    pub group_by: String,
51    pub points: Vec<SessionTrendPoint>,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
55pub struct ActiveSessionRow {
56    #[serde(rename = "session_id")]
57    pub session: String,
58    pub user_type: String,
59    pub started_at: String,
60    pub duration_seconds: i64,
61    pub request_count: i64,
62    pub last_activity: String,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
66pub struct LiveSessionsOutput {
67    pub active_count: i64,
68    pub sessions: Vec<ActiveSessionRow>,
69    pub timestamp: String,
70}
71
72pub async fn execute(command: SessionsCommands, config: &CliConfig) -> Result<()> {
73    match command {
74        SessionsCommands::Stats(args) => {
75            let result = stats::execute(args, config).await?;
76            render_result(&result);
77            Ok(())
78        },
79        SessionsCommands::Trends(args) => {
80            let result = trends::execute(args, config).await?;
81            render_result(&result);
82            Ok(())
83        },
84        SessionsCommands::Live(args) => {
85            let result = live::execute(args, config).await?;
86            render_result(&result);
87            Ok(())
88        },
89    }
90}
91
92pub async fn execute_with_pool(
93    command: SessionsCommands,
94    db_ctx: &DatabaseContext,
95    config: &CliConfig,
96) -> Result<()> {
97    match command {
98        SessionsCommands::Stats(args) => {
99            let result = stats::execute_with_pool(args, db_ctx, config).await?;
100            render_result(&result);
101            Ok(())
102        },
103        SessionsCommands::Trends(args) => {
104            let result = trends::execute_with_pool(args, db_ctx, config).await?;
105            render_result(&result);
106            Ok(())
107        },
108        SessionsCommands::Live(args) => {
109            let result = live::execute_with_pool(args, db_ctx, config).await?;
110            render_result(&result);
111            Ok(())
112        },
113    }
114}