rainy_sdk/endpoints/search.rs
1//! Web Research endpoint
2//!
3//! This endpoint provides deep web research capabilities via Exa/Tavily.
4//! Requires a Cowork plan with web_research feature enabled.
5
6use crate::{
7 error::{RainyError, Result},
8 search::{DeepResearchResponse, ResearchConfig, ResearchRequest},
9 RainyClient,
10};
11
12impl RainyClient {
13 /// Perform deep web research on a topic.
14 ///
15 /// This method leverages the Rainy Agent Network to perform comprehensive
16 /// web research using providers like Exa or Tavily.
17 ///
18 /// # Arguments
19 ///
20 /// * `topic` - The research topic or question.
21 /// * `config` - Research configuration (provider, depth, etc.)
22 ///
23 /// # Returns
24 ///
25 /// A `Result` containing `DeepResearchResponse` on success.
26 ///
27 /// # Example
28 ///
29 /// ```rust,no_run
30 /// # use rainy_sdk::{RainyClient, search::ResearchConfig, models::{ResearchProvider, ResearchDepth}};
31 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
32 /// let client = RainyClient::with_api_key("your-api-key")?;
33 ///
34 /// // Basic research
35 /// let response = client.research("Latest Rust features", None).await?;
36 /// if let Some(content) = response.result {
37 /// println!("Report: {}", content);
38 /// }
39 ///
40 /// // Advanced deep research with Exa
41 /// let config = ResearchConfig::new()
42 /// .with_provider(ResearchProvider::Exa)
43 /// .with_depth(ResearchDepth::Advanced);
44 ///
45 /// let response = client.research("Quantum Computing advances", Some(config)).await?;
46 /// # Ok(())
47 /// # }
48 /// ```
49 pub async fn research(
50 &self,
51 topic: impl Into<String>,
52 config: Option<ResearchConfig>,
53 ) -> Result<DeepResearchResponse> {
54 let cfg = config.unwrap_or_default();
55 let request = ResearchRequest::new(topic.into(), &cfg);
56
57 // Note: The endpoint is /agents/research based on previous analysis
58 let url = format!("{}/agents/research", self.auth_config().base_url);
59
60 let response = self
61 .http_client()
62 .post(&url)
63 .json(&request)
64 .send()
65 .await
66 .map_err(|e| RainyError::Network {
67 message: e.to_string(),
68 retryable: true,
69 source_error: Some(e.to_string()),
70 })?;
71
72 if response.status().as_u16() == 403 {
73 return Err(RainyError::Authentication {
74 code: "FEATURE_NOT_AVAILABLE".to_string(),
75 message: "Research feature requires a valid subscription".to_string(),
76 retryable: false,
77 });
78 }
79
80 self.handle_response(response).await
81 }
82}