1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
// src/components/output.rs
//! Structures related to output items generated by the model, such as messages, tool calls, and annotations.
/// Define a private namespace for all its items.
mod private
{
use crate::components::common::{ VectorStoreFileAttributes, Reasoning };
use crate::components::input::ListedInputContentPart;
use crate::components::responses::OutputMessage;
use crate::components::tools::
{
FileSearchToolCall,
FunctionToolCall,
WebSearchToolCall,
ComputerToolCall,
};
// Standard library imports
use core::fmt;
// Serde imports
use serde::{ Deserialize, Serialize };
use serde::
{
de ::{ self, Deserializer, MapAccess, Visitor },
};
// --- Annotation Structs (Restored) ---
/// Inner data for a file citation annotation.
///
/// # Used By
/// - `Annotation::FileCitation`
/// - `MessageContentTextAnnotationsFileCitationObject` (within `assistants_shared.rs`)
#[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
pub struct FileCitationAnnotation
{
/// The ID of the specific File the citation is from.
pub file_id : String,
}
/// Inner data for a URL citation annotation.
///
/// # Used By
/// - `Annotation::UrlCitation`
/// - `ChatCompletionResponseMessage` (within `chat_shared.rs`)
#[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
pub struct UrlCitationAnnotation
{
/// The URL of the web resource.
pub url : String,
/// The title of the web resource.
pub title : String,
}
/// Inner data for a file path annotation.
///
/// # Used By
/// - `Annotation::FilePath`
/// - `MessageContentTextAnnotationsFilePathObject` (within `assistants_shared.rs`)
#[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
pub struct FilePathAnnotation
{
/// The ID of the file that was generated.
pub file_id : String,
}
/// Represents annotations embedded within output text content.
/// These annotations provide context or references for parts of the text.
///
/// # Used By
/// - `OutputContentPart::Text`
/// - `MessageContentTextObject` (within `assistants_shared.rs`)
/// - `MessageDeltaTextContent` (within `assistants_shared.rs`)
/// - `ResponseTextAnnotationDeltaEvent` (within `realtime_shared.rs`)
#[ derive( Debug, Serialize, Clone, PartialEq ) ]
pub enum Annotation
{
/// A citation within the message that points to a specific quote from a specific File.
FileCitation
{
/// The text in the message content that needs to be replaced.
text : String,
/// The details of the file citation.
file_citation : FileCitationAnnotation,
/// The start index of the citation in the text.
start_index : u32,
/// The end index of the citation in the text.
end_index : u32,
},
/// A citation for a web resource used to generate a model response.
UrlCitation
{
/// The URL of the web resource.
url : String,
/// The title of the web resource.
title : String,
/// The start index of the citation in the text.
start_index : u32,
/// The end index of the citation in the text.
end_index : u32,
},
/// A URL for the file that's generated when the assistant used the `code_interpreter` tool.
FilePath
{
/// The text in the message content that needs to be replaced.
text : String,
/// The details of the file path.
file_path : FilePathAnnotation,
/// The start index of the file path in the text.
start_index : u32,
/// The end index of the file path in the text.
end_index : u32,
},
}
// Manual Deserialization for Annotation enum based on the 'type' field
impl< 'de > Deserialize< 'de > for Annotation
{
#[ allow( clippy::too_many_lines, reason = "Manual deserialization requires many lines." ) ]
#[ inline ]
fn deserialize< D >( deserializer : D ) -> Result< Self, D::Error >
where
D : Deserializer< 'de >,
{
#[ derive( Deserialize ) ]
#[ serde( field_identifier, rename_all = "snake_case" ) ]
enum Field
{
Type, Text, FileCitation, UrlCitation, FilePath, StartIndex, EndIndex, Url, Title
}
struct AnnotationVisitor;
impl< 'de > Visitor< 'de > for AnnotationVisitor
{
type Value = Annotation;
fn expecting( &self, formatter : &mut fmt::Formatter< '_ > ) -> fmt::Result
{
formatter.write_str( "struct Annotation" )
}
fn visit_map< V >( self, mut map : V ) -> Result< Annotation, V::Error >
where
V : MapAccess< 'de >,
{
let mut type_ : Option< String > = None;
let mut text : Option< String > = None;
let mut file_citation : Option< FileCitationAnnotation > = None;
let mut url_citation : Option< UrlCitationAnnotation > = None;
let mut file_path : Option< FilePathAnnotation > = None;
let mut start_index : Option< u32 > = None;
let mut end_index : Option< u32 > = None;
let mut url : Option< String > = None;
let mut title : Option< String > = None;
while let Some( key ) = map.next_key()?
{
match key
{
Field::Type =>
{
if type_.is_some() { Err( de::Error::duplicate_field( "type" ) )? }
type_ = Some( map.next_value()? );
}
Field::Text =>
{
if text.is_some() { Err( de::Error::duplicate_field( "text" ) )? }
text = Some( map.next_value()? );
}
Field::FileCitation =>
{
if file_citation.is_some() { Err( de::Error::duplicate_field( "file_citation" ) )? }
file_citation = Some( map.next_value()? );
}
Field::UrlCitation =>
{
if url_citation.is_some() { Err( de::Error::duplicate_field( "url_citation" ) )? }
url_citation = Some( map.next_value()? );
}
Field::FilePath =>
{
if file_path.is_some() { Err( de::Error::duplicate_field( "file_path" ) )? }
file_path = Some( map.next_value()? );
}
Field::StartIndex =>
{
if start_index.is_some() { Err( de::Error::duplicate_field( "start_index" ) )? }
start_index = Some( map.next_value()? );
}
Field::EndIndex =>
{
if end_index.is_some() { Err( de::Error::duplicate_field( "end_index" ) )? }
end_index = Some( map.next_value()? );
}
Field::Url =>
{
if url.is_some() { Err( de::Error::duplicate_field( "url" ) )? }
url = Some( map.next_value()? );
}
Field::Title =>
{
if title.is_some() { Err( de::Error::duplicate_field( "title" ) )? }
title = Some( map.next_value()? );
}
}
}
let type_ = type_.ok_or_else( || de::Error::missing_field( "type" ) )?;
let start_index = start_index.ok_or_else( || de::Error::missing_field( "start_index" ) )?;
let end_index = end_index.ok_or_else( || de::Error::missing_field( "end_index" ) )?;
match type_.as_str()
{
"file_citation" =>
{
let text = text.ok_or_else( || de::Error::missing_field( "text" ) )?;
let file_citation = file_citation.ok_or_else( || de::Error::missing_field( "file_citation" ) )?;
Ok( Annotation::FileCitation { text, file_citation, start_index, end_index } )
}
"url_citation" =>
{
let url = url.ok_or_else( || de::Error::missing_field( "url" ) )?;
let title = title.ok_or_else( || de::Error::missing_field( "title" ) )?;
Ok( Annotation::UrlCitation { url, title, start_index, end_index } )
}
"file_path" =>
{
let text = text.ok_or_else( || de::Error::missing_field( "text" ) )?;
let file_path = file_path.ok_or_else( || de::Error::missing_field( "file_path" ) )?;
Ok( Annotation::FilePath { text, file_path, start_index, end_index } )
}
_ => Err( de::Error::unknown_variant( &type_, &[ "file_citation", "url_citation", "file_path" ] ) ),
}
}
}
const FIELDS : &[ &str ] = &[ "type", "text", "file_citation", "url_citation", "file_path", "start_index", "end_index" ];
deserializer.deserialize_struct( "Annotation", FIELDS, AnnotationVisitor )
}
}
// --- OutputItem Enum (Added) ---
/// Represents the different types of items that can appear in the `output` array of a `Response`.
/// Corresponds to the `OutputItem` schema in the `OpenAPI` spec.
///
/// # Used By
/// - `Response` (within `responses.rs`)
#[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
#[ serde( tag = "type" ) ] // Use the 'type' field to discriminate variants
pub enum OutputItem
{
/// An output message from the model.
#[ serde( rename = "message" ) ]
Message( OutputMessage ), // Use definition from responses.rs
/// A call to the file search tool.
#[ serde( rename = "file_search_call" ) ]
FileSearchCall( FileSearchToolCall ),
/// A call to a function tool.
#[ serde( rename = "function_call" ) ]
FunctionCall( FunctionToolCall ),
/// A call to the web search tool.
#[ serde( rename = "web_search_call" ) ]
WebSearchCall( WebSearchToolCall ),
/// A call to the computer use tool.
#[ serde( rename = "computer_call" ) ]
ComputerCall( ComputerToolCall ),
/// Reasoning steps taken by the model.
#[ serde( rename = "reasoning" ) ]
Reasoning( Reasoning ), // Corrected name
}
// --- OutputContentPart Definition ---
/// Represents parts of the output content within a response message.
/// Corresponds to the `OutputContent` schema in the `OpenAPI` spec.
///
/// # Used By
/// - `OutputMessage` (within `responses.rs`)
#[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
#[ serde( tag = "type" ) ]
pub enum OutputContentPart
{
/// Text content generated by the model.
#[ serde( rename = "output_text" ) ]
Text
{
/// The text content.
text : String,
/// Any annotations associated with the text (e.g., citations).
#[ serde( default ) ]
annotations : Vec< Annotation >,
},
/// A refusal message generated by the model.
#[ serde( rename = "refusal" ) ]
Refusal
{
/// The refusal explanation.
refusal : String,
},
// Note : Other output types like audio might be added here in the future
}
// --- FileSearchResultItem (Moved from file_search.rs for dependency reasons) ---
// Note : Ideally, this would stay in file_search.rs, but OutputItem needs it.
// Consider refactoring later if this becomes problematic.
/// Represents a single item found during a file search.
///
/// # Used By
/// - `FileSearchToolCall` (within `tools/file_search.rs`)
#[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
pub struct FileSearchResultItem
{
/// The ID of the file containing the result.
pub file_id : String,
/// The name of the file containing the result.
pub filename : String,
/// The relevance score of the result (between 0 and 1).
pub score : f64,
/// Attributes associated with the file.
#[ serde( default ) ]
pub attributes : VectorStoreFileAttributes,
/// Content chunks from the file (only included if requested).
#[ serde( default ) ]
pub content : Vec< ListedInputContentPart >,
}
// --- ComputerScreenshotImage (Moved from computer_use.rs for dependency reasons) ---
// Note : Ideally, this would stay in computer_use.rs.
/// Represents the output of a computer tool action, typically a screenshot.
///
/// # Used By
/// - `ComputerToolCallOutput` (within `tools/computer_use.rs`)
#[ derive( Debug, Serialize, Deserialize, Clone, PartialEq ) ]
pub struct ComputerScreenshotImage
{
/// The URL of the screenshot image.
#[ serde( skip_serializing_if = "Option::is_none" ) ]
pub image_url : Option< String >,
/// The identifier of an uploaded file that contains the screenshot.
#[ serde( skip_serializing_if = "Option::is_none" ) ]
pub file_id : Option< String >,
}
} // end mod private
crate ::mod_interface!
{
exposed use
{
FileCitationAnnotation,
UrlCitationAnnotation,
FilePathAnnotation,
Annotation,
OutputItem,
OutputContentPart, // Expose the newly defined enum
// ReasoningItem, // No longer a placeholder here
// Expose moved structs
FileSearchResultItem,
ComputerScreenshotImage,
};
// Re-export types used within the exposed items
own use crate::components::
{
common ::{ VectorStoreFileAttributes, Reasoning }, // Corrected ReasoningItem to Reasoning
input ::ListedInputContentPart,
tools ::
{
FileSearchToolCall,
FunctionToolCall,
WebSearchToolCall,
ComputerToolCall,
},
// Import OutputMessage from responses.rs
responses ::OutputMessage,
};
}