openai_types/responses/
response.rs1use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7use super::create::{Reasoning, ResponseTextConfig};
8use super::output::{FunctionCall, ResponseOutputItem};
9use super::tools::{ResponseTool, ResponseToolChoice};
10
11#[derive(Debug, Clone, Deserialize, Serialize)]
13#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
14pub struct ResponseError {
15 pub code: String,
17 pub message: String,
19}
20
21#[derive(Debug, Clone, Deserialize, Serialize)]
23#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
24pub struct IncompleteDetails {
25 #[serde(default)]
27 pub reason: Option<String>,
28}
29
30#[derive(Debug, Clone, Deserialize, Serialize)]
32#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
33pub struct ResponseAnnotation {
34 #[serde(rename = "type")]
36 pub type_: String,
37 #[serde(default)]
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub start_index: Option<i64>,
41 #[serde(default)]
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub end_index: Option<i64>,
45 #[serde(default)]
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub url: Option<String>,
49 #[serde(default)]
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub title: Option<String>,
53 #[serde(default)]
55 #[serde(skip_serializing_if = "Option::is_none")]
56 pub file_id: Option<String>,
57}
58
59#[derive(Debug, Clone, Deserialize, Serialize)]
61#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
62pub struct InputTokensDetails {
63 #[serde(default)]
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub cached_tokens: Option<i64>,
67}
68
69#[derive(Debug, Clone, Deserialize, Serialize)]
71#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
72pub struct OutputTokensDetails {
73 #[serde(default)]
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub reasoning_tokens: Option<i64>,
77}
78
79#[derive(Debug, Clone, Deserialize, Serialize)]
81#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
82pub struct ResponseUsage {
83 #[serde(default)]
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub input_tokens: Option<i64>,
87 #[serde(default)]
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub output_tokens: Option<i64>,
91 #[serde(default)]
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub total_tokens: Option<i64>,
95 #[serde(default)]
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub input_tokens_details: Option<InputTokensDetails>,
99 #[serde(default)]
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub output_tokens_details: Option<OutputTokensDetails>,
103}
104
105#[derive(Debug, Clone, Deserialize, Serialize)]
107#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
108pub struct Response {
109 pub id: String,
111 pub object: String,
113 pub created_at: f64,
115 pub model: String,
117 pub output: Vec<ResponseOutputItem>,
119 #[serde(default)]
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub status: Option<String>,
123 #[serde(default)]
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub error: Option<ResponseError>,
127 #[serde(default)]
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub incomplete_details: Option<IncompleteDetails>,
131 #[serde(default)]
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub instructions: Option<String>,
135 #[serde(default)]
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub metadata: Option<HashMap<String, String>>,
139 #[serde(default)]
141 #[serde(skip_serializing_if = "Option::is_none")]
142 pub temperature: Option<f64>,
143 #[serde(default)]
145 #[serde(skip_serializing_if = "Option::is_none")]
146 pub top_p: Option<f64>,
147 #[serde(default)]
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub max_output_tokens: Option<i64>,
151 #[serde(default)]
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub previous_response_id: Option<String>,
155 #[serde(default)]
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub usage: Option<ResponseUsage>,
159 #[serde(default)]
161 #[serde(skip_serializing_if = "Option::is_none")]
162 pub tools: Option<Vec<ResponseTool>>,
163 #[serde(default)]
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub tool_choice: Option<ResponseToolChoice>,
167 #[serde(default)]
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub parallel_tool_calls: Option<bool>,
171 #[serde(default)]
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub truncation: Option<String>,
175 #[serde(default)]
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub reasoning: Option<Reasoning>,
179 #[serde(default)]
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub service_tier: Option<String>,
183 #[serde(default)]
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub text: Option<ResponseTextConfig>,
187 #[serde(default)]
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub completed_at: Option<f64>,
191 #[serde(default)]
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub background: Option<bool>,
195 #[serde(default)]
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub user: Option<String>,
199 #[serde(default)]
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub top_logprobs: Option<i64>,
203 #[serde(default)]
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub max_tool_calls: Option<i64>,
207}
208
209impl Response {
210 pub fn output_text(&self) -> String {
212 let mut result = String::new();
213 for item in &self.output {
214 if let Some(content) = &item.content {
215 for block in content {
216 if block.type_ == "output_text"
217 && let Some(text) = &block.text
218 {
219 result.push_str(text);
220 }
221 }
222 }
223 }
224 result
225 }
226
227 pub fn function_calls(&self) -> Vec<FunctionCall> {
229 self.output
230 .iter()
231 .filter(|item| item.type_ == "function_call")
232 .map(|item| {
233 let call_id = item
234 .call_id
235 .as_deref()
236 .or(item.id.as_deref())
237 .unwrap_or("unknown")
238 .to_string();
239 let name = item.name.clone().unwrap_or_default();
240 let arguments = item
241 .arguments
242 .as_deref()
243 .and_then(|s| serde_json::from_str(s).ok())
244 .unwrap_or(serde_json::Value::Object(Default::default()));
245 FunctionCall {
246 call_id,
247 name,
248 arguments,
249 }
250 })
251 .collect()
252 }
253
254 pub fn has_function_calls(&self) -> bool {
256 self.output.iter().any(|item| item.type_ == "function_call")
257 }
258}
259
260pub type InputTokenDetails = InputTokensDetails;
264pub type OutputTokenDetails = OutputTokensDetails;