Skip to main content

gproxy_protocol/protocol/openai/generate_content/
stream.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize, de};
4use serde_json::Value;
5
6use super::super::common::*;
7use super::{
8    ResponseContentPart, ResponseObject, ResponseOutputItem, ResponseReasoningSummaryPart,
9};
10
11#[derive(Debug, Clone, PartialEq)]
12pub enum ResponseStreamEvent {
13    Known(KnownResponseStreamEvent),
14    Unknown(UnknownResponseStreamEvent),
15}
16
17impl ResponseStreamEvent {
18    /// SSE event name: the wire `type` of this event, if any.
19    pub fn event_name(&self) -> Option<&str> {
20        match self {
21            Self::Known(event) => Some(event.event_name()),
22            Self::Unknown(event) => event.type_.as_ref().map(ResponseStreamEventType::as_str),
23        }
24    }
25}
26
27impl Serialize for ResponseStreamEvent {
28    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
29    where
30        S: serde::Serializer,
31    {
32        match self {
33            Self::Known(event) => event.serialize(serializer),
34            Self::Unknown(event) => event.serialize(serializer),
35        }
36    }
37}
38
39impl<'de> Deserialize<'de> for ResponseStreamEvent {
40    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
41    where
42        D: serde::Deserializer<'de>,
43    {
44        let value = Value::deserialize(deserializer)?;
45        let Some(type_name) = value.get("type").and_then(Value::as_str) else {
46            return serde_json::from_value(value)
47                .map(Self::Unknown)
48                .map_err(de::Error::custom);
49        };
50
51        let event_type =
52            serde_json::from_value::<ResponseStreamEventType>(Value::String(type_name.to_owned()))
53                .map_err(de::Error::custom)?;
54
55        match event_type {
56            ResponseStreamEventType::Known(_) => serde_json::from_value(value)
57                .map(Self::Known)
58                .map_err(de::Error::custom),
59            ResponseStreamEventType::Unknown(_) => serde_json::from_value(value)
60                .map(Self::Unknown)
61                .map_err(de::Error::custom),
62        }
63    }
64}
65
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
67#[serde(tag = "type")]
68pub enum KnownResponseStreamEvent {
69    #[serde(rename = "response.created")]
70    ResponseCreated {
71        response: Box<ResponseObject>,
72        #[serde(skip_serializing_if = "Option::is_none")]
73        sequence_number: Option<u64>,
74        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
75        extra: Extra,
76    },
77    #[serde(rename = "response.in_progress")]
78    ResponseInProgress {
79        response: Box<ResponseObject>,
80        #[serde(skip_serializing_if = "Option::is_none")]
81        sequence_number: Option<u64>,
82        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
83        extra: Extra,
84    },
85    #[serde(rename = "response.completed")]
86    ResponseCompleted {
87        response: Box<ResponseObject>,
88        #[serde(skip_serializing_if = "Option::is_none")]
89        sequence_number: Option<u64>,
90        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
91        extra: Extra,
92    },
93    #[serde(rename = "response.failed")]
94    ResponseFailed {
95        response: Box<ResponseObject>,
96        #[serde(skip_serializing_if = "Option::is_none")]
97        sequence_number: Option<u64>,
98        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
99        extra: Extra,
100    },
101    #[serde(rename = "response.incomplete")]
102    ResponseIncomplete {
103        response: Box<ResponseObject>,
104        #[serde(skip_serializing_if = "Option::is_none")]
105        sequence_number: Option<u64>,
106        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
107        extra: Extra,
108    },
109    #[serde(rename = "response.queued")]
110    ResponseQueued {
111        response: Box<ResponseObject>,
112        #[serde(skip_serializing_if = "Option::is_none")]
113        sequence_number: Option<u64>,
114        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
115        extra: Extra,
116    },
117    #[serde(rename = "response.output_item.added")]
118    ResponseOutputItemAdded {
119        item: Box<ResponseOutputItem>,
120        output_index: u32,
121        #[serde(skip_serializing_if = "Option::is_none")]
122        sequence_number: Option<u64>,
123        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
124        extra: Extra,
125    },
126    #[serde(rename = "response.output_item.done")]
127    ResponseOutputItemDone {
128        item: Box<ResponseOutputItem>,
129        output_index: u32,
130        #[serde(skip_serializing_if = "Option::is_none")]
131        sequence_number: Option<u64>,
132        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
133        extra: Extra,
134    },
135    #[serde(rename = "response.content_part.added")]
136    ResponseContentPartAdded {
137        content_index: u32,
138        item_id: String,
139        output_index: u32,
140        part: ResponseContentPart,
141        #[serde(skip_serializing_if = "Option::is_none")]
142        sequence_number: Option<u64>,
143        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
144        extra: Extra,
145    },
146    #[serde(rename = "response.content_part.done")]
147    ResponseContentPartDone {
148        content_index: u32,
149        item_id: String,
150        output_index: u32,
151        part: ResponseContentPart,
152        #[serde(skip_serializing_if = "Option::is_none")]
153        sequence_number: Option<u64>,
154        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
155        extra: Extra,
156    },
157    #[serde(rename = "response.output_text.delta")]
158    ResponseOutputTextDelta {
159        content_index: u32,
160        delta: String,
161        item_id: String,
162        #[serde(skip_serializing_if = "Option::is_none")]
163        logprobs: Option<Vec<StreamTokenLogprob>>,
164        output_index: u32,
165        #[serde(skip_serializing_if = "Option::is_none")]
166        sequence_number: Option<u64>,
167        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
168        extra: Extra,
169    },
170    #[serde(rename = "response.output_text.done")]
171    ResponseOutputTextDone {
172        content_index: u32,
173        item_id: String,
174        #[serde(skip_serializing_if = "Option::is_none")]
175        logprobs: Option<Vec<StreamTokenLogprob>>,
176        output_index: u32,
177        #[serde(skip_serializing_if = "Option::is_none")]
178        sequence_number: Option<u64>,
179        text: String,
180        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
181        extra: Extra,
182    },
183    #[serde(rename = "response.output_text.annotation.added")]
184    ResponseOutputTextAnnotationAdded {
185        annotation: Value,
186        annotation_index: u32,
187        content_index: u32,
188        item_id: String,
189        output_index: u32,
190        #[serde(skip_serializing_if = "Option::is_none")]
191        sequence_number: Option<u64>,
192        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
193        extra: Extra,
194    },
195    #[serde(rename = "response.function_call_arguments.delta")]
196    ResponseFunctionCallArgumentsDelta {
197        delta: String,
198        item_id: String,
199        output_index: u32,
200        #[serde(skip_serializing_if = "Option::is_none")]
201        sequence_number: Option<u64>,
202        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
203        extra: Extra,
204    },
205    #[serde(rename = "response.function_call_arguments.done")]
206    ResponseFunctionCallArgumentsDone {
207        arguments: String,
208        item_id: String,
209        name: String,
210        output_index: u32,
211        #[serde(skip_serializing_if = "Option::is_none")]
212        sequence_number: Option<u64>,
213        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
214        extra: Extra,
215    },
216    #[serde(rename = "response.custom_tool_call_input.delta")]
217    ResponseCustomToolCallInputDelta {
218        delta: String,
219        item_id: String,
220        output_index: u32,
221        #[serde(skip_serializing_if = "Option::is_none")]
222        sequence_number: Option<u64>,
223        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
224        extra: Extra,
225    },
226    #[serde(rename = "response.custom_tool_call_input.done")]
227    ResponseCustomToolCallInputDone {
228        input: String,
229        item_id: String,
230        output_index: u32,
231        #[serde(skip_serializing_if = "Option::is_none")]
232        sequence_number: Option<u64>,
233        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
234        extra: Extra,
235    },
236    #[serde(rename = "response.refusal.delta")]
237    ResponseRefusalDelta {
238        content_index: u32,
239        delta: String,
240        item_id: String,
241        output_index: u32,
242        #[serde(skip_serializing_if = "Option::is_none")]
243        sequence_number: Option<u64>,
244        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
245        extra: Extra,
246    },
247    #[serde(rename = "response.refusal.done")]
248    ResponseRefusalDone {
249        content_index: u32,
250        item_id: String,
251        output_index: u32,
252        refusal: String,
253        #[serde(skip_serializing_if = "Option::is_none")]
254        sequence_number: Option<u64>,
255        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
256        extra: Extra,
257    },
258    #[serde(rename = "response.reasoning_summary_part.added")]
259    ResponseReasoningSummaryPartAdded {
260        item_id: String,
261        output_index: u32,
262        part: ResponseReasoningSummaryPart,
263        #[serde(skip_serializing_if = "Option::is_none")]
264        sequence_number: Option<u64>,
265        summary_index: u32,
266        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
267        extra: Extra,
268    },
269    #[serde(rename = "response.reasoning_summary_part.done")]
270    ResponseReasoningSummaryPartDone {
271        item_id: String,
272        output_index: u32,
273        part: ResponseReasoningSummaryPart,
274        #[serde(skip_serializing_if = "Option::is_none")]
275        sequence_number: Option<u64>,
276        summary_index: u32,
277        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
278        extra: Extra,
279    },
280    #[serde(rename = "response.reasoning_summary_text.delta")]
281    ResponseReasoningSummaryTextDelta {
282        delta: String,
283        item_id: String,
284        output_index: u32,
285        #[serde(skip_serializing_if = "Option::is_none")]
286        sequence_number: Option<u64>,
287        summary_index: u32,
288        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
289        extra: Extra,
290    },
291    #[serde(rename = "response.reasoning_summary_text.done")]
292    ResponseReasoningSummaryTextDone {
293        item_id: String,
294        output_index: u32,
295        #[serde(skip_serializing_if = "Option::is_none")]
296        sequence_number: Option<u64>,
297        summary_index: u32,
298        text: String,
299        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
300        extra: Extra,
301    },
302    #[serde(rename = "response.reasoning_text.delta")]
303    ResponseReasoningTextDelta {
304        content_index: u32,
305        delta: String,
306        item_id: String,
307        output_index: u32,
308        #[serde(skip_serializing_if = "Option::is_none")]
309        sequence_number: Option<u64>,
310        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
311        extra: Extra,
312    },
313    #[serde(rename = "response.reasoning_text.done")]
314    ResponseReasoningTextDone {
315        content_index: u32,
316        item_id: String,
317        output_index: u32,
318        #[serde(skip_serializing_if = "Option::is_none")]
319        sequence_number: Option<u64>,
320        text: String,
321        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
322        extra: Extra,
323    },
324    #[serde(rename = "response.audio.delta")]
325    ResponseAudioDelta {
326        delta: String,
327        #[serde(skip_serializing_if = "Option::is_none")]
328        sequence_number: Option<u64>,
329        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
330        extra: Extra,
331    },
332    #[serde(rename = "response.audio.done")]
333    ResponseAudioDone {
334        #[serde(skip_serializing_if = "Option::is_none")]
335        sequence_number: Option<u64>,
336        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
337        extra: Extra,
338    },
339    #[serde(rename = "response.audio.transcript.delta")]
340    ResponseAudioTranscriptDelta {
341        delta: String,
342        #[serde(skip_serializing_if = "Option::is_none")]
343        sequence_number: Option<u64>,
344        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
345        extra: Extra,
346    },
347    #[serde(rename = "response.audio.transcript.done")]
348    ResponseAudioTranscriptDone {
349        #[serde(skip_serializing_if = "Option::is_none")]
350        sequence_number: Option<u64>,
351        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
352        extra: Extra,
353    },
354    #[serde(rename = "response.image_generation_call.completed")]
355    ResponseImageGenerationCallCompleted {
356        item_id: String,
357        output_index: u32,
358        #[serde(skip_serializing_if = "Option::is_none")]
359        sequence_number: Option<u64>,
360        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
361        extra: Extra,
362    },
363    #[serde(rename = "response.image_generation_call.generating")]
364    ResponseImageGenerationCallGenerating {
365        item_id: String,
366        output_index: u32,
367        #[serde(skip_serializing_if = "Option::is_none")]
368        sequence_number: Option<u64>,
369        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
370        extra: Extra,
371    },
372    #[serde(rename = "response.image_generation_call.in_progress")]
373    ResponseImageGenerationCallInProgress {
374        item_id: String,
375        output_index: u32,
376        #[serde(skip_serializing_if = "Option::is_none")]
377        sequence_number: Option<u64>,
378        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
379        extra: Extra,
380    },
381    #[serde(rename = "response.image_generation_call.partial_image")]
382    ResponseImageGenerationCallPartialImage {
383        item_id: String,
384        output_index: u32,
385        partial_image_b64: String,
386        partial_image_index: u32,
387        #[serde(skip_serializing_if = "Option::is_none")]
388        sequence_number: Option<u64>,
389        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
390        extra: Extra,
391    },
392    #[serde(rename = "response.file_search_call.in_progress")]
393    ResponseFileSearchCallInProgress {
394        item_id: String,
395        output_index: u32,
396        #[serde(skip_serializing_if = "Option::is_none")]
397        sequence_number: Option<u64>,
398        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
399        extra: Extra,
400    },
401    #[serde(rename = "response.file_search_call.searching")]
402    ResponseFileSearchCallSearching {
403        item_id: String,
404        output_index: u32,
405        #[serde(skip_serializing_if = "Option::is_none")]
406        sequence_number: Option<u64>,
407        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
408        extra: Extra,
409    },
410    #[serde(rename = "response.file_search_call.completed")]
411    ResponseFileSearchCallCompleted {
412        item_id: String,
413        output_index: u32,
414        #[serde(skip_serializing_if = "Option::is_none")]
415        sequence_number: Option<u64>,
416        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
417        extra: Extra,
418    },
419    #[serde(rename = "response.web_search_call.in_progress")]
420    ResponseWebSearchCallInProgress {
421        item_id: String,
422        output_index: u32,
423        #[serde(skip_serializing_if = "Option::is_none")]
424        sequence_number: Option<u64>,
425        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
426        extra: Extra,
427    },
428    #[serde(rename = "response.web_search_call.searching")]
429    ResponseWebSearchCallSearching {
430        item_id: String,
431        output_index: u32,
432        #[serde(skip_serializing_if = "Option::is_none")]
433        sequence_number: Option<u64>,
434        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
435        extra: Extra,
436    },
437    #[serde(rename = "response.web_search_call.completed")]
438    ResponseWebSearchCallCompleted {
439        item_id: String,
440        output_index: u32,
441        #[serde(skip_serializing_if = "Option::is_none")]
442        sequence_number: Option<u64>,
443        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
444        extra: Extra,
445    },
446    #[serde(rename = "response.code_interpreter_call.in_progress")]
447    ResponseCodeInterpreterCallInProgress {
448        item_id: String,
449        output_index: u32,
450        #[serde(skip_serializing_if = "Option::is_none")]
451        sequence_number: Option<u64>,
452        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
453        extra: Extra,
454    },
455    #[serde(rename = "response.code_interpreter_call.interpreting")]
456    ResponseCodeInterpreterCallInterpreting {
457        item_id: String,
458        output_index: u32,
459        #[serde(skip_serializing_if = "Option::is_none")]
460        sequence_number: Option<u64>,
461        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
462        extra: Extra,
463    },
464    #[serde(rename = "response.code_interpreter_call.completed")]
465    ResponseCodeInterpreterCallCompleted {
466        item_id: String,
467        output_index: u32,
468        #[serde(skip_serializing_if = "Option::is_none")]
469        sequence_number: Option<u64>,
470        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
471        extra: Extra,
472    },
473    #[serde(rename = "response.code_interpreter_call_code.delta")]
474    ResponseCodeInterpreterCallCodeDelta {
475        delta: String,
476        item_id: String,
477        output_index: u32,
478        #[serde(skip_serializing_if = "Option::is_none")]
479        sequence_number: Option<u64>,
480        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
481        extra: Extra,
482    },
483    #[serde(rename = "response.code_interpreter_call_code.done")]
484    ResponseCodeInterpreterCallCodeDone {
485        code: String,
486        item_id: String,
487        output_index: u32,
488        #[serde(skip_serializing_if = "Option::is_none")]
489        sequence_number: Option<u64>,
490        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
491        extra: Extra,
492    },
493    #[serde(rename = "response.mcp_call_arguments.delta")]
494    ResponseMcpCallArgumentsDelta {
495        delta: String,
496        item_id: String,
497        output_index: u32,
498        #[serde(skip_serializing_if = "Option::is_none")]
499        sequence_number: Option<u64>,
500        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
501        extra: Extra,
502    },
503    #[serde(rename = "response.mcp_call_arguments.done")]
504    ResponseMcpCallArgumentsDone {
505        arguments: String,
506        item_id: String,
507        output_index: u32,
508        #[serde(skip_serializing_if = "Option::is_none")]
509        sequence_number: Option<u64>,
510        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
511        extra: Extra,
512    },
513    #[serde(rename = "response.mcp_call.in_progress")]
514    ResponseMcpCallInProgress {
515        item_id: String,
516        output_index: u32,
517        #[serde(skip_serializing_if = "Option::is_none")]
518        sequence_number: Option<u64>,
519        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
520        extra: Extra,
521    },
522    #[serde(rename = "response.mcp_call.completed")]
523    ResponseMcpCallCompleted {
524        item_id: String,
525        output_index: u32,
526        #[serde(skip_serializing_if = "Option::is_none")]
527        sequence_number: Option<u64>,
528        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
529        extra: Extra,
530    },
531    #[serde(rename = "response.mcp_call.failed")]
532    ResponseMcpCallFailed {
533        item_id: String,
534        output_index: u32,
535        #[serde(skip_serializing_if = "Option::is_none")]
536        sequence_number: Option<u64>,
537        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
538        extra: Extra,
539    },
540    #[serde(rename = "response.mcp_list_tools.in_progress")]
541    ResponseMcpListToolsInProgress {
542        item_id: String,
543        output_index: u32,
544        #[serde(skip_serializing_if = "Option::is_none")]
545        sequence_number: Option<u64>,
546        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
547        extra: Extra,
548    },
549    #[serde(rename = "response.mcp_list_tools.completed")]
550    ResponseMcpListToolsCompleted {
551        item_id: String,
552        output_index: u32,
553        #[serde(skip_serializing_if = "Option::is_none")]
554        sequence_number: Option<u64>,
555        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
556        extra: Extra,
557    },
558    #[serde(rename = "response.mcp_list_tools.failed")]
559    ResponseMcpListToolsFailed {
560        item_id: String,
561        output_index: u32,
562        #[serde(skip_serializing_if = "Option::is_none")]
563        sequence_number: Option<u64>,
564        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
565        extra: Extra,
566    },
567    #[serde(rename = "error")]
568    Error {
569        code: String,
570        message: String,
571        param: String,
572        #[serde(skip_serializing_if = "Option::is_none")]
573        sequence_number: Option<u64>,
574        #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
575        extra: Extra,
576    },
577}
578
579impl KnownResponseStreamEvent {
580    /// Typed event type of this variant, mirroring the serde `type` tag.
581    pub fn event_type(&self) -> ResponseStreamEventTypeKnown {
582        use ResponseStreamEventTypeKnown as T;
583        match self {
584            Self::ResponseCreated { .. } => T::ResponseCreated,
585            Self::ResponseInProgress { .. } => T::ResponseInProgress,
586            Self::ResponseCompleted { .. } => T::ResponseCompleted,
587            Self::ResponseFailed { .. } => T::ResponseFailed,
588            Self::ResponseIncomplete { .. } => T::ResponseIncomplete,
589            Self::ResponseQueued { .. } => T::ResponseQueued,
590            Self::ResponseOutputItemAdded { .. } => T::ResponseOutputItemAdded,
591            Self::ResponseOutputItemDone { .. } => T::ResponseOutputItemDone,
592            Self::ResponseContentPartAdded { .. } => T::ResponseContentPartAdded,
593            Self::ResponseContentPartDone { .. } => T::ResponseContentPartDone,
594            Self::ResponseOutputTextDelta { .. } => T::ResponseOutputTextDelta,
595            Self::ResponseOutputTextDone { .. } => T::ResponseOutputTextDone,
596            Self::ResponseOutputTextAnnotationAdded { .. } => T::ResponseOutputTextAnnotationAdded,
597            Self::ResponseFunctionCallArgumentsDelta { .. } => {
598                T::ResponseFunctionCallArgumentsDelta
599            }
600            Self::ResponseFunctionCallArgumentsDone { .. } => T::ResponseFunctionCallArgumentsDone,
601            Self::ResponseCustomToolCallInputDelta { .. } => T::ResponseCustomToolCallInputDelta,
602            Self::ResponseCustomToolCallInputDone { .. } => T::ResponseCustomToolCallInputDone,
603            Self::ResponseRefusalDelta { .. } => T::ResponseRefusalDelta,
604            Self::ResponseRefusalDone { .. } => T::ResponseRefusalDone,
605            Self::ResponseReasoningSummaryPartAdded { .. } => T::ResponseReasoningSummaryPartAdded,
606            Self::ResponseReasoningSummaryPartDone { .. } => T::ResponseReasoningSummaryPartDone,
607            Self::ResponseReasoningSummaryTextDelta { .. } => T::ResponseReasoningSummaryTextDelta,
608            Self::ResponseReasoningSummaryTextDone { .. } => T::ResponseReasoningSummaryTextDone,
609            Self::ResponseReasoningTextDelta { .. } => T::ResponseReasoningTextDelta,
610            Self::ResponseReasoningTextDone { .. } => T::ResponseReasoningTextDone,
611            Self::ResponseAudioDelta { .. } => T::ResponseAudioDelta,
612            Self::ResponseAudioDone { .. } => T::ResponseAudioDone,
613            Self::ResponseAudioTranscriptDelta { .. } => T::ResponseAudioTranscriptDelta,
614            Self::ResponseAudioTranscriptDone { .. } => T::ResponseAudioTranscriptDone,
615            Self::ResponseImageGenerationCallCompleted { .. } => {
616                T::ResponseImageGenerationCallCompleted
617            }
618            Self::ResponseImageGenerationCallGenerating { .. } => {
619                T::ResponseImageGenerationCallGenerating
620            }
621            Self::ResponseImageGenerationCallInProgress { .. } => {
622                T::ResponseImageGenerationCallInProgress
623            }
624            Self::ResponseImageGenerationCallPartialImage { .. } => {
625                T::ResponseImageGenerationCallPartialImage
626            }
627            Self::ResponseFileSearchCallInProgress { .. } => T::ResponseFileSearchCallInProgress,
628            Self::ResponseFileSearchCallSearching { .. } => T::ResponseFileSearchCallSearching,
629            Self::ResponseFileSearchCallCompleted { .. } => T::ResponseFileSearchCallCompleted,
630            Self::ResponseWebSearchCallInProgress { .. } => T::ResponseWebSearchCallInProgress,
631            Self::ResponseWebSearchCallSearching { .. } => T::ResponseWebSearchCallSearching,
632            Self::ResponseWebSearchCallCompleted { .. } => T::ResponseWebSearchCallCompleted,
633            Self::ResponseCodeInterpreterCallInProgress { .. } => {
634                T::ResponseCodeInterpreterCallInProgress
635            }
636            Self::ResponseCodeInterpreterCallInterpreting { .. } => {
637                T::ResponseCodeInterpreterCallInterpreting
638            }
639            Self::ResponseCodeInterpreterCallCompleted { .. } => {
640                T::ResponseCodeInterpreterCallCompleted
641            }
642            Self::ResponseCodeInterpreterCallCodeDelta { .. } => {
643                T::ResponseCodeInterpreterCallCodeDelta
644            }
645            Self::ResponseCodeInterpreterCallCodeDone { .. } => {
646                T::ResponseCodeInterpreterCallCodeDone
647            }
648            Self::ResponseMcpCallArgumentsDelta { .. } => T::ResponseMcpCallArgumentsDelta,
649            Self::ResponseMcpCallArgumentsDone { .. } => T::ResponseMcpCallArgumentsDone,
650            Self::ResponseMcpCallInProgress { .. } => T::ResponseMcpCallInProgress,
651            Self::ResponseMcpCallCompleted { .. } => T::ResponseMcpCallCompleted,
652            Self::ResponseMcpCallFailed { .. } => T::ResponseMcpCallFailed,
653            Self::ResponseMcpListToolsInProgress { .. } => T::ResponseMcpListToolsInProgress,
654            Self::ResponseMcpListToolsCompleted { .. } => T::ResponseMcpListToolsCompleted,
655            Self::ResponseMcpListToolsFailed { .. } => T::ResponseMcpListToolsFailed,
656            Self::Error { .. } => T::Error,
657        }
658    }
659
660    /// SSE event name: the exact serde rename of this variant.
661    pub fn event_name(&self) -> &'static str {
662        self.event_type().as_str()
663    }
664}
665
666#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
667pub struct UnknownResponseStreamEvent {
668    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
669    pub type_: Option<ResponseStreamEventType>,
670    #[serde(skip_serializing_if = "Option::is_none")]
671    pub sequence_number: Option<u64>,
672    #[serde(default, flatten, skip_serializing_if = "BTreeMap::is_empty")]
673    pub extra: Extra,
674}
675
676#[cfg(test)]
677mod tests {
678    use super::*;
679
680    /// Regression: `event_name()` must equal the serialized `type` tag.
681    #[test]
682    fn event_name_matches_serialized_type_tag() {
683        let events: Vec<ResponseStreamEvent> = [
684            r#"{"type":"response.output_text.delta","content_index":0,"delta":"hi","item_id":"msg_0","output_index":0}"#,
685            r#"{"type":"response.output_item.done","output_index":0,"item":{"id":"fc_1","type":"function_call","call_id":"c1","name":"f","arguments":"{}"}}"#,
686            r#"{"type":"response.function_call_arguments.done","arguments":"{}","item_id":"fc_1","name":"f","output_index":0}"#,
687            r#"{"type":"response.completed","response":{"id":"r","object":"response","created_at":0,"output":[]}}"#,
688            r#"{"type":"response.some_future_event","sequence_number":1}"#,
689        ]
690        .iter()
691        .map(|raw| serde_json::from_str(raw).unwrap())
692        .collect();
693        for event in events {
694            let value = serde_json::to_value(&event).unwrap();
695            assert_eq!(
696                event.event_name(),
697                value.get("type").and_then(Value::as_str),
698                "{value}"
699            );
700        }
701    }
702}