Skip to main content

openai_protocol/
event_types.rs

1use std::fmt;
2
3/// Response lifecycle events
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum ResponseEvent {
6    Created,
7    InProgress,
8    Completed,
9}
10
11impl ResponseEvent {
12    pub const CREATED: &'static str = "response.created";
13    pub const IN_PROGRESS: &'static str = "response.in_progress";
14    pub const COMPLETED: &'static str = "response.completed";
15
16    pub const fn as_str(self) -> &'static str {
17        match self {
18            Self::Created => Self::CREATED,
19            Self::InProgress => Self::IN_PROGRESS,
20            Self::Completed => Self::COMPLETED,
21        }
22    }
23}
24
25impl fmt::Display for ResponseEvent {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        f.write_str(self.as_str())
28    }
29}
30
31/// Output item events for streaming
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub enum OutputItemEvent {
34    Added,
35    Done,
36    Delta,
37}
38
39impl OutputItemEvent {
40    pub const ADDED: &'static str = "response.output_item.added";
41    pub const DONE: &'static str = "response.output_item.done";
42    pub const DELTA: &'static str = "response.output_item.delta";
43
44    pub const fn as_str(self) -> &'static str {
45        match self {
46            Self::Added => Self::ADDED,
47            Self::Done => Self::DONE,
48            Self::Delta => Self::DELTA,
49        }
50    }
51}
52
53impl fmt::Display for OutputItemEvent {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        f.write_str(self.as_str())
56    }
57}
58
59/// Function call argument streaming events
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub enum FunctionCallEvent {
62    ArgumentsDelta,
63    ArgumentsDone,
64}
65
66impl FunctionCallEvent {
67    pub const ARGUMENTS_DELTA: &'static str = "response.function_call_arguments.delta";
68    pub const ARGUMENTS_DONE: &'static str = "response.function_call_arguments.done";
69
70    pub const fn as_str(self) -> &'static str {
71        match self {
72            Self::ArgumentsDelta => Self::ARGUMENTS_DELTA,
73            Self::ArgumentsDone => Self::ARGUMENTS_DONE,
74        }
75    }
76}
77
78impl fmt::Display for FunctionCallEvent {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        f.write_str(self.as_str())
81    }
82}
83
84/// Content part streaming events
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86pub enum ContentPartEvent {
87    Added,
88    Done,
89}
90
91impl ContentPartEvent {
92    pub const ADDED: &'static str = "response.content_part.added";
93    pub const DONE: &'static str = "response.content_part.done";
94
95    pub const fn as_str(self) -> &'static str {
96        match self {
97            Self::Added => Self::ADDED,
98            Self::Done => Self::DONE,
99        }
100    }
101}
102
103impl fmt::Display for ContentPartEvent {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        f.write_str(self.as_str())
106    }
107}
108
109/// Output text streaming events
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub enum OutputTextEvent {
112    Delta,
113    Done,
114}
115
116impl OutputTextEvent {
117    pub const DELTA: &'static str = "response.output_text.delta";
118    pub const DONE: &'static str = "response.output_text.done";
119
120    pub const fn as_str(self) -> &'static str {
121        match self {
122            Self::Delta => Self::DELTA,
123            Self::Done => Self::DONE,
124        }
125    }
126}
127
128impl fmt::Display for OutputTextEvent {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        f.write_str(self.as_str())
131    }
132}
133
134// ============================================================================
135// MCP Events
136// ============================================================================
137
138/// MCP (Model Context Protocol) call events
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
140pub enum McpEvent {
141    CallArgumentsDelta,
142    CallArgumentsDone,
143    CallInProgress,
144    CallCompleted,
145    CallFailed,
146    ListToolsInProgress,
147    ListToolsCompleted,
148}
149
150impl McpEvent {
151    pub const CALL_ARGUMENTS_DELTA: &'static str = "response.mcp_call_arguments.delta";
152    pub const CALL_ARGUMENTS_DONE: &'static str = "response.mcp_call_arguments.done";
153    pub const CALL_IN_PROGRESS: &'static str = "response.mcp_call.in_progress";
154    pub const CALL_COMPLETED: &'static str = "response.mcp_call.completed";
155    pub const CALL_FAILED: &'static str = "response.mcp_call.failed";
156    pub const LIST_TOOLS_IN_PROGRESS: &'static str = "response.mcp_list_tools.in_progress";
157    pub const LIST_TOOLS_COMPLETED: &'static str = "response.mcp_list_tools.completed";
158
159    pub const fn as_str(self) -> &'static str {
160        match self {
161            Self::CallArgumentsDelta => Self::CALL_ARGUMENTS_DELTA,
162            Self::CallArgumentsDone => Self::CALL_ARGUMENTS_DONE,
163            Self::CallInProgress => Self::CALL_IN_PROGRESS,
164            Self::CallCompleted => Self::CALL_COMPLETED,
165            Self::CallFailed => Self::CALL_FAILED,
166            Self::ListToolsInProgress => Self::LIST_TOOLS_IN_PROGRESS,
167            Self::ListToolsCompleted => Self::LIST_TOOLS_COMPLETED,
168        }
169    }
170}
171
172impl fmt::Display for McpEvent {
173    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174        f.write_str(self.as_str())
175    }
176}
177
178// ============================================================================
179// Built-in Tool Events
180// ============================================================================
181
182/// Web search call events for streaming
183#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
184pub enum WebSearchCallEvent {
185    InProgress,
186    Searching,
187    Completed,
188}
189
190impl WebSearchCallEvent {
191    pub const IN_PROGRESS: &'static str = "response.web_search_call.in_progress";
192    pub const SEARCHING: &'static str = "response.web_search_call.searching";
193    pub const COMPLETED: &'static str = "response.web_search_call.completed";
194
195    pub const fn as_str(self) -> &'static str {
196        match self {
197            Self::InProgress => Self::IN_PROGRESS,
198            Self::Searching => Self::SEARCHING,
199            Self::Completed => Self::COMPLETED,
200        }
201    }
202}
203
204impl fmt::Display for WebSearchCallEvent {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        f.write_str(self.as_str())
207    }
208}
209
210/// Code interpreter call events for streaming
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
212pub enum CodeInterpreterCallEvent {
213    InProgress,
214    Interpreting,
215    Completed,
216}
217
218impl CodeInterpreterCallEvent {
219    pub const IN_PROGRESS: &'static str = "response.code_interpreter_call.in_progress";
220    pub const INTERPRETING: &'static str = "response.code_interpreter_call.interpreting";
221    pub const COMPLETED: &'static str = "response.code_interpreter_call.completed";
222
223    pub const fn as_str(self) -> &'static str {
224        match self {
225            Self::InProgress => Self::IN_PROGRESS,
226            Self::Interpreting => Self::INTERPRETING,
227            Self::Completed => Self::COMPLETED,
228        }
229    }
230}
231
232impl fmt::Display for CodeInterpreterCallEvent {
233    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234        f.write_str(self.as_str())
235    }
236}
237
238/// File search call events for streaming
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
240pub enum FileSearchCallEvent {
241    InProgress,
242    Searching,
243    Completed,
244}
245
246impl FileSearchCallEvent {
247    pub const IN_PROGRESS: &'static str = "response.file_search_call.in_progress";
248    pub const SEARCHING: &'static str = "response.file_search_call.searching";
249    pub const COMPLETED: &'static str = "response.file_search_call.completed";
250
251    pub const fn as_str(self) -> &'static str {
252        match self {
253            Self::InProgress => Self::IN_PROGRESS,
254            Self::Searching => Self::SEARCHING,
255            Self::Completed => Self::COMPLETED,
256        }
257    }
258}
259
260impl fmt::Display for FileSearchCallEvent {
261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262        f.write_str(self.as_str())
263    }
264}
265
266/// Item type discriminators used in output items
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268pub enum ItemType {
269    FunctionCall,
270    FunctionToolCall,
271    McpCall,
272    Function,
273    McpListTools,
274    WebSearchCall,
275    CodeInterpreterCall,
276    FileSearchCall,
277}
278
279impl ItemType {
280    pub const FUNCTION_CALL: &'static str = "function_call";
281    pub const FUNCTION_TOOL_CALL: &'static str = "function_tool_call";
282    pub const MCP_CALL: &'static str = "mcp_call";
283    pub const FUNCTION: &'static str = "function";
284    pub const MCP_LIST_TOOLS: &'static str = "mcp_list_tools";
285    pub const WEB_SEARCH_CALL: &'static str = "web_search_call";
286    pub const CODE_INTERPRETER_CALL: &'static str = "code_interpreter_call";
287    pub const FILE_SEARCH_CALL: &'static str = "file_search_call";
288
289    pub const fn as_str(self) -> &'static str {
290        match self {
291            Self::FunctionCall => Self::FUNCTION_CALL,
292            Self::FunctionToolCall => Self::FUNCTION_TOOL_CALL,
293            Self::McpCall => Self::MCP_CALL,
294            Self::Function => Self::FUNCTION,
295            Self::McpListTools => Self::MCP_LIST_TOOLS,
296            Self::WebSearchCall => Self::WEB_SEARCH_CALL,
297            Self::CodeInterpreterCall => Self::CODE_INTERPRETER_CALL,
298            Self::FileSearchCall => Self::FILE_SEARCH_CALL,
299        }
300    }
301
302    /// Check if this is a function call variant (FunctionCall or FunctionToolCall)
303    pub const fn is_function_call(self) -> bool {
304        matches!(self, Self::FunctionCall | Self::FunctionToolCall)
305    }
306
307    /// Check if this is a builtin tool call variant
308    pub const fn is_builtin_tool_call(self) -> bool {
309        matches!(
310            self,
311            Self::WebSearchCall | Self::CodeInterpreterCall | Self::FileSearchCall
312        )
313    }
314}
315
316impl fmt::Display for ItemType {
317    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318        f.write_str(self.as_str())
319    }
320}
321
322// ============================================================================
323// Realtime Client Events
324// ============================================================================
325
326/// Realtime API client events sent over WebSocket/WebRTC/SIP connections.
327#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
328pub enum RealtimeClientEvent {
329    ConversationItemCreate,
330    ConversationItemDelete,
331    ConversationItemRetrieve,
332    ConversationItemTruncate,
333    InputAudioBufferAppend,
334    InputAudioBufferClear,
335    InputAudioBufferCommit,
336    OutputAudioBufferClear,
337    ResponseCancel,
338    ResponseCreate,
339    SessionUpdate,
340    TranscriptionSessionUpdate,
341}
342
343impl RealtimeClientEvent {
344    pub const CONVERSATION_ITEM_CREATE: &'static str = "conversation.item.create";
345    pub const CONVERSATION_ITEM_DELETE: &'static str = "conversation.item.delete";
346    pub const CONVERSATION_ITEM_RETRIEVE: &'static str = "conversation.item.retrieve";
347    pub const CONVERSATION_ITEM_TRUNCATE: &'static str = "conversation.item.truncate";
348    pub const INPUT_AUDIO_BUFFER_APPEND: &'static str = "input_audio_buffer.append";
349    pub const INPUT_AUDIO_BUFFER_CLEAR: &'static str = "input_audio_buffer.clear";
350    pub const INPUT_AUDIO_BUFFER_COMMIT: &'static str = "input_audio_buffer.commit";
351    pub const OUTPUT_AUDIO_BUFFER_CLEAR: &'static str = "output_audio_buffer.clear";
352    pub const RESPONSE_CANCEL: &'static str = "response.cancel";
353    pub const RESPONSE_CREATE: &'static str = "response.create";
354    pub const SESSION_UPDATE: &'static str = "session.update";
355    pub const TRANSCRIPTION_SESSION_UPDATE: &'static str = "transcription_session.update";
356
357    pub const fn as_str(self) -> &'static str {
358        match self {
359            Self::ConversationItemCreate => Self::CONVERSATION_ITEM_CREATE,
360            Self::ConversationItemDelete => Self::CONVERSATION_ITEM_DELETE,
361            Self::ConversationItemRetrieve => Self::CONVERSATION_ITEM_RETRIEVE,
362            Self::ConversationItemTruncate => Self::CONVERSATION_ITEM_TRUNCATE,
363            Self::InputAudioBufferAppend => Self::INPUT_AUDIO_BUFFER_APPEND,
364            Self::InputAudioBufferClear => Self::INPUT_AUDIO_BUFFER_CLEAR,
365            Self::InputAudioBufferCommit => Self::INPUT_AUDIO_BUFFER_COMMIT,
366            Self::OutputAudioBufferClear => Self::OUTPUT_AUDIO_BUFFER_CLEAR,
367            Self::ResponseCancel => Self::RESPONSE_CANCEL,
368            Self::ResponseCreate => Self::RESPONSE_CREATE,
369            Self::SessionUpdate => Self::SESSION_UPDATE,
370            Self::TranscriptionSessionUpdate => Self::TRANSCRIPTION_SESSION_UPDATE,
371        }
372    }
373}
374
375impl fmt::Display for RealtimeClientEvent {
376    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
377        f.write_str(self.as_str())
378    }
379}
380
381// ============================================================================
382// Realtime Server Events
383// ============================================================================
384
385/// Realtime API server events received over WebSocket/WebRTC/SIP connections.
386#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
387pub enum RealtimeServerEvent {
388    // Session events
389    SessionCreated,
390    SessionUpdated,
391    // Conversation events
392    ConversationCreated,
393    ConversationItemCreated,
394    ConversationItemAdded,
395    ConversationItemDone,
396    ConversationItemDeleted,
397    ConversationItemRetrieved,
398    ConversationItemTruncated,
399    // Input audio transcription events
400    ConversationItemInputAudioTranscriptionCompleted,
401    ConversationItemInputAudioTranscriptionDelta,
402    ConversationItemInputAudioTranscriptionFailed,
403    ConversationItemInputAudioTranscriptionSegment,
404    // Input audio buffer events
405    InputAudioBufferCleared,
406    InputAudioBufferCommitted,
407    InputAudioBufferSpeechStarted,
408    InputAudioBufferSpeechStopped,
409    InputAudioBufferTimeoutTriggered,
410    InputAudioBufferDtmfEventReceived,
411    // Output audio buffer events (WebRTC/SIP only)
412    OutputAudioBufferStarted,
413    OutputAudioBufferStopped,
414    OutputAudioBufferCleared,
415    // Response lifecycle events
416    ResponseCreated,
417    ResponseDone,
418    // Response output item events
419    ResponseOutputItemAdded,
420    ResponseOutputItemDone,
421    // Response content part events
422    ResponseContentPartAdded,
423    ResponseContentPartDone,
424    // Response text events
425    ResponseOutputTextDelta,
426    ResponseOutputTextDone,
427    // Response audio events
428    ResponseOutputAudioDelta,
429    ResponseOutputAudioDone,
430    // Response audio transcript events
431    ResponseOutputAudioTranscriptDelta,
432    ResponseOutputAudioTranscriptDone,
433    // Response function call events
434    ResponseFunctionCallArgumentsDelta,
435    ResponseFunctionCallArgumentsDone,
436    // Response MCP call events
437    ResponseMcpCallArgumentsDelta,
438    ResponseMcpCallArgumentsDone,
439    ResponseMcpCallInProgress,
440    ResponseMcpCallCompleted,
441    ResponseMcpCallFailed,
442    // MCP list tools events
443    McpListToolsInProgress,
444    McpListToolsCompleted,
445    McpListToolsFailed,
446    // Rate limits
447    RateLimitsUpdated,
448    // Error
449    Error,
450}
451
452impl RealtimeServerEvent {
453    // Session events
454    pub const SESSION_CREATED: &'static str = "session.created";
455    pub const SESSION_UPDATED: &'static str = "session.updated";
456    // Conversation events
457    pub const CONVERSATION_CREATED: &'static str = "conversation.created";
458    pub const CONVERSATION_ITEM_CREATED: &'static str = "conversation.item.created";
459    pub const CONVERSATION_ITEM_ADDED: &'static str = "conversation.item.added";
460    pub const CONVERSATION_ITEM_DONE: &'static str = "conversation.item.done";
461    pub const CONVERSATION_ITEM_DELETED: &'static str = "conversation.item.deleted";
462    pub const CONVERSATION_ITEM_RETRIEVED: &'static str = "conversation.item.retrieved";
463    pub const CONVERSATION_ITEM_TRUNCATED: &'static str = "conversation.item.truncated";
464    // Input audio transcription events
465    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED: &'static str =
466        "conversation.item.input_audio_transcription.completed";
467    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA: &'static str =
468        "conversation.item.input_audio_transcription.delta";
469    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED: &'static str =
470        "conversation.item.input_audio_transcription.failed";
471    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT: &'static str =
472        "conversation.item.input_audio_transcription.segment";
473    // Input audio buffer events
474    pub const INPUT_AUDIO_BUFFER_CLEARED: &'static str = "input_audio_buffer.cleared";
475    pub const INPUT_AUDIO_BUFFER_COMMITTED: &'static str = "input_audio_buffer.committed";
476    pub const INPUT_AUDIO_BUFFER_SPEECH_STARTED: &'static str = "input_audio_buffer.speech_started";
477    pub const INPUT_AUDIO_BUFFER_SPEECH_STOPPED: &'static str = "input_audio_buffer.speech_stopped";
478    pub const INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED: &'static str =
479        "input_audio_buffer.timeout_triggered";
480    pub const INPUT_AUDIO_BUFFER_DTMF_EVENT_RECEIVED: &'static str =
481        "input_audio_buffer.dtmf_event_received";
482    // Output audio buffer events
483    pub const OUTPUT_AUDIO_BUFFER_STARTED: &'static str = "output_audio_buffer.started";
484    pub const OUTPUT_AUDIO_BUFFER_STOPPED: &'static str = "output_audio_buffer.stopped";
485    pub const OUTPUT_AUDIO_BUFFER_CLEARED: &'static str = "output_audio_buffer.cleared";
486    // Response lifecycle events
487    pub const RESPONSE_CREATED: &'static str = "response.created";
488    pub const RESPONSE_DONE: &'static str = "response.done";
489    // Response output item events
490    pub const RESPONSE_OUTPUT_ITEM_ADDED: &'static str = "response.output_item.added";
491    pub const RESPONSE_OUTPUT_ITEM_DONE: &'static str = "response.output_item.done";
492    // Response content part events
493    pub const RESPONSE_CONTENT_PART_ADDED: &'static str = "response.content_part.added";
494    pub const RESPONSE_CONTENT_PART_DONE: &'static str = "response.content_part.done";
495    // Response text events
496    pub const RESPONSE_OUTPUT_TEXT_DELTA: &'static str = "response.output_text.delta";
497    pub const RESPONSE_OUTPUT_TEXT_DONE: &'static str = "response.output_text.done";
498    // Response audio events
499    pub const RESPONSE_OUTPUT_AUDIO_DELTA: &'static str = "response.output_audio.delta";
500    pub const RESPONSE_OUTPUT_AUDIO_DONE: &'static str = "response.output_audio.done";
501    // Response audio transcript events
502    pub const RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA: &'static str =
503        "response.output_audio_transcript.delta";
504    pub const RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE: &'static str =
505        "response.output_audio_transcript.done";
506    // Response function call events
507    pub const RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA: &'static str =
508        "response.function_call_arguments.delta";
509    pub const RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE: &'static str =
510        "response.function_call_arguments.done";
511    // Response MCP call events
512    pub const RESPONSE_MCP_CALL_ARGUMENTS_DELTA: &'static str = "response.mcp_call_arguments.delta";
513    pub const RESPONSE_MCP_CALL_ARGUMENTS_DONE: &'static str = "response.mcp_call_arguments.done";
514    pub const RESPONSE_MCP_CALL_IN_PROGRESS: &'static str = "response.mcp_call.in_progress";
515    pub const RESPONSE_MCP_CALL_COMPLETED: &'static str = "response.mcp_call.completed";
516    pub const RESPONSE_MCP_CALL_FAILED: &'static str = "response.mcp_call.failed";
517    // MCP list tools events
518    pub const MCP_LIST_TOOLS_IN_PROGRESS: &'static str = "mcp_list_tools.in_progress";
519    pub const MCP_LIST_TOOLS_COMPLETED: &'static str = "mcp_list_tools.completed";
520    pub const MCP_LIST_TOOLS_FAILED: &'static str = "mcp_list_tools.failed";
521    // Rate limits
522    pub const RATE_LIMITS_UPDATED: &'static str = "rate_limits.updated";
523    // Error
524    pub const ERROR: &'static str = "error";
525
526    pub const fn as_str(self) -> &'static str {
527        match self {
528            Self::SessionCreated => Self::SESSION_CREATED,
529            Self::SessionUpdated => Self::SESSION_UPDATED,
530            Self::ConversationCreated => Self::CONVERSATION_CREATED,
531            Self::ConversationItemCreated => Self::CONVERSATION_ITEM_CREATED,
532            Self::ConversationItemAdded => Self::CONVERSATION_ITEM_ADDED,
533            Self::ConversationItemDone => Self::CONVERSATION_ITEM_DONE,
534            Self::ConversationItemDeleted => Self::CONVERSATION_ITEM_DELETED,
535            Self::ConversationItemRetrieved => Self::CONVERSATION_ITEM_RETRIEVED,
536            Self::ConversationItemTruncated => Self::CONVERSATION_ITEM_TRUNCATED,
537            Self::ConversationItemInputAudioTranscriptionCompleted => {
538                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED
539            }
540            Self::ConversationItemInputAudioTranscriptionDelta => {
541                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA
542            }
543            Self::ConversationItemInputAudioTranscriptionFailed => {
544                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED
545            }
546            Self::ConversationItemInputAudioTranscriptionSegment => {
547                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT
548            }
549            Self::InputAudioBufferCleared => Self::INPUT_AUDIO_BUFFER_CLEARED,
550            Self::InputAudioBufferCommitted => Self::INPUT_AUDIO_BUFFER_COMMITTED,
551            Self::InputAudioBufferSpeechStarted => Self::INPUT_AUDIO_BUFFER_SPEECH_STARTED,
552            Self::InputAudioBufferSpeechStopped => Self::INPUT_AUDIO_BUFFER_SPEECH_STOPPED,
553            Self::InputAudioBufferTimeoutTriggered => Self::INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED,
554            Self::InputAudioBufferDtmfEventReceived => Self::INPUT_AUDIO_BUFFER_DTMF_EVENT_RECEIVED,
555            Self::OutputAudioBufferStarted => Self::OUTPUT_AUDIO_BUFFER_STARTED,
556            Self::OutputAudioBufferStopped => Self::OUTPUT_AUDIO_BUFFER_STOPPED,
557            Self::OutputAudioBufferCleared => Self::OUTPUT_AUDIO_BUFFER_CLEARED,
558            Self::ResponseCreated => Self::RESPONSE_CREATED,
559            Self::ResponseDone => Self::RESPONSE_DONE,
560            Self::ResponseOutputItemAdded => Self::RESPONSE_OUTPUT_ITEM_ADDED,
561            Self::ResponseOutputItemDone => Self::RESPONSE_OUTPUT_ITEM_DONE,
562            Self::ResponseContentPartAdded => Self::RESPONSE_CONTENT_PART_ADDED,
563            Self::ResponseContentPartDone => Self::RESPONSE_CONTENT_PART_DONE,
564            Self::ResponseOutputTextDelta => Self::RESPONSE_OUTPUT_TEXT_DELTA,
565            Self::ResponseOutputTextDone => Self::RESPONSE_OUTPUT_TEXT_DONE,
566            Self::ResponseOutputAudioDelta => Self::RESPONSE_OUTPUT_AUDIO_DELTA,
567            Self::ResponseOutputAudioDone => Self::RESPONSE_OUTPUT_AUDIO_DONE,
568            Self::ResponseOutputAudioTranscriptDelta => {
569                Self::RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA
570            }
571            Self::ResponseOutputAudioTranscriptDone => Self::RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE,
572            Self::ResponseFunctionCallArgumentsDelta => {
573                Self::RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA
574            }
575            Self::ResponseFunctionCallArgumentsDone => Self::RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE,
576            Self::ResponseMcpCallArgumentsDelta => Self::RESPONSE_MCP_CALL_ARGUMENTS_DELTA,
577            Self::ResponseMcpCallArgumentsDone => Self::RESPONSE_MCP_CALL_ARGUMENTS_DONE,
578            Self::ResponseMcpCallInProgress => Self::RESPONSE_MCP_CALL_IN_PROGRESS,
579            Self::ResponseMcpCallCompleted => Self::RESPONSE_MCP_CALL_COMPLETED,
580            Self::ResponseMcpCallFailed => Self::RESPONSE_MCP_CALL_FAILED,
581            Self::McpListToolsInProgress => Self::MCP_LIST_TOOLS_IN_PROGRESS,
582            Self::McpListToolsCompleted => Self::MCP_LIST_TOOLS_COMPLETED,
583            Self::McpListToolsFailed => Self::MCP_LIST_TOOLS_FAILED,
584            Self::RateLimitsUpdated => Self::RATE_LIMITS_UPDATED,
585            Self::Error => Self::ERROR,
586        }
587    }
588}
589
590impl fmt::Display for RealtimeServerEvent {
591    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592        f.write_str(self.as_str())
593    }
594}
595
596/// Check if an event type string matches any response lifecycle event
597pub fn is_response_event(event_type: &str) -> bool {
598    matches!(
599        event_type,
600        ResponseEvent::CREATED | ResponseEvent::IN_PROGRESS | ResponseEvent::COMPLETED
601    )
602}
603
604/// Check if an item type string is a function call variant
605pub fn is_function_call_type(item_type: &str) -> bool {
606    item_type == ItemType::FUNCTION_CALL || item_type == ItemType::FUNCTION_TOOL_CALL
607}