1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "snake_case")]
16pub enum ItemType {
17 Message,
19 FunctionCall,
21 FunctionCallOutput,
23 Reasoning,
25 ItemReference,
27 #[serde(other)]
29 Unknown,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(rename_all = "lowercase")]
35pub enum MessageRole {
36 User,
37 Assistant,
38 System,
39 Developer,
40 #[serde(other)]
42 Unknown,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47#[serde(rename_all = "snake_case")]
48pub enum ItemStatus {
49 InProgress,
50 Completed,
51 Failed,
52 #[serde(other)]
54 Unknown,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(rename_all = "snake_case")]
60pub enum FunctionCallStatus {
61 InProgress,
62 Completed,
63 Failed,
64 #[serde(other)]
66 Unknown,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct InputTextContent {
76 #[serde(rename = "type")]
77 content_type: String, text: String,
79}
80
81impl InputTextContent {
82 fn new(text: impl Into<String>) -> Self {
83 Self {
84 content_type: "input_text".to_string(),
85 text: text.into(),
86 }
87 }
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct OutputTextContent {
93 #[serde(rename = "type")]
94 content_type: String, text: String,
96 #[serde(skip_serializing_if = "Option::is_none")]
97 annotations: Option<Vec<Annotation>>,
98}
99
100impl OutputTextContent {
101 pub fn new(text: impl Into<String>) -> Self {
102 Self {
103 content_type: "output_text".to_string(),
104 text: text.into(),
105 annotations: None,
106 }
107 }
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct RefusalContent {
113 #[serde(rename = "type")]
114 content_type: String, refusal: String,
116}
117
118#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "lowercase")]
121pub enum ImageDetail {
122 Low,
123 High,
124 Auto,
125 Original,
126 #[serde(other)]
128 Unknown,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct InputImageContent {
134 #[serde(rename = "type")]
135 content_type: String, #[serde(skip_serializing_if = "Option::is_none")]
137 image_url: Option<String>,
138 #[serde(skip_serializing_if = "Option::is_none")]
139 detail: Option<ImageDetail>,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct InputFileContent {
145 #[serde(rename = "type")]
146 content_type: String, #[serde(skip_serializing_if = "Option::is_none")]
148 filename: Option<String>,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 file_id: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 file_data: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 file_url: Option<String>,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159#[serde(tag = "type")]
160pub enum Annotation {
161 #[serde(rename = "url_citation")]
162 UrlCitation {
163 start_index: usize,
164 end_index: usize,
165 url: String,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 title: Option<String>,
168 },
169 #[serde(other)]
171 Unknown,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
176#[serde(untagged)]
177pub enum InputContent {
178 Text(InputTextContent),
179 Image(InputImageContent),
180 File(InputFileContent),
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
185#[serde(untagged)]
186pub enum OutputContent {
187 Text(OutputTextContent),
188 Refusal(RefusalContent),
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct UserMessageItemParam {
198 #[serde(rename = "type")]
199 item_type: String, role: String, content: Vec<InputContent>,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 id: Option<String>,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 status: Option<String>,
206}
207
208impl UserMessageItemParam {
209 fn new(text: impl Into<String>) -> Self {
210 Self {
211 item_type: "message".to_string(),
212 role: "user".to_string(),
213 content: vec![InputContent::Text(InputTextContent::new(text))],
214 id: None,
215 status: None,
216 }
217 }
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct SystemMessageItemParam {
223 #[serde(rename = "type")]
224 item_type: String, role: String, content: Vec<InputTextContent>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 id: Option<String>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 status: Option<String>,
231}
232
233impl SystemMessageItemParam {
234 pub fn new(text: impl Into<String>) -> Self {
235 Self {
236 item_type: "message".to_string(),
237 role: "system".to_string(),
238 content: vec![InputTextContent::new(text)],
239 id: None,
240 status: None,
241 }
242 }
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
247pub struct DeveloperMessageItemParam {
248 #[serde(rename = "type")]
249 item_type: String, role: String, content: Vec<InputTextContent>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 id: Option<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 status: Option<String>,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct AssistantMessageItemParam {
261 #[serde(rename = "type")]
262 item_type: String, role: String, content: Vec<OutputContent>,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 id: Option<String>,
267 #[serde(skip_serializing_if = "Option::is_none")]
268 status: Option<String>,
269}
270
271impl AssistantMessageItemParam {
272 pub fn new(text: impl Into<String>) -> Self {
273 Self {
274 item_type: "message".to_string(),
275 role: "assistant".to_string(),
276 content: vec![OutputContent::Text(OutputTextContent::new(text))],
277 id: None,
278 status: None,
279 }
280 }
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct FunctionCallItemParam {
286 #[serde(rename = "type")]
287 item_type: String, id: String,
289 call_id: String,
290 name: String,
291 arguments: String,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 status: Option<FunctionCallStatus>,
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct FunctionCallOutputItemParam {
299 #[serde(rename = "type")]
300 item_type: String, call_id: String,
302 output: String,
303 #[serde(skip_serializing_if = "Option::is_none")]
304 id: Option<String>,
305 #[serde(skip_serializing_if = "Option::is_none")]
306 status: Option<FunctionCallStatus>,
307}
308
309impl FunctionCallOutputItemParam {
310 fn new(call_id: impl Into<String>, output: impl Into<String>) -> Self {
311 Self {
312 item_type: "function_call_output".to_string(),
313 call_id: call_id.into(),
314 output: output.into(),
315 id: None,
316 status: None,
317 }
318 }
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct ReasoningSummaryContent {
324 #[serde(rename = "type")]
325 content_type: String, text: String,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct ReasoningItemParam {
332 #[serde(rename = "type")]
333 item_type: String, summary: Vec<ReasoningSummaryContent>,
335 #[serde(skip_serializing_if = "Option::is_none")]
336 id: Option<String>,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 content: Option<Value>,
339 #[serde(skip_serializing_if = "Option::is_none")]
340 encrypted_content: Option<String>,
341 #[serde(skip_serializing_if = "Option::is_none")]
342 usage: Option<ReasoningUsage>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct ReasoningUsage {
348 #[serde(skip_serializing_if = "Option::is_none")]
349 input_tokens: Option<u32>,
350 #[serde(skip_serializing_if = "Option::is_none")]
351 output_tokens: Option<u32>,
352 #[serde(skip_serializing_if = "Option::is_none")]
353 total_tokens: Option<u32>,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct ItemReferenceParam {
359 #[serde(rename = "type")]
360 item_type: String, id: String,
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize)]
366#[serde(untagged)]
367pub enum ItemParam {
368 UserMessage(UserMessageItemParam),
369 SystemMessage(SystemMessageItemParam),
370 DeveloperMessage(DeveloperMessageItemParam),
371 AssistantMessage(AssistantMessageItemParam),
372 FunctionCall(FunctionCallItemParam),
373 FunctionCallOutput(FunctionCallOutputItemParam),
374 Reasoning(ReasoningItemParam),
375 ItemReference(ItemReferenceParam),
376}
377
378#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct FunctionToolParam {
385 #[serde(rename = "type")]
386 tool_type: String, name: String,
388 #[serde(skip_serializing_if = "Option::is_none")]
389 description: Option<String>,
390 #[serde(skip_serializing_if = "Option::is_none")]
391 parameters: Option<Value>,
392 #[serde(skip_serializing_if = "Option::is_none")]
393 strict: Option<bool>,
394}
395
396impl FunctionToolParam {
397 fn new(name: impl Into<String>) -> Self {
398 Self {
399 tool_type: "function".to_string(),
400 name: name.into(),
401 description: None,
402 parameters: None,
403 strict: None,
404 }
405 }
406
407 fn with_description(mut self, description: impl Into<String>) -> Self {
408 self.description = Some(description.into());
409 self
410 }
411
412 fn with_parameters(mut self, parameters: Value) -> Self {
413 self.parameters = Some(parameters);
414 self
415 }
416
417 pub fn with_strict(mut self, strict: bool) -> Self {
418 self.strict = Some(strict);
419 self
420 }
421}
422
423#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
425#[serde(rename_all = "lowercase")]
426pub enum ToolChoiceValue {
427 Auto,
428 None,
429 Required,
430 #[serde(other)]
432 Unknown,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
437pub struct SpecificFunctionChoice {
438 #[serde(rename = "type")]
439 choice_type: String, name: String,
441}
442
443#[derive(Debug, Clone, Serialize, Deserialize)]
445#[serde(untagged)]
446pub enum ToolChoiceParam {
447 Value(ToolChoiceValue),
448 Specific(SpecificFunctionChoice),
449}
450
451#[derive(Debug, Clone, Serialize, Deserialize)]
453pub struct IncompleteDetails {
454 #[serde(skip_serializing_if = "Option::is_none")]
455 reason: Option<String>,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize)]
460pub struct ResponseError {
461 code: String,
462 message: String,
463}
464
465#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
467#[serde(rename_all = "snake_case")]
468pub enum ResponseStatus {
469 Queued,
470 #[default]
471 InProgress,
472 Completed,
473 Failed,
474 Cancelled,
475 #[serde(other)]
477 Unknown,
478}
479
480#[derive(Debug, Clone, Serialize, Deserialize)]
482pub struct OpenResponsesResponse {
483 id: String,
484 object: String, #[serde(default)]
486 status: ResponseStatus,
487 output: Vec<Value>,
488 #[serde(skip_serializing_if = "Option::is_none")]
489 usage: Option<ResponseUsage>,
490 #[serde(skip_serializing_if = "Option::is_none")]
491 error: Option<ResponseError>,
492 #[serde(skip_serializing_if = "Option::is_none")]
493 incomplete_details: Option<IncompleteDetails>,
494 #[serde(skip_serializing_if = "Option::is_none")]
495 model: Option<String>,
496 #[serde(skip_serializing_if = "Option::is_none")]
497 created_at: Option<u64>,
498 #[serde(skip_serializing_if = "Option::is_none")]
499 metadata: Option<Value>,
500}
501
502#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct ResponseUsage {
505 input_tokens: u64,
506 output_tokens: u64,
507 #[serde(skip_serializing_if = "Option::is_none")]
508 input_tokens_details: Option<Value>,
509 #[serde(skip_serializing_if = "Option::is_none")]
510 output_tokens_details: Option<Value>,
511}
512
513#[cfg(test)]
514mod tests {
515 use super::*;
516 use serde_json::json;
517
518 #[test]
519 fn test_user_message_serialization() {
520 let msg = UserMessageItemParam::new("Hello, world!");
521 let json = serde_json::to_value(&msg).unwrap();
522 assert_eq!(json["type"], "message");
523 assert_eq!(json["role"], "user");
524 assert_eq!(json["content"][0]["type"], "input_text");
525 assert_eq!(json["content"][0]["text"], "Hello, world!");
526 }
527
528 #[test]
529 fn test_function_tool_param() {
530 let tool = FunctionToolParam::new("get_weather")
531 .with_description("Get the current weather")
532 .with_parameters(json!({
533 "type": "object",
534 "properties": {
535 "location": {"type": "string"}
536 }
537 }));
538
539 let json = serde_json::to_value(&tool).unwrap();
540 assert_eq!(json["type"], "function");
541 assert_eq!(json["name"], "get_weather");
542 assert!(json["description"].is_string());
543 }
544
545 #[test]
546 fn test_function_call_output() {
547 let output = FunctionCallOutputItemParam::new("call_123", r#"{"temperature": 72}"#);
548 let json = serde_json::to_value(&output).unwrap();
549 assert_eq!(json["type"], "function_call_output");
550 assert_eq!(json["call_id"], "call_123");
551 }
552}