Skip to main content

systemprompt_cli/commands/analytics/costs/
mod.rs

1mod breakdown;
2mod summary;
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 CostsCommands {
16    #[command(about = "Cost summary")]
17    Summary(summary::SummaryArgs),
18
19    #[command(about = "Cost trends over time")]
20    Trends(trends::TrendsArgs),
21
22    #[command(about = "Cost breakdown by model/agent")]
23    Breakdown(breakdown::BreakdownArgs),
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct CostSummaryOutput {
28    pub period: String,
29    pub total_cost_microdollars: i64,
30    pub total_requests: i64,
31    pub total_tokens: i64,
32    pub avg_cost_per_request_microdollars: f64,
33    pub change_percent: Option<f64>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
37pub struct CostTrendPoint {
38    pub timestamp: String,
39    pub cost_microdollars: i64,
40    pub request_count: i64,
41    pub tokens: i64,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
45pub struct CostTrendsOutput {
46    pub period: String,
47    pub group_by: String,
48    pub points: Vec<CostTrendPoint>,
49    pub total_cost_microdollars: i64,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
53pub struct CostBreakdownItem {
54    pub name: String,
55    pub cost_microdollars: i64,
56    pub request_count: i64,
57    pub tokens: i64,
58    pub percentage: f64,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
62pub struct CostBreakdownOutput {
63    pub period: String,
64    pub breakdown_by: String,
65    pub items: Vec<CostBreakdownItem>,
66    pub total_cost_microdollars: i64,
67}
68
69pub async fn execute(command: CostsCommands, config: &CliConfig) -> Result<()> {
70    match command {
71        CostsCommands::Summary(args) => {
72            let result = summary::execute(args, config).await?;
73            render_result(&result);
74            Ok(())
75        },
76        CostsCommands::Trends(args) => {
77            let result = trends::execute(args, config).await?;
78            render_result(&result);
79            Ok(())
80        },
81        CostsCommands::Breakdown(args) => {
82            let result = breakdown::execute(args, config).await?;
83            render_result(&result);
84            Ok(())
85        },
86    }
87}
88
89pub async fn execute_with_pool(
90    command: CostsCommands,
91    db_ctx: &DatabaseContext,
92    config: &CliConfig,
93) -> Result<()> {
94    match command {
95        CostsCommands::Summary(args) => {
96            let result = summary::execute_with_pool(args, db_ctx, config).await?;
97            render_result(&result);
98            Ok(())
99        },
100        CostsCommands::Trends(args) => {
101            let result = trends::execute_with_pool(args, db_ctx, config).await?;
102            render_result(&result);
103            Ok(())
104        },
105        CostsCommands::Breakdown(args) => {
106            let result = breakdown::execute_with_pool(args, db_ctx, config).await?;
107            render_result(&result);
108            Ok(())
109        },
110    }
111}