1mod private
6{
7 use crate::components::common::{ VectorStoreFileAttributes, Reasoning };
8 use crate::components::input::ListedInputContentPart;
9 use crate::components::responses::OutputMessage;
10 use crate::components::tools::
11 {
12 FileSearchToolCall,
13 FunctionToolCall,
14 WebSearchToolCall,
15 ComputerToolCall,
16 };
17
18 use core::fmt;
20 use serde::{ Deserialize, Serialize };
22 use serde::
23 {
24 de ::{ self, Deserializer, MapAccess, Visitor },
25 };
26
27 #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
35 pub struct FileCitationAnnotation
36 {
37 pub file_id : String,
39 }
40
41 #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
47 pub struct UrlCitationAnnotation
48 {
49 pub url : String,
51 pub title : String,
53 }
54
55 #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
61 pub struct FilePathAnnotation
62 {
63 pub file_id : String,
65 }
66
67 #[ derive( Debug, Serialize, Clone, PartialEq ) ]
76 pub enum Annotation
77 {
78 FileCitation
80 {
81 text : String,
83 file_citation : FileCitationAnnotation,
85 start_index : u32,
87 end_index : u32,
89 },
90 UrlCitation
92 {
93 url : String,
95 title : String,
97 start_index : u32,
99 end_index : u32,
101 },
102 FilePath
104 {
105 text : String,
107 file_path : FilePathAnnotation,
109 start_index : u32,
111 end_index : u32,
113 },
114 }
115
116 impl< 'de > Deserialize< 'de > for Annotation
118 {
119 #[ allow( clippy::too_many_lines, reason = "Manual deserialization requires many lines." ) ]
120 #[ inline ]
121 fn deserialize< D >( deserializer : D ) -> Result< Self, D::Error >
122 where
123 D : Deserializer< 'de >,
124 {
125 #[ derive( Deserialize ) ]
126 #[ serde( field_identifier, rename_all = "snake_case" ) ]
127 enum Field
128 {
129 Type, Text, FileCitation, UrlCitation, FilePath, StartIndex, EndIndex, Url, Title
130 }
131
132 struct AnnotationVisitor;
133
134 impl< 'de > Visitor< 'de > for AnnotationVisitor
135 {
136 type Value = Annotation;
137
138 fn expecting( &self, formatter : &mut fmt::Formatter< '_ > ) -> fmt::Result
139 {
140 formatter.write_str( "struct Annotation" )
141 }
142
143 fn visit_map< V >( self, mut map : V ) -> Result< Annotation, V::Error >
144 where
145 V : MapAccess< 'de >,
146 {
147 let mut type_ : Option< String > = None;
148 let mut text : Option< String > = None;
149 let mut file_citation : Option< FileCitationAnnotation > = None;
150 let mut url_citation : Option< UrlCitationAnnotation > = None;
151 let mut file_path : Option< FilePathAnnotation > = None;
152 let mut start_index : Option< u32 > = None;
153 let mut end_index : Option< u32 > = None;
154 let mut url : Option< String > = None;
155 let mut title : Option< String > = None;
156
157 while let Some( key ) = map.next_key()?
158 {
159 match key
160 {
161 Field::Type =>
162 {
163 if type_.is_some() { Err( de::Error::duplicate_field( "type" ) )? }
164 type_ = Some( map.next_value()? );
165 }
166 Field::Text =>
167 {
168 if text.is_some() { Err( de::Error::duplicate_field( "text" ) )? }
169 text = Some( map.next_value()? );
170 }
171 Field::FileCitation =>
172 {
173 if file_citation.is_some() { Err( de::Error::duplicate_field( "file_citation" ) )? }
174 file_citation = Some( map.next_value()? );
175 }
176 Field::UrlCitation =>
177 {
178 if url_citation.is_some() { Err( de::Error::duplicate_field( "url_citation" ) )? }
179 url_citation = Some( map.next_value()? );
180 }
181 Field::FilePath =>
182 {
183 if file_path.is_some() { Err( de::Error::duplicate_field( "file_path" ) )? }
184 file_path = Some( map.next_value()? );
185 }
186 Field::StartIndex =>
187 {
188 if start_index.is_some() { Err( de::Error::duplicate_field( "start_index" ) )? }
189 start_index = Some( map.next_value()? );
190 }
191 Field::EndIndex =>
192 {
193 if end_index.is_some() { Err( de::Error::duplicate_field( "end_index" ) )? }
194 end_index = Some( map.next_value()? );
195 }
196 Field::Url =>
197 {
198 if url.is_some() { Err( de::Error::duplicate_field( "url" ) )? }
199 url = Some( map.next_value()? );
200 }
201 Field::Title =>
202 {
203 if title.is_some() { Err( de::Error::duplicate_field( "title" ) )? }
204 title = Some( map.next_value()? );
205 }
206 }
207 }
208
209 let type_ = type_.ok_or_else( || de::Error::missing_field( "type" ) )?;
210 let start_index = start_index.ok_or_else( || de::Error::missing_field( "start_index" ) )?;
211 let end_index = end_index.ok_or_else( || de::Error::missing_field( "end_index" ) )?;
212
213 match type_.as_str()
214 {
215 "file_citation" =>
216 {
217 let text = text.ok_or_else( || de::Error::missing_field( "text" ) )?;
218 let file_citation = file_citation.ok_or_else( || de::Error::missing_field( "file_citation" ) )?;
219 Ok( Annotation::FileCitation { text, file_citation, start_index, end_index } )
220 }
221 "url_citation" =>
222 {
223 let url = url.ok_or_else( || de::Error::missing_field( "url" ) )?;
224 let title = title.ok_or_else( || de::Error::missing_field( "title" ) )?;
225 Ok( Annotation::UrlCitation { url, title, start_index, end_index } )
226 }
227 "file_path" =>
228 {
229 let text = text.ok_or_else( || de::Error::missing_field( "text" ) )?;
230 let file_path = file_path.ok_or_else( || de::Error::missing_field( "file_path" ) )?;
231 Ok( Annotation::FilePath { text, file_path, start_index, end_index } )
232 }
233 _ => Err( de::Error::unknown_variant( &type_, &[ "file_citation", "url_citation", "file_path" ] ) ),
234 }
235 }
236 }
237
238 const FIELDS : &[ &str ] = &[ "type", "text", "file_citation", "url_citation", "file_path", "start_index", "end_index" ];
239 deserializer.deserialize_struct( "Annotation", FIELDS, AnnotationVisitor )
240 }
241 }
242
243 #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
251 #[ serde( tag = "type" ) ] pub enum OutputItem
253 {
254 #[ serde( rename = "message" ) ]
256 Message( OutputMessage ), #[ serde( rename = "file_search_call" ) ]
260 FileSearchCall( FileSearchToolCall ),
261
262 #[ serde( rename = "function_call" ) ]
264 FunctionCall( FunctionToolCall ),
265
266 #[ serde( rename = "web_search_call" ) ]
268 WebSearchCall( WebSearchToolCall ),
269
270 #[ serde( rename = "computer_call" ) ]
272 ComputerCall( ComputerToolCall ),
273
274 #[ serde( rename = "reasoning" ) ]
276 Reasoning( Reasoning ), }
278
279 #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
286 #[ serde( tag = "type" ) ]
287 pub enum OutputContentPart
288 {
289 #[ serde( rename = "output_text" ) ]
291 Text
292 {
293 text : String,
295 #[ serde( default ) ]
297 annotations : Vec< Annotation >,
298 },
299 #[ serde( rename = "refusal" ) ]
301 Refusal
302 {
303 refusal : String,
305 },
306 }
308
309 #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
317 pub struct FileSearchResultItem
318 {
319 pub file_id : String,
321 pub filename : String,
323 pub score : f64,
325 #[ serde( default ) ]
327 pub attributes : VectorStoreFileAttributes,
328 #[ serde( default ) ]
330 pub content : Vec< ListedInputContentPart >,
331 }
332
333 #[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
340 pub struct ComputerScreenshotImage
341 {
342 #[ serde( skip_serializing_if = "Option::is_none" ) ]
344 pub image_url : Option< String >,
345 #[ serde( skip_serializing_if = "Option::is_none" ) ]
347 pub file_id : Option< String >,
348 }
349
350
351} crate ::mod_interface!
354{
355 exposed use
356 {
357 FileCitationAnnotation,
358 UrlCitationAnnotation,
359 FilePathAnnotation,
360 Annotation,
361 OutputItem,
362 OutputContentPart, FileSearchResultItem,
366 ComputerScreenshotImage,
367 };
368
369 own use crate::components::
371 {
372 common ::{ VectorStoreFileAttributes, Reasoning }, input ::ListedInputContentPart,
374 tools ::
375 {
376 FileSearchToolCall,
377 FunctionToolCall,
378 WebSearchToolCall,
379 ComputerToolCall,
380 },
381 responses ::OutputMessage,
383 };
384}