Skip to main content

systemprompt_cli/commands/analytics/conversations/
mod.rs

1mod list;
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::shared::render_result;
12use crate::CliConfig;
13
14#[derive(Debug, Subcommand)]
15pub enum ConversationsCommands {
16    #[command(about = "Conversation statistics")]
17    Stats(stats::StatsArgs),
18
19    #[command(about = "Conversation trends over time")]
20    Trends(trends::TrendsArgs),
21
22    #[command(about = "List conversations")]
23    List(list::ListArgs),
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct ConversationStatsOutput {
28    pub period: String,
29    pub total_contexts: i64,
30    pub total_tasks: i64,
31    pub total_messages: i64,
32    pub avg_messages_per_task: f64,
33    pub avg_task_duration_ms: i64,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
37pub struct ConversationTrendPoint {
38    pub timestamp: String,
39    pub context_count: i64,
40    pub task_count: i64,
41    pub message_count: i64,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
45pub struct ConversationTrendsOutput {
46    pub period: String,
47    pub group_by: String,
48    pub points: Vec<ConversationTrendPoint>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
52pub struct ConversationListRow {
53    pub context_id: String,
54    pub name: Option<String>,
55    pub task_count: i64,
56    pub message_count: i64,
57    pub created_at: String,
58    pub updated_at: String,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
62pub struct ConversationListOutput {
63    pub conversations: Vec<ConversationListRow>,
64    pub total: i64,
65}
66
67pub async fn execute(command: ConversationsCommands, config: &CliConfig) -> Result<()> {
68    match command {
69        ConversationsCommands::Stats(args) => {
70            let result = stats::execute(args, config).await?;
71            render_result(&result);
72            Ok(())
73        },
74        ConversationsCommands::Trends(args) => {
75            let result = trends::execute(args, config).await?;
76            render_result(&result);
77            Ok(())
78        },
79        ConversationsCommands::List(args) => {
80            let result = list::execute(args, config).await?;
81            render_result(&result);
82            Ok(())
83        },
84    }
85}
86
87pub async fn execute_with_pool(
88    command: ConversationsCommands,
89    db_ctx: &DatabaseContext,
90    config: &CliConfig,
91) -> Result<()> {
92    match command {
93        ConversationsCommands::Stats(args) => {
94            let result = stats::execute_with_pool(args, db_ctx, config).await?;
95            render_result(&result);
96            Ok(())
97        },
98        ConversationsCommands::Trends(args) => {
99            let result = trends::execute_with_pool(args, db_ctx, config).await?;
100            render_result(&result);
101            Ok(())
102        },
103        ConversationsCommands::List(args) => {
104            let result = list::execute_with_pool(args, db_ctx, config).await?;
105            render_result(&result);
106            Ok(())
107        },
108    }
109}