1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use serde_json::Value;
7
8use crate::error::WebSocketError;
9use crate::json_payload::JsonPayload;
10
11#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
13pub struct WebSocketServerEvent {
14 #[serde(rename = "type", default)]
16 pub event_type: String,
17 #[serde(flatten)]
19 pub data: BTreeMap<String, Value>,
20}
21
22impl WebSocketServerEvent {
23 pub fn is_error(&self) -> bool {
25 self.event_type == "error"
26 }
27
28 pub fn error_message(&self) -> Option<String> {
30 self.data
31 .get("error")
32 .and_then(|value| {
33 value
34 .get("message")
35 .or_else(|| value.get("error"))
36 .or_else(|| value.get("detail"))
37 })
38 .or_else(|| self.data.get("message"))
39 .and_then(Value::as_str)
40 .map(str::to_owned)
41 }
42}
43
44#[derive(Debug, Clone, PartialEq)]
46pub struct ResponseCreatedEvent {
47 pub id: Option<String>,
49 pub response: Option<JsonPayload>,
51 pub raw: WebSocketServerEvent,
53}
54
55#[derive(Debug, Clone, PartialEq)]
57pub struct ResponseOutputTextDeltaEvent {
58 pub delta: Option<String>,
60 pub response_id: Option<String>,
62 pub item_id: Option<String>,
64 pub raw: WebSocketServerEvent,
66}
67
68#[derive(Debug, Clone, PartialEq)]
70pub struct SessionCreatedEvent {
71 pub id: Option<String>,
73 pub session: Option<JsonPayload>,
75 pub raw: WebSocketServerEvent,
77}
78
79#[derive(Debug, Clone, PartialEq)]
81pub enum RealtimeServerEvent {
82 SessionCreated(SessionCreatedEvent),
84 ResponseCreated(ResponseCreatedEvent),
86 ResponseOutputTextDelta(ResponseOutputTextDeltaEvent),
88 Unknown(WebSocketServerEvent),
90}
91
92#[derive(Debug, Clone, PartialEq)]
94pub enum ResponsesServerEvent {
95 ResponseCreated(ResponseCreatedEvent),
97 ResponseOutputTextDelta(ResponseOutputTextDeltaEvent),
99 Unknown(WebSocketServerEvent),
101}
102
103impl RealtimeServerEvent {
104 pub fn event_type(&self) -> &str {
106 self.raw().event_type.as_str()
107 }
108
109 pub fn raw(&self) -> &WebSocketServerEvent {
111 match self {
112 Self::SessionCreated(event) => &event.raw,
113 Self::ResponseCreated(event) => &event.raw,
114 Self::ResponseOutputTextDelta(event) => &event.raw,
115 Self::Unknown(event) => event,
116 }
117 }
118}
119
120impl ResponsesServerEvent {
121 pub fn event_type(&self) -> &str {
123 self.raw().event_type.as_str()
124 }
125
126 pub fn raw(&self) -> &WebSocketServerEvent {
128 match self {
129 Self::ResponseCreated(event) => &event.raw,
130 Self::ResponseOutputTextDelta(event) => &event.raw,
131 Self::Unknown(event) => event,
132 }
133 }
134}
135
136impl From<WebSocketServerEvent> for RealtimeServerEvent {
137 fn from(raw: WebSocketServerEvent) -> Self {
138 match raw.event_type.as_str() {
139 "session.created" => Self::SessionCreated(SessionCreatedEvent {
140 id: extract_event_string(&raw, "id").or_else(|| {
141 raw.data
142 .get("session")
143 .and_then(|value| value.get("id"))
144 .and_then(Value::as_str)
145 .map(str::to_owned)
146 }),
147 session: raw.data.get("session").cloned().map(JsonPayload::from),
148 raw,
149 }),
150 "response.created" => Self::ResponseCreated(ResponseCreatedEvent {
151 id: extract_event_string(&raw, "id").or_else(|| {
152 raw.data
153 .get("response")
154 .and_then(|value| value.get("id"))
155 .and_then(Value::as_str)
156 .map(str::to_owned)
157 }),
158 response: raw.data.get("response").cloned().map(JsonPayload::from),
159 raw,
160 }),
161 "response.output_text.delta" => {
162 Self::ResponseOutputTextDelta(ResponseOutputTextDeltaEvent {
163 delta: extract_event_string(&raw, "delta"),
164 response_id: extract_event_string(&raw, "response_id"),
165 item_id: extract_event_string(&raw, "item_id"),
166 raw,
167 })
168 }
169 _ => Self::Unknown(raw),
170 }
171 }
172}
173
174impl From<WebSocketServerEvent> for ResponsesServerEvent {
175 fn from(raw: WebSocketServerEvent) -> Self {
176 match raw.event_type.as_str() {
177 "response.created" => Self::ResponseCreated(ResponseCreatedEvent {
178 id: extract_event_string(&raw, "id").or_else(|| {
179 raw.data
180 .get("response")
181 .and_then(|value| value.get("id"))
182 .and_then(Value::as_str)
183 .map(str::to_owned)
184 }),
185 response: raw.data.get("response").cloned().map(JsonPayload::from),
186 raw,
187 }),
188 "response.output_text.delta" => {
189 Self::ResponseOutputTextDelta(ResponseOutputTextDeltaEvent {
190 delta: extract_event_string(&raw, "delta"),
191 response_id: extract_event_string(&raw, "response_id"),
192 item_id: extract_event_string(&raw, "item_id"),
193 raw,
194 })
195 }
196 _ => Self::Unknown(raw),
197 }
198 }
199}
200
201impl<'de> Deserialize<'de> for RealtimeServerEvent {
202 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
203 where
204 D: Deserializer<'de>,
205 {
206 WebSocketServerEvent::deserialize(deserializer).map(Self::from)
207 }
208}
209
210impl<'de> Deserialize<'de> for ResponsesServerEvent {
211 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
212 where
213 D: Deserializer<'de>,
214 {
215 WebSocketServerEvent::deserialize(deserializer).map(Self::from)
216 }
217}
218
219impl Serialize for RealtimeServerEvent {
220 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
221 where
222 S: Serializer,
223 {
224 self.raw().serialize(serializer)
225 }
226}
227
228impl Serialize for ResponsesServerEvent {
229 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
230 where
231 S: Serializer,
232 {
233 self.raw().serialize(serializer)
234 }
235}
236
237fn extract_event_string(raw: &WebSocketServerEvent, key: &str) -> Option<String> {
238 raw.data.get(key).and_then(Value::as_str).map(str::to_owned)
239}
240
241#[derive(Debug, Clone)]
243pub enum SocketStreamMessage<T> {
244 Connecting,
246 Open,
248 Closing,
250 Close,
252 Message(T),
254 Error(WebSocketError),
256}
257
258pub type RealtimeStreamMessage = SocketStreamMessage<RealtimeServerEvent>;
260
261pub type ResponsesStreamMessage = SocketStreamMessage<ResponsesServerEvent>;
263
264#[derive(Debug, Clone)]
266pub struct SocketCloseOptions {
267 pub code: u16,
269 pub reason: String,
271}
272
273impl Default for SocketCloseOptions {
274 fn default() -> Self {
275 Self {
276 code: 1000,
277 reason: "OK".into(),
278 }
279 }
280}