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::CliConfig;
12use crate::shared::render_result;
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    #[serde(rename = "context_id")]
54    pub context: String,
55    pub name: Option<String>,
56    pub task_count: i64,
57    pub message_count: i64,
58    pub created_at: String,
59    pub updated_at: String,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
63pub struct ConversationListOutput {
64    pub conversations: Vec<ConversationListRow>,
65    pub total: i64,
66}
67
68pub async fn execute(command: ConversationsCommands, config: &CliConfig) -> Result<()> {
69    match command {
70        ConversationsCommands::Stats(args) => {
71            let result = stats::execute(args, config).await?;
72            render_result(&result);
73            Ok(())
74        },
75        ConversationsCommands::Trends(args) => {
76            let result = trends::execute(args, config).await?;
77            render_result(&result);
78            Ok(())
79        },
80        ConversationsCommands::List(args) => {
81            let result = list::execute(args, config).await?;
82            render_result(&result);
83            Ok(())
84        },
85    }
86}
87
88pub async fn execute_with_pool(
89    command: ConversationsCommands,
90    db_ctx: &DatabaseContext,
91    config: &CliConfig,
92) -> Result<()> {
93    match command {
94        ConversationsCommands::Stats(args) => {
95            let result = stats::execute_with_pool(args, db_ctx, config).await?;
96            render_result(&result);
97            Ok(())
98        },
99        ConversationsCommands::Trends(args) => {
100            let result = trends::execute_with_pool(args, db_ctx, config).await?;
101            render_result(&result);
102            Ok(())
103        },
104        ConversationsCommands::List(args) => {
105            let result = list::execute_with_pool(args, db_ctx, config).await?;
106            render_result(&result);
107            Ok(())
108        },
109    }
110}