Skip to main content

openai_core/websocket/
events.rs

1//! WebSocket event models and lifecycle message types.
2
3use 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/// 表示服务端推送的通用 WebSocket 事件。
12#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
13pub struct WebSocketServerEvent {
14    /// 事件类型。
15    #[serde(rename = "type", default)]
16    pub event_type: String,
17    /// 除 `type` 外的原始负载字段。
18    #[serde(flatten)]
19    pub data: BTreeMap<String, Value>,
20}
21
22impl WebSocketServerEvent {
23    /// 判断当前事件是否为错误事件。
24    pub fn is_error(&self) -> bool {
25        self.event_type == "error"
26    }
27
28    /// 尝试从错误事件中提取可读错误消息。
29    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/// 表示响应创建事件。
45#[derive(Debug, Clone, PartialEq)]
46pub struct ResponseCreatedEvent {
47    /// 响应 ID。
48    pub id: Option<String>,
49    /// 原始响应对象。
50    pub response: Option<JsonPayload>,
51    /// 原始事件。
52    pub raw: WebSocketServerEvent,
53}
54
55/// 表示输出文本增量事件。
56#[derive(Debug, Clone, PartialEq)]
57pub struct ResponseOutputTextDeltaEvent {
58    /// 文本增量。
59    pub delta: Option<String>,
60    /// 响应 ID。
61    pub response_id: Option<String>,
62    /// 输出项 ID。
63    pub item_id: Option<String>,
64    /// 原始事件。
65    pub raw: WebSocketServerEvent,
66}
67
68/// 表示会话创建事件。
69#[derive(Debug, Clone, PartialEq)]
70pub struct SessionCreatedEvent {
71    /// 会话 ID。
72    pub id: Option<String>,
73    /// 原始会话对象。
74    pub session: Option<JsonPayload>,
75    /// 原始事件。
76    pub raw: WebSocketServerEvent,
77}
78
79/// Realtime 服务端事件。
80#[derive(Debug, Clone, PartialEq)]
81pub enum RealtimeServerEvent {
82    /// 会话创建事件。
83    SessionCreated(SessionCreatedEvent),
84    /// 响应创建事件。
85    ResponseCreated(ResponseCreatedEvent),
86    /// 输出文本增量事件。
87    ResponseOutputTextDelta(ResponseOutputTextDeltaEvent),
88    /// 未知事件,保留原始负载以保证向前兼容。
89    Unknown(WebSocketServerEvent),
90}
91
92/// Responses 服务端事件。
93#[derive(Debug, Clone, PartialEq)]
94pub enum ResponsesServerEvent {
95    /// 响应创建事件。
96    ResponseCreated(ResponseCreatedEvent),
97    /// 输出文本增量事件。
98    ResponseOutputTextDelta(ResponseOutputTextDeltaEvent),
99    /// 未知事件,保留原始负载以保证向前兼容。
100    Unknown(WebSocketServerEvent),
101}
102
103impl RealtimeServerEvent {
104    /// 返回事件类型。
105    pub fn event_type(&self) -> &str {
106        self.raw().event_type.as_str()
107    }
108
109    /// 返回原始事件。
110    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    /// 返回事件类型。
122    pub fn event_type(&self) -> &str {
123        self.raw().event_type.as_str()
124    }
125
126    /// 返回原始事件。
127    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/// 表示 WebSocket 流中的生命周期或消息事件。
242#[derive(Debug, Clone)]
243pub enum SocketStreamMessage<T> {
244    /// 连接正在建立。
245    Connecting,
246    /// 连接已建立。
247    Open,
248    /// 连接正在关闭。
249    Closing,
250    /// 连接已经关闭。
251    Close,
252    /// 收到服务端消息。
253    Message(T),
254    /// 收到协议层或业务层错误。
255    Error(WebSocketError),
256}
257
258/// Realtime WebSocket 流消息。
259pub type RealtimeStreamMessage = SocketStreamMessage<RealtimeServerEvent>;
260
261/// Responses WebSocket 流消息。
262pub type ResponsesStreamMessage = SocketStreamMessage<ResponsesServerEvent>;
263
264/// 表示关闭 WebSocket 时附带的参数。
265#[derive(Debug, Clone)]
266pub struct SocketCloseOptions {
267    /// WebSocket close code。
268    pub code: u16,
269    /// 关闭原因。
270    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}