rainy_sdk/endpoints/
cowork.rs

1//! Cowork endpoint for retrieving subscription capabilities
2//!
3//! This endpoint validates the API key and returns the user's
4//! Cowork tier, available models, and feature access.
5
6use crate::{
7    cowork::{CoworkCapabilities, CoworkCapabilitiesResponse, CoworkTier},
8    error::Result,
9    RainyClient,
10};
11
12impl RainyClient {
13    /// Retrieve Cowork capabilities for the current API key.
14    ///
15    /// This method validates the API key and returns information about:
16    /// - Subscription tier (Free, Basic, Pro, Enterprise)
17    /// - Available AI models
18    /// - Feature access (web research, document export, etc.)
19    /// - Usage limits
20    ///
21    /// # Returns
22    ///
23    /// A `Result` containing `CoworkCapabilities` on success, or a `RainyError` on failure.
24    ///
25    /// # Example
26    ///
27    /// ```rust,no_run
28    /// # use rainy_sdk::RainyClient;
29    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
30    /// let client = RainyClient::with_api_key("your-api-key")?;
31    /// let caps = client.get_cowork_capabilities().await?;
32    ///
33    /// if caps.tier.is_premium() {
34    ///     println!("Premium user with {} models available", caps.models.len());
35    /// } else {
36    ///     println!("Free tier - please upgrade for more features");
37    /// }
38    /// # Ok(())
39    /// # }
40    /// ```
41    pub async fn get_cowork_capabilities(&self) -> Result<CoworkCapabilities> {
42        let url = format!("{}/api/v1/cowork/capabilities", self.auth_config().base_url);
43
44        let response = self.http_client().get(&url).send().await;
45
46        match response {
47            Ok(resp) => {
48                if resp.status().is_success() {
49                    let caps_response: CoworkCapabilitiesResponse =
50                        self.handle_response(resp).await?;
51
52                    Ok(CoworkCapabilities {
53                        tier: caps_response.tier,
54                        tier_name: caps_response.tier_name,
55                        models: caps_response.models,
56                        features: caps_response.features,
57                        limits: caps_response.limits,
58                        is_valid: true,
59                        expires_at: caps_response.expires_at,
60                    })
61                } else {
62                    // Invalid or expired API key - return free tier
63                    Ok(CoworkCapabilities::free())
64                }
65            }
66            Err(_) => {
67                // Network error or API unavailable - return free tier
68                Ok(CoworkCapabilities::free())
69            }
70        }
71    }
72
73    /// Check if the current API key grants premium access.
74    ///
75    /// This is a convenience method that calls `get_cowork_capabilities()`
76    /// and checks if the tier is not Free.
77    ///
78    /// # Returns
79    ///
80    /// `true` if the user has premium (Basic, Pro, or Enterprise) access.
81    pub async fn is_premium(&self) -> bool {
82        match self.get_cowork_capabilities().await {
83            Ok(caps) => caps.tier.is_premium(),
84            Err(_) => false,
85        }
86    }
87
88    /// Get available models for Cowork based on subscription tier.
89    ///
90    /// # Returns
91    ///
92    /// A vector of model identifiers available for the current tier.
93    pub async fn get_cowork_models(&self) -> Result<Vec<String>> {
94        let caps = self.get_cowork_capabilities().await?;
95        Ok(caps.models)
96    }
97
98    /// Check if a specific feature is available.
99    ///
100    /// # Arguments
101    ///
102    /// * `feature` - Feature name: "web_research", "document_export", "image_analysis", etc.
103    ///
104    /// # Returns
105    ///
106    /// `true` if the feature is available for the current tier.
107    pub async fn can_use_feature(&self, feature: &str) -> bool {
108        match self.get_cowork_capabilities().await {
109            Ok(caps) => caps.can_use_feature(feature),
110            Err(_) => false,
111        }
112    }
113
114    /// Check if a specific model is available for the current tier.
115    ///
116    /// # Arguments
117    ///
118    /// * `model` - The model identifier to check.
119    ///
120    /// # Returns
121    ///
122    /// `true` if the model is available for the current tier.
123    pub async fn can_use_model(&self, model: &str) -> bool {
124        match self.get_cowork_capabilities().await {
125            Ok(caps) => caps.can_use_model(model),
126            Err(_) => false,
127        }
128    }
129}
130
131/// Offline tier detection based on cached data.
132///
133/// This can be used when network is unavailable to provide
134/// a degraded experience based on previously cached tier info.
135pub fn get_offline_capabilities(cached_tier: Option<CoworkTier>) -> CoworkCapabilities {
136    match cached_tier {
137        Some(CoworkTier::Enterprise) => CoworkCapabilities::enterprise(),
138        Some(CoworkTier::Pro) => CoworkCapabilities::pro(),
139        Some(CoworkTier::Basic) => CoworkCapabilities::basic(),
140        _ => CoworkCapabilities::free(),
141    }
142}