1use serde::{Deserialize, Serialize};
2
3use crate::engine::ThinkingStep;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6pub struct ResponseObject {
7 pub id: String,
8 pub object: String,
9 pub created_at: u64,
10 pub status: String,
11 pub model: String,
12 pub output: Vec<ResponseOutputItem>,
13 pub usage: ResponseUsage,
14 #[serde(default)]
15 pub evidence_links: Vec<String>,
16 #[serde(default, skip_serializing_if = "Vec::is_empty")]
17 pub thinking_steps: Vec<ThinkingStep>,
18}
19
20impl ResponseObject {
21 #[must_use]
23 pub fn output_messages(&self) -> Vec<&ResponseOutputMessage> {
24 self.output
25 .iter()
26 .filter_map(|item| match item {
27 ResponseOutputItem::Message(message) => Some(message),
28 ResponseOutputItem::FunctionCall(_)
29 | ResponseOutputItem::WebSearchCall(_)
30 | ResponseOutputItem::Reasoning(_) => None,
31 })
32 .collect()
33 }
34
35 #[must_use]
38 pub fn function_calls(&self) -> Vec<&ResponseFunctionToolCall> {
39 self.output
40 .iter()
41 .filter_map(|item| match item {
42 ResponseOutputItem::FunctionCall(call) => Some(call),
43 ResponseOutputItem::Message(_)
44 | ResponseOutputItem::WebSearchCall(_)
45 | ResponseOutputItem::Reasoning(_) => None,
46 })
47 .collect()
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(untagged)]
60pub enum ResponseOutputItem {
61 FunctionCall(ResponseFunctionToolCall),
63 WebSearchCall(ResponseWebSearchToolCall),
65 Message(ResponseOutputMessage),
67 Reasoning(ResponseReasoningItem),
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75pub struct ResponseWebSearchToolCall {
76 pub id: String,
77 #[serde(rename = "type")]
78 pub kind: String,
79 pub status: String,
80 pub action: ResponseWebSearchAction,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
84pub struct ResponseWebSearchAction {
85 #[serde(rename = "type")]
86 pub kind: String,
87 pub query: String,
88 pub queries: Vec<String>,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
96pub struct ResponseFunctionToolCall {
97 pub id: String,
98 #[serde(rename = "type", default = "function_call_kind")]
99 pub kind: String,
100 pub call_id: String,
101 pub name: String,
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub namespace: Option<String>,
104 pub arguments: String,
105 pub status: String,
106}
107
108pub(super) fn function_call_kind() -> String {
109 String::from("function_call")
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
113pub struct ResponseOutputMessage {
114 pub id: String,
115 #[serde(rename = "type")]
116 pub kind: String,
117 pub role: String,
118 pub content: Vec<ResponseOutputContent>,
119 #[serde(default, skip_serializing_if = "Vec::is_empty")]
120 pub thinking_steps: Vec<ThinkingStep>,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
124pub struct ResponseOutputContent {
125 #[serde(rename = "type")]
126 pub kind: String,
127 pub text: String,
128}
129
130#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub struct ResponseReasoningItem {
132 pub id: String,
133 #[serde(rename = "type")]
134 pub kind: String,
135 pub summary: Vec<ResponseReasoningSummaryText>,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
139pub struct ResponseReasoningSummaryText {
140 #[serde(rename = "type")]
141 pub kind: String,
142 pub text: String,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
146pub struct ResponseUsage {
147 pub input_tokens: u32,
148 pub output_tokens: u32,
149 pub total_tokens: u32,
150}