Skip to main content

ai_usagebar/
vendor.rs

1//! Shared vendor IDs and renderer/fetcher structs used by the widget and TUI.
2//!
3//! Snapshots remain a discriminated `VendorSnapshot` enum because the six
4//! vendors have genuinely different shapes — see `usage.rs`.
5
6use std::time::Duration;
7
8use clap::ValueEnum;
9
10use crate::usage::VendorSnapshot;
11use crate::widget::cli::Cli;
12
13/// Outer reqwest client timeout shared by widget and TUI entry points.
14/// Vendor fetchers still apply their own tighter per-request timeouts.
15pub const HTTP_CLIENT_TIMEOUT: Duration = Duration::from_secs(30);
16
17/// Stable enum used by `--vendor` and in config files.
18#[derive(
19    Debug, Clone, Copy, ValueEnum, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize,
20)]
21#[serde(rename_all = "lowercase")]
22pub enum VendorId {
23    Anthropic,
24    Openai,
25    Zai,
26    Openrouter,
27    Deepseek,
28    Kimi,
29}
30
31impl VendorId {
32    pub fn slug(self) -> &'static str {
33        match self {
34            VendorId::Anthropic => "anthropic",
35            VendorId::Openai => "openai",
36            VendorId::Zai => "zai",
37            VendorId::Openrouter => "openrouter",
38            VendorId::Deepseek => "deepseek",
39            VendorId::Kimi => "kimi",
40        }
41    }
42
43    pub fn all() -> &'static [VendorId] {
44        &[
45            VendorId::Anthropic,
46            VendorId::Openai,
47            VendorId::Zai,
48            VendorId::Openrouter,
49            VendorId::Deepseek,
50            VendorId::Kimi,
51        ]
52    }
53}
54
55/// What a vendor returns from a successful fetch — snapshot + meta. Mirrors
56/// `anthropic::fetch::FetchOutcome` but vendor-agnostic.
57#[derive(Debug, Clone)]
58pub struct VendorOutcome {
59    pub snapshot: VendorSnapshot,
60    pub stale: bool,
61    pub last_error: Option<(u16, String)>,
62    pub cache_age: Option<std::time::Duration>,
63}
64
65/// Options forwarded to renderers from the CLI.
66#[derive(Debug, Clone)]
67pub struct RenderOpts {
68    pub format: Option<String>,
69    pub tooltip_format: Option<String>,
70    pub icon: Option<String>,
71    pub pace_tolerance: u32,
72    pub format_pace_color: bool,
73    pub tooltip_pace_pts: bool,
74}
75
76impl RenderOpts {
77    pub fn from_cli(cli: &Cli) -> Self {
78        Self {
79            format: cli.format.clone(),
80            tooltip_format: cli.tooltip_format.clone(),
81            icon: cli.icon.clone(),
82            pace_tolerance: cli.pace_tolerance,
83            format_pace_color: cli.format_pace_color,
84            tooltip_pace_pts: cli.tooltip_pace_pts,
85        }
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn vendor_id_slug_round_trip() {
95        for id in VendorId::all() {
96            assert_eq!(
97                id.slug(),
98                serde_json::to_value(id).unwrap().as_str().unwrap()
99            );
100        }
101    }
102}