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