Skip to main content

codex_api/
search.rs

1use crate::common::Reasoning;
2use codex_protocol::models::ResponseItem;
3use schemars::JsonSchema;
4use serde::Deserialize;
5use serde::Serialize;
6use serde_json::Value as JsonValue;
7
8#[derive(Debug, Clone, Serialize, PartialEq)]
9pub struct SearchRequest {
10    pub id: String,
11    pub model: String,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub reasoning: Option<Reasoning>,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub input: Option<SearchInput>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub commands: Option<SearchCommands>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub settings: Option<SearchSettings>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub max_output_tokens: Option<u64>,
22}
23
24#[derive(Debug, Clone, Serialize, PartialEq)]
25#[serde(untagged)]
26pub enum SearchInput {
27    Text(String),
28    Items(Vec<ResponseItem>),
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, JsonSchema)]
32pub struct SearchCommands {
33    /// Query the internet search engine for a given list of queries.
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub search_query: Option<Vec<SearchQuery>>,
36    /// Query the image search engine for a given list of queries.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub image_query: Option<Vec<SearchQuery>>,
39    /// Open pages by reference id or URL.
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub open: Option<Vec<OpenOperation>>,
42    /// Open links from previously opened pages.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub click: Option<Vec<ClickOperation>>,
45    /// Find text patterns in pages.
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub find: Option<Vec<FindOperation>>,
48    /// Take screenshots of PDF pages.
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub screenshot: Option<Vec<ScreenshotOperation>>,
51    /// Look up prices for the given stock symbols.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub finance: Option<Vec<FinanceOperation>>,
54    /// Look up weather forecasts.
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub weather: Option<Vec<WeatherOperation>>,
57    /// Look up sports schedules and standings.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub sports: Option<Vec<SportsOperation>>,
60    /// Get time for the given UTC offsets.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub time: Option<Vec<TimeOperation>>,
63    /// Set the length of the response to be returned.
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub response_length: Option<SearchResponseLength>,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
69pub struct SearchQuery {
70    /// Search query.
71    pub q: String,
72    /// Whether to filter by recency, as a number of recent days.
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub recency: Option<u64>,
75    /// Whether to filter by a specific list of domains.
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub domains: Option<Vec<String>>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
81pub struct OpenOperation {
82    /// Reference id or URL to open.
83    pub ref_id: String,
84    /// Line number to position the page at.
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub lineno: Option<u64>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
90pub struct ClickOperation {
91    /// Reference id containing the numbered link.
92    pub ref_id: String,
93    /// Numbered link id to open.
94    pub id: u64,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
98pub struct FindOperation {
99    /// Reference id or URL to search within.
100    pub ref_id: String,
101    /// Text pattern to find.
102    pub pattern: String,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
106pub struct ScreenshotOperation {
107    /// Reference id or URL to screenshot.
108    pub ref_id: String,
109    /// Zero-indexed PDF page number.
110    pub pageno: u64,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
114pub struct FinanceOperation {
115    /// Ticker symbol to look up.
116    pub ticker: String,
117    /// Asset type to look up.
118    pub r#type: FinanceAssetType,
119    /// ISO 3166-1 alpha-3 country code, "OTC", or "" for cryptocurrency.
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub market: Option<String>,
122}
123
124#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
125#[serde(rename_all = "lowercase")]
126pub enum FinanceAssetType {
127    Equity,
128    Fund,
129    Crypto,
130    Index,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
134pub struct WeatherOperation {
135    /// Location in "Country, Area, City" format.
136    pub location: String,
137    /// Start date in YYYY-MM-DD format. Defaults to today.
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub start: Option<String>,
140    /// Number of days to return. Defaults to 7.
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub duration: Option<u64>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
146pub struct SportsOperation {
147    /// Tool name for sports requests.
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub tool: Option<SportsToolName>,
150    /// Sports function to call.
151    pub r#fn: SportsFunction,
152    /// League to look up.
153    pub league: SportsLeague,
154    /// Team to look up, using the common 3 or 4 letter alias used in broadcasts.
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub team: Option<String>,
157    /// Opponent to use with `team` when narrowing the lookup.
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub opponent: Option<String>,
160    /// Start date in YYYY-MM-DD format.
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub date_from: Option<String>,
163    /// End date in YYYY-MM-DD format.
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub date_to: Option<String>,
166    /// Number of games to return.
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub num_games: Option<u64>,
169    /// Locale for the lookup.
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub locale: Option<String>,
172}
173
174#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
175#[serde(rename_all = "lowercase")]
176pub enum SportsToolName {
177    Sports,
178}
179
180#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
181#[serde(rename_all = "lowercase")]
182pub enum SportsFunction {
183    Schedule,
184    Standings,
185}
186
187#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
188#[serde(rename_all = "lowercase")]
189pub enum SportsLeague {
190    Nba,
191    Wnba,
192    Nfl,
193    Nhl,
194    Mlb,
195    Epl,
196    Ncaamb,
197    Ncaawb,
198    Ipl,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
202pub struct TimeOperation {
203    /// UTC offset formatted like "+03:00".
204    pub utc_offset: String,
205}
206
207#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
208#[serde(rename_all = "lowercase")]
209pub enum SearchResponseLength {
210    Short,
211    Medium,
212    Long,
213}
214
215#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
216#[serde(rename_all = "snake_case")]
217pub enum ExternalWebAccessMode {
218    Cached,
219    Indexed,
220    Live,
221}
222
223#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
224#[serde(untagged)]
225pub enum ExternalWebAccess {
226    Boolean(bool),
227    Mode(ExternalWebAccessMode),
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
231pub struct SearchSettings {
232    #[serde(skip_serializing_if = "Option::is_none")]
233    pub user_location: Option<ApproximateLocation>,
234    #[serde(skip_serializing_if = "Option::is_none")]
235    pub search_context_size: Option<SearchContextSize>,
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub filters: Option<SearchFilters>,
238    #[serde(skip_serializing_if = "Option::is_none")]
239    pub image_settings: Option<SearchImageSettings>,
240    #[serde(skip_serializing_if = "Option::is_none")]
241    pub allowed_callers: Option<Vec<AllowedCaller>>,
242    #[serde(skip_serializing_if = "Option::is_none")]
243    pub external_web_access: Option<ExternalWebAccess>,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
247pub struct ApproximateLocation {
248    pub r#type: LocationType,
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub country: Option<String>,
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub region: Option<String>,
253    #[serde(skip_serializing_if = "Option::is_none")]
254    pub city: Option<String>,
255    #[serde(skip_serializing_if = "Option::is_none")]
256    pub timezone: Option<String>,
257}
258
259#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
260#[serde(rename_all = "lowercase")]
261pub enum LocationType {
262    Approximate,
263}
264
265#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
266#[serde(rename_all = "lowercase")]
267pub enum SearchContextSize {
268    Low,
269    Medium,
270    High,
271}
272
273#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
274pub struct SearchFilters {
275    #[serde(skip_serializing_if = "Option::is_none")]
276    pub allowed_domains: Option<Vec<String>>,
277    #[serde(skip_serializing_if = "Option::is_none")]
278    pub blocked_domains: Option<Vec<String>>,
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
282pub struct SearchImageSettings {
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub max_results: Option<u64>,
285    #[serde(skip_serializing_if = "Option::is_none")]
286    pub caption: Option<bool>,
287}
288
289#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
290#[serde(rename_all = "snake_case")]
291pub enum AllowedCaller {
292    Direct,
293    Shell,
294    CodeInterpreter,
295}
296
297#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
298pub struct SearchResponse {
299    pub encrypted_output: Option<String>,
300    pub output: String,
301    /// Structured result DTOs are passed to clients out-of-band from `output`.
302    /// Keep them opaque here so newer result variants remain forward-compatible.
303    #[serde(default)]
304    pub results: Option<Vec<JsonValue>>,
305}