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}