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_CALL_OUTPUT: &'static str = "function_call_output";
282    pub const FUNCTION_TOOL_CALL: &'static str = "function_tool_call";
283    pub const MCP_CALL: &'static str = "mcp_call";
284    pub const FUNCTION: &'static str = "function";
285    pub const MCP_LIST_TOOLS: &'static str = "mcp_list_tools";
286    pub const WEB_SEARCH_CALL: &'static str = "web_search_call";
287    pub const CODE_INTERPRETER_CALL: &'static str = "code_interpreter_call";
288    pub const FILE_SEARCH_CALL: &'static str = "file_search_call";
289
290    pub const fn as_str(self) -> &'static str {
291        match self {
292            Self::FunctionCall => Self::FUNCTION_CALL,
293            Self::FunctionToolCall => Self::FUNCTION_TOOL_CALL,
294            Self::McpCall => Self::MCP_CALL,
295            Self::Function => Self::FUNCTION,
296            Self::McpListTools => Self::MCP_LIST_TOOLS,
297            Self::WebSearchCall => Self::WEB_SEARCH_CALL,
298            Self::CodeInterpreterCall => Self::CODE_INTERPRETER_CALL,
299            Self::FileSearchCall => Self::FILE_SEARCH_CALL,
300        }
301    }
302
303    /// Check if this is a function call variant (FunctionCall or FunctionToolCall)
304    pub const fn is_function_call(self) -> bool {
305        matches!(self, Self::FunctionCall | Self::FunctionToolCall)
306    }
307
308    /// Check if this is a builtin tool call variant
309    pub const fn is_builtin_tool_call(self) -> bool {
310        matches!(
311            self,
312            Self::WebSearchCall | Self::CodeInterpreterCall | Self::FileSearchCall
313        )
314    }
315}
316
317impl fmt::Display for ItemType {
318    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319        f.write_str(self.as_str())
320    }
321}
322
323// ============================================================================
324// Realtime Client Events
325// ============================================================================
326
327/// Realtime API client events sent over WebSocket/WebRTC/SIP connections.
328#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
329pub enum RealtimeClientEvent {
330    ConversationItemCreate,
331    ConversationItemDelete,
332    ConversationItemRetrieve,
333    ConversationItemTruncate,
334    InputAudioBufferAppend,
335    InputAudioBufferClear,
336    InputAudioBufferCommit,
337    OutputAudioBufferClear,
338    ResponseCancel,
339    ResponseCreate,
340    SessionUpdate,
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
356    pub const fn as_str(self) -> &'static str {
357        match self {
358            Self::ConversationItemCreate => Self::CONVERSATION_ITEM_CREATE,
359            Self::ConversationItemDelete => Self::CONVERSATION_ITEM_DELETE,
360            Self::ConversationItemRetrieve => Self::CONVERSATION_ITEM_RETRIEVE,
361            Self::ConversationItemTruncate => Self::CONVERSATION_ITEM_TRUNCATE,
362            Self::InputAudioBufferAppend => Self::INPUT_AUDIO_BUFFER_APPEND,
363            Self::InputAudioBufferClear => Self::INPUT_AUDIO_BUFFER_CLEAR,
364            Self::InputAudioBufferCommit => Self::INPUT_AUDIO_BUFFER_COMMIT,
365            Self::OutputAudioBufferClear => Self::OUTPUT_AUDIO_BUFFER_CLEAR,
366            Self::ResponseCancel => Self::RESPONSE_CANCEL,
367            Self::ResponseCreate => Self::RESPONSE_CREATE,
368            Self::SessionUpdate => Self::SESSION_UPDATE,
369        }
370    }
371}
372
373impl fmt::Display for RealtimeClientEvent {
374    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375        f.write_str(self.as_str())
376    }
377}
378
379// ============================================================================
380// Realtime Server Events
381// ============================================================================
382
383/// Realtime API server events received over WebSocket/WebRTC/SIP connections.
384#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
385pub enum RealtimeServerEvent {
386    // Session events
387    SessionCreated,
388    SessionUpdated,
389    // Conversation events
390    ConversationCreated,
391    ConversationItemCreated,
392    ConversationItemAdded,
393    ConversationItemDone,
394    ConversationItemDeleted,
395    ConversationItemRetrieved,
396    ConversationItemTruncated,
397    // Input audio transcription events
398    ConversationItemInputAudioTranscriptionCompleted,
399    ConversationItemInputAudioTranscriptionDelta,
400    ConversationItemInputAudioTranscriptionFailed,
401    ConversationItemInputAudioTranscriptionSegment,
402    // Input audio buffer events
403    InputAudioBufferCleared,
404    InputAudioBufferCommitted,
405    InputAudioBufferSpeechStarted,
406    InputAudioBufferSpeechStopped,
407    InputAudioBufferTimeoutTriggered,
408    InputAudioBufferDtmfEventReceived,
409    // Output audio buffer events (WebRTC/SIP only)
410    OutputAudioBufferStarted,
411    OutputAudioBufferStopped,
412    OutputAudioBufferCleared,
413    // Response lifecycle events
414    ResponseCreated,
415    ResponseDone,
416    // Response output item events
417    ResponseOutputItemAdded,
418    ResponseOutputItemDone,
419    // Response content part events
420    ResponseContentPartAdded,
421    ResponseContentPartDone,
422    // Response text events
423    ResponseOutputTextDelta,
424    ResponseOutputTextDone,
425    // Response audio events
426    ResponseOutputAudioDelta,
427    ResponseOutputAudioDone,
428    // Response audio transcript events
429    ResponseOutputAudioTranscriptDelta,
430    ResponseOutputAudioTranscriptDone,
431    // Response function call events
432    ResponseFunctionCallArgumentsDelta,
433    ResponseFunctionCallArgumentsDone,
434    // Response MCP call events
435    ResponseMcpCallArgumentsDelta,
436    ResponseMcpCallArgumentsDone,
437    ResponseMcpCallInProgress,
438    ResponseMcpCallCompleted,
439    ResponseMcpCallFailed,
440    // MCP list tools events
441    McpListToolsInProgress,
442    McpListToolsCompleted,
443    McpListToolsFailed,
444    // Rate limits
445    RateLimitsUpdated,
446    // Error
447    Error,
448}
449
450impl RealtimeServerEvent {
451    // Session events
452    pub const SESSION_CREATED: &'static str = "session.created";
453    pub const SESSION_UPDATED: &'static str = "session.updated";
454    // Conversation events
455    pub const CONVERSATION_CREATED: &'static str = "conversation.created";
456    pub const CONVERSATION_ITEM_CREATED: &'static str = "conversation.item.created";
457    pub const CONVERSATION_ITEM_ADDED: &'static str = "conversation.item.added";
458    pub const CONVERSATION_ITEM_DONE: &'static str = "conversation.item.done";
459    pub const CONVERSATION_ITEM_DELETED: &'static str = "conversation.item.deleted";
460    pub const CONVERSATION_ITEM_RETRIEVED: &'static str = "conversation.item.retrieved";
461    pub const CONVERSATION_ITEM_TRUNCATED: &'static str = "conversation.item.truncated";
462    // Input audio transcription events
463    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED: &'static str =
464        "conversation.item.input_audio_transcription.completed";
465    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA: &'static str =
466        "conversation.item.input_audio_transcription.delta";
467    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED: &'static str =
468        "conversation.item.input_audio_transcription.failed";
469    pub const CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT: &'static str =
470        "conversation.item.input_audio_transcription.segment";
471    // Input audio buffer events
472    pub const INPUT_AUDIO_BUFFER_CLEARED: &'static str = "input_audio_buffer.cleared";
473    pub const INPUT_AUDIO_BUFFER_COMMITTED: &'static str = "input_audio_buffer.committed";
474    pub const INPUT_AUDIO_BUFFER_SPEECH_STARTED: &'static str = "input_audio_buffer.speech_started";
475    pub const INPUT_AUDIO_BUFFER_SPEECH_STOPPED: &'static str = "input_audio_buffer.speech_stopped";
476    pub const INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED: &'static str =
477        "input_audio_buffer.timeout_triggered";
478    pub const INPUT_AUDIO_BUFFER_DTMF_EVENT_RECEIVED: &'static str =
479        "input_audio_buffer.dtmf_event_received";
480    // Output audio buffer events
481    pub const OUTPUT_AUDIO_BUFFER_STARTED: &'static str = "output_audio_buffer.started";
482    pub const OUTPUT_AUDIO_BUFFER_STOPPED: &'static str = "output_audio_buffer.stopped";
483    pub const OUTPUT_AUDIO_BUFFER_CLEARED: &'static str = "output_audio_buffer.cleared";
484    // Response lifecycle events
485    pub const RESPONSE_CREATED: &'static str = "response.created";
486    pub const RESPONSE_DONE: &'static str = "response.done";
487    // Response output item events
488    pub const RESPONSE_OUTPUT_ITEM_ADDED: &'static str = "response.output_item.added";
489    pub const RESPONSE_OUTPUT_ITEM_DONE: &'static str = "response.output_item.done";
490    // Response content part events
491    pub const RESPONSE_CONTENT_PART_ADDED: &'static str = "response.content_part.added";
492    pub const RESPONSE_CONTENT_PART_DONE: &'static str = "response.content_part.done";
493    // Response text events
494    pub const RESPONSE_OUTPUT_TEXT_DELTA: &'static str = "response.output_text.delta";
495    pub const RESPONSE_OUTPUT_TEXT_DONE: &'static str = "response.output_text.done";
496    // Response audio events
497    pub const RESPONSE_OUTPUT_AUDIO_DELTA: &'static str = "response.output_audio.delta";
498    pub const RESPONSE_OUTPUT_AUDIO_DONE: &'static str = "response.output_audio.done";
499    // Response audio transcript events
500    pub const RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA: &'static str =
501        "response.output_audio_transcript.delta";
502    pub const RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE: &'static str =
503        "response.output_audio_transcript.done";
504    // Response function call events
505    pub const RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA: &'static str =
506        "response.function_call_arguments.delta";
507    pub const RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE: &'static str =
508        "response.function_call_arguments.done";
509    // Response MCP call events
510    pub const RESPONSE_MCP_CALL_ARGUMENTS_DELTA: &'static str = "response.mcp_call_arguments.delta";
511    pub const RESPONSE_MCP_CALL_ARGUMENTS_DONE: &'static str = "response.mcp_call_arguments.done";
512    pub const RESPONSE_MCP_CALL_IN_PROGRESS: &'static str = "response.mcp_call.in_progress";
513    pub const RESPONSE_MCP_CALL_COMPLETED: &'static str = "response.mcp_call.completed";
514    pub const RESPONSE_MCP_CALL_FAILED: &'static str = "response.mcp_call.failed";
515    // MCP list tools events
516    pub const MCP_LIST_TOOLS_IN_PROGRESS: &'static str = "mcp_list_tools.in_progress";
517    pub const MCP_LIST_TOOLS_COMPLETED: &'static str = "mcp_list_tools.completed";
518    pub const MCP_LIST_TOOLS_FAILED: &'static str = "mcp_list_tools.failed";
519    // Rate limits
520    pub const RATE_LIMITS_UPDATED: &'static str = "rate_limits.updated";
521    // Error
522    pub const ERROR: &'static str = "error";
523
524    pub const fn as_str(self) -> &'static str {
525        match self {
526            Self::SessionCreated => Self::SESSION_CREATED,
527            Self::SessionUpdated => Self::SESSION_UPDATED,
528            Self::ConversationCreated => Self::CONVERSATION_CREATED,
529            Self::ConversationItemCreated => Self::CONVERSATION_ITEM_CREATED,
530            Self::ConversationItemAdded => Self::CONVERSATION_ITEM_ADDED,
531            Self::ConversationItemDone => Self::CONVERSATION_ITEM_DONE,
532            Self::ConversationItemDeleted => Self::CONVERSATION_ITEM_DELETED,
533            Self::ConversationItemRetrieved => Self::CONVERSATION_ITEM_RETRIEVED,
534            Self::ConversationItemTruncated => Self::CONVERSATION_ITEM_TRUNCATED,
535            Self::ConversationItemInputAudioTranscriptionCompleted => {
536                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED
537            }
538            Self::ConversationItemInputAudioTranscriptionDelta => {
539                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA
540            }
541            Self::ConversationItemInputAudioTranscriptionFailed => {
542                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED
543            }
544            Self::ConversationItemInputAudioTranscriptionSegment => {
545                Self::CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT
546            }
547            Self::InputAudioBufferCleared => Self::INPUT_AUDIO_BUFFER_CLEARED,
548            Self::InputAudioBufferCommitted => Self::INPUT_AUDIO_BUFFER_COMMITTED,
549            Self::InputAudioBufferSpeechStarted => Self::INPUT_AUDIO_BUFFER_SPEECH_STARTED,
550            Self::InputAudioBufferSpeechStopped => Self::INPUT_AUDIO_BUFFER_SPEECH_STOPPED,
551            Self::InputAudioBufferTimeoutTriggered => Self::INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED,
552            Self::InputAudioBufferDtmfEventReceived => Self::INPUT_AUDIO_BUFFER_DTMF_EVENT_RECEIVED,
553            Self::OutputAudioBufferStarted => Self::OUTPUT_AUDIO_BUFFER_STARTED,
554            Self::OutputAudioBufferStopped => Self::OUTPUT_AUDIO_BUFFER_STOPPED,
555            Self::OutputAudioBufferCleared => Self::OUTPUT_AUDIO_BUFFER_CLEARED,
556            Self::ResponseCreated => Self::RESPONSE_CREATED,
557            Self::ResponseDone => Self::RESPONSE_DONE,
558            Self::ResponseOutputItemAdded => Self::RESPONSE_OUTPUT_ITEM_ADDED,
559            Self::ResponseOutputItemDone => Self::RESPONSE_OUTPUT_ITEM_DONE,
560            Self::ResponseContentPartAdded => Self::RESPONSE_CONTENT_PART_ADDED,
561            Self::ResponseContentPartDone => Self::RESPONSE_CONTENT_PART_DONE,
562            Self::ResponseOutputTextDelta => Self::RESPONSE_OUTPUT_TEXT_DELTA,
563            Self::ResponseOutputTextDone => Self::RESPONSE_OUTPUT_TEXT_DONE,
564            Self::ResponseOutputAudioDelta => Self::RESPONSE_OUTPUT_AUDIO_DELTA,
565            Self::ResponseOutputAudioDone => Self::RESPONSE_OUTPUT_AUDIO_DONE,
566            Self::ResponseOutputAudioTranscriptDelta => {
567                Self::RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA
568            }
569            Self::ResponseOutputAudioTranscriptDone => Self::RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE,
570            Self::ResponseFunctionCallArgumentsDelta => {
571                Self::RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA
572            }
573            Self::ResponseFunctionCallArgumentsDone => Self::RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE,
574            Self::ResponseMcpCallArgumentsDelta => Self::RESPONSE_MCP_CALL_ARGUMENTS_DELTA,
575            Self::ResponseMcpCallArgumentsDone => Self::RESPONSE_MCP_CALL_ARGUMENTS_DONE,
576            Self::ResponseMcpCallInProgress => Self::RESPONSE_MCP_CALL_IN_PROGRESS,
577            Self::ResponseMcpCallCompleted => Self::RESPONSE_MCP_CALL_COMPLETED,
578            Self::ResponseMcpCallFailed => Self::RESPONSE_MCP_CALL_FAILED,
579            Self::McpListToolsInProgress => Self::MCP_LIST_TOOLS_IN_PROGRESS,
580            Self::McpListToolsCompleted => Self::MCP_LIST_TOOLS_COMPLETED,
581            Self::McpListToolsFailed => Self::MCP_LIST_TOOLS_FAILED,
582            Self::RateLimitsUpdated => Self::RATE_LIMITS_UPDATED,
583            Self::Error => Self::ERROR,
584        }
585    }
586}
587
588impl fmt::Display for RealtimeServerEvent {
589    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590        f.write_str(self.as_str())
591    }
592}
593
594/// Check if an event type string matches any response lifecycle event
595pub fn is_response_event(event_type: &str) -> bool {
596    matches!(
597        event_type,
598        ResponseEvent::CREATED | ResponseEvent::IN_PROGRESS | ResponseEvent::COMPLETED
599    )
600}
601
602/// Check if an item type string is a function call variant
603pub fn is_function_call_type(item_type: &str) -> bool {
604    item_type == ItemType::FUNCTION_CALL || item_type == ItemType::FUNCTION_TOOL_CALL
605}