Skip to main content

exa_async/types/
search.rs

1//! Types for the Exa `/search` endpoint
2
3use serde::Deserialize;
4use serde::Serialize;
5
6use super::common::ContentsOptions;
7use super::common::LivecrawlOption;
8use super::common::SearchResult;
9use super::common::SearchType;
10
11// Backward-compatible re-exports (CostDollars previously lived in this module)
12pub use super::common::CostDollars;
13pub use super::common::CostDollarsContents;
14pub use super::common::CostDollarsSearch;
15
16/// Request body for `POST /search`
17#[derive(Debug, Clone, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19pub struct SearchRequest {
20    /// The search query (natural language)
21    pub query: String,
22
23    /// Number of results to return (default: 10)
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub num_results: Option<u32>,
26
27    /// Type of search
28    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
29    pub search_type: Option<SearchType>,
30
31    /// What content to include in results
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub contents: Option<ContentsOptions>,
34
35    /// Include domains filter
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub include_domains: Option<Vec<String>>,
38
39    /// Exclude domains filter
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub exclude_domains: Option<Vec<String>>,
42
43    /// Start date filter (ISO 8601)
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub start_published_date: Option<String>,
46
47    /// End date filter (ISO 8601)
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub end_published_date: Option<String>,
50
51    /// Livecrawl option
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub livecrawl: Option<LivecrawlOption>,
54
55    /// Category filter
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub category: Option<String>,
58}
59
60impl SearchRequest {
61    /// Create a new search request with the given query
62    #[must_use]
63    pub fn new(query: impl Into<String>) -> Self {
64        Self {
65            query: query.into(),
66            num_results: None,
67            search_type: None,
68            contents: None,
69            include_domains: None,
70            exclude_domains: None,
71            start_published_date: None,
72            end_published_date: None,
73            livecrawl: None,
74            category: None,
75        }
76    }
77
78    /// Set the number of results
79    #[must_use]
80    pub const fn with_num_results(mut self, n: u32) -> Self {
81        self.num_results = Some(n);
82        self
83    }
84
85    /// Set the search type
86    #[must_use]
87    pub const fn with_search_type(mut self, st: SearchType) -> Self {
88        self.search_type = Some(st);
89        self
90    }
91
92    /// Set the contents options
93    #[must_use]
94    pub fn with_contents(mut self, contents: ContentsOptions) -> Self {
95        self.contents = Some(contents);
96        self
97    }
98}
99
100/// Response from `POST /search`
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct SearchResponse {
104    /// Search results
105    pub results: Vec<SearchResult>,
106
107    /// Autoprompt context (orientation text generated by Exa)
108    #[serde(default)]
109    pub autoprompt_string: Option<String>,
110
111    /// Cost in dollars for this request
112    #[serde(default)]
113    pub cost_dollars: Option<CostDollars>,
114
115    /// Resolved search type used
116    #[serde(default)]
117    pub resolved_search_type: Option<String>,
118}