systemprompt_cli/commands/analytics/conversations/
mod.rs1mod 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}