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