1
+ """
2
+ Realtime model events module with Pydantic validation.
3
+
4
+ This module defines all model-level events that can be emitted during realtime model operations.
5
+ """
6
+
1
7
from __future__ import annotations
2
8
3
- from dataclasses import dataclass
4
9
from typing import Any , Literal , Union
5
10
11
+ from pydantic import BaseModel , ConfigDict , Field
6
12
from typing_extensions import TypeAlias
7
13
8
14
from .items import RealtimeItem
9
15
10
16
RealtimeConnectionStatus : TypeAlias = Literal ["connecting" , "connected" , "disconnected" ]
11
17
12
18
13
- @dataclass
14
- class RealtimeModelErrorEvent :
19
+ class RealtimeModelErrorEvent (BaseModel ):
15
20
"""Represents a transport‑layer error."""
16
21
17
- error : Any
22
+ model_config = ConfigDict (
23
+ arbitrary_types_allowed = True ,
24
+ validate_assignment = True ,
25
+ extra = "forbid" ,
26
+ frozen = True ,
27
+ )
18
28
19
- type : Literal ["error" ] = "error"
29
+ error : Any = Field (..., description = "The error that occurred." )
30
+ type : Literal ["error" ] = Field (default = "error" , description = "Event type identifier." )
20
31
21
32
22
- @dataclass
23
- class RealtimeModelToolCallEvent :
33
+ class RealtimeModelToolCallEvent (BaseModel ):
24
34
"""Model attempted a tool/function call."""
25
35
26
- name : str
27
- call_id : str
28
- arguments : str
29
-
30
- id : str | None = None
31
- previous_item_id : str | None = None
32
-
33
- type : Literal ["function_call" ] = "function_call"
34
-
35
-
36
- @dataclass
37
- class RealtimeModelAudioEvent :
36
+ model_config = ConfigDict (
37
+ arbitrary_types_allowed = True ,
38
+ validate_assignment = True ,
39
+ extra = "forbid" ,
40
+ frozen = True ,
41
+ )
42
+
43
+ name : str = Field (..., description = "The name of the tool/function being called." )
44
+ call_id : str = Field (..., description = "Unique identifier for this tool call." )
45
+ arguments : str = Field (..., description = "JSON string of arguments for the tool call." )
46
+ id : str | None = Field (default = None , description = "Optional item ID." )
47
+ previous_item_id : str | None = Field (
48
+ default = None , description = "ID of the previous item in the conversation."
49
+ )
50
+ type : Literal ["function_call" ] = Field (
51
+ default = "function_call" , description = "Event type identifier."
52
+ )
53
+
54
+
55
+ class RealtimeModelAudioEvent (BaseModel ):
38
56
"""Raw audio bytes emitted by the model."""
39
57
40
- data : bytes
41
- response_id : str
42
-
43
- item_id : str
44
- """The ID of the item containing audio."""
45
-
46
- content_index : int
47
- """The index of the audio content in `item.content`"""
58
+ model_config = ConfigDict (
59
+ arbitrary_types_allowed = True ,
60
+ validate_assignment = True ,
61
+ extra = "forbid" ,
62
+ frozen = True ,
63
+ )
48
64
49
- type : Literal ["audio" ] = "audio"
65
+ data : bytes = Field (..., description = "The raw audio data bytes." )
66
+ response_id : str = Field (..., description = "ID of the response containing this audio." )
67
+ item_id : str = Field (..., description = "The ID of the item containing audio." )
68
+ content_index : int = Field (..., description = "The index of the audio content in `item.content`" )
69
+ type : Literal ["audio" ] = Field (default = "audio" , description = "Event type identifier." )
50
70
51
71
52
- @dataclass
53
- class RealtimeModelAudioInterruptedEvent :
72
+ class RealtimeModelAudioInterruptedEvent (BaseModel ):
54
73
"""Audio interrupted."""
55
74
56
- item_id : str
57
- """The ID of the item containing audio."""
75
+ model_config = ConfigDict (
76
+ arbitrary_types_allowed = True ,
77
+ validate_assignment = True ,
78
+ extra = "forbid" ,
79
+ frozen = True ,
80
+ )
58
81
59
- content_index : int
60
- """The index of the audio content in `item.content`"""
82
+ item_id : str = Field (..., description = "The ID of the item containing audio." )
83
+ content_index : int = Field (..., description = "The index of the audio content in `item.content`" )
84
+ type : Literal ["audio_interrupted" ] = Field (
85
+ default = "audio_interrupted" , description = "Event type identifier."
86
+ )
61
87
62
- type : Literal ["audio_interrupted" ] = "audio_interrupted"
63
88
64
-
65
- @dataclass
66
- class RealtimeModelAudioDoneEvent :
89
+ class RealtimeModelAudioDoneEvent (BaseModel ):
67
90
"""Audio done."""
68
91
69
- item_id : str
70
- """The ID of the item containing audio."""
71
-
72
- content_index : int
73
- """The index of the audio content in `item.content`"""
92
+ model_config = ConfigDict (
93
+ arbitrary_types_allowed = True ,
94
+ validate_assignment = True ,
95
+ extra = "forbid" ,
96
+ frozen = True ,
97
+ )
74
98
75
- type : Literal ["audio_done" ] = "audio_done"
99
+ item_id : str = Field (..., description = "The ID of the item containing audio." )
100
+ content_index : int = Field (..., description = "The index of the audio content in `item.content`" )
101
+ type : Literal ["audio_done" ] = Field (default = "audio_done" , description = "Event type identifier." )
76
102
77
103
78
- @dataclass
79
- class RealtimeModelInputAudioTranscriptionCompletedEvent :
104
+ class RealtimeModelInputAudioTranscriptionCompletedEvent (BaseModel ):
80
105
"""Input audio transcription completed."""
81
106
82
- item_id : str
83
- transcript : str
107
+ model_config = ConfigDict (
108
+ arbitrary_types_allowed = True ,
109
+ validate_assignment = True ,
110
+ extra = "forbid" ,
111
+ frozen = True ,
112
+ )
84
113
85
- type : Literal ["input_audio_transcription_completed" ] = "input_audio_transcription_completed"
114
+ item_id : str = Field (..., description = "ID of the audio item that was transcribed." )
115
+ transcript : str = Field (..., description = "The completed transcript text." )
116
+ type : Literal ["input_audio_transcription_completed" ] = Field (
117
+ default = "input_audio_transcription_completed" , description = "Event type identifier."
118
+ )
86
119
87
120
88
- @dataclass
89
- class RealtimeModelTranscriptDeltaEvent :
121
+ class RealtimeModelTranscriptDeltaEvent (BaseModel ):
90
122
"""Partial transcript update."""
91
123
92
- item_id : str
93
- delta : str
94
- response_id : str
124
+ model_config = ConfigDict (
125
+ arbitrary_types_allowed = True ,
126
+ validate_assignment = True ,
127
+ extra = "forbid" ,
128
+ frozen = True ,
129
+ )
95
130
96
- type : Literal ["transcript_delta" ] = "transcript_delta"
131
+ item_id : str = Field (..., description = "ID of the item being transcribed." )
132
+ delta : str = Field (..., description = "The incremental transcript text." )
133
+ response_id : str = Field (..., description = "ID of the response containing this transcript." )
134
+ type : Literal ["transcript_delta" ] = Field (
135
+ default = "transcript_delta" , description = "Event type identifier."
136
+ )
97
137
98
138
99
- @dataclass
100
- class RealtimeModelItemUpdatedEvent :
139
+ class RealtimeModelItemUpdatedEvent (BaseModel ):
101
140
"""Item added to the history or updated."""
102
141
103
- item : RealtimeItem
142
+ model_config = ConfigDict (
143
+ arbitrary_types_allowed = True ,
144
+ validate_assignment = True ,
145
+ extra = "forbid" ,
146
+ frozen = True ,
147
+ )
104
148
105
- type : Literal ["item_updated" ] = "item_updated"
149
+ item : RealtimeItem = Field (..., description = "The item that was updated or added." )
150
+ type : Literal ["item_updated" ] = Field (
151
+ default = "item_updated" , description = "Event type identifier."
152
+ )
106
153
107
154
108
- @dataclass
109
- class RealtimeModelItemDeletedEvent :
155
+ class RealtimeModelItemDeletedEvent (BaseModel ):
110
156
"""Item deleted from the history."""
111
157
112
- item_id : str
158
+ model_config = ConfigDict (
159
+ arbitrary_types_allowed = True ,
160
+ validate_assignment = True ,
161
+ extra = "forbid" ,
162
+ frozen = True ,
163
+ )
113
164
114
- type : Literal ["item_deleted" ] = "item_deleted"
165
+ item_id : str = Field (..., description = "ID of the deleted item." )
166
+ type : Literal ["item_deleted" ] = Field (
167
+ default = "item_deleted" , description = "Event type identifier."
168
+ )
115
169
116
170
117
- @dataclass
118
- class RealtimeModelConnectionStatusEvent :
171
+ class RealtimeModelConnectionStatusEvent (BaseModel ):
119
172
"""Connection status changed."""
120
173
121
- status : RealtimeConnectionStatus
174
+ model_config = ConfigDict (
175
+ arbitrary_types_allowed = True ,
176
+ validate_assignment = True ,
177
+ extra = "forbid" ,
178
+ frozen = True ,
179
+ )
122
180
123
- type : Literal ["connection_status" ] = "connection_status"
181
+ status : RealtimeConnectionStatus = Field (..., description = "The new connection status." )
182
+ type : Literal ["connection_status" ] = Field (
183
+ default = "connection_status" , description = "Event type identifier."
184
+ )
124
185
125
186
126
- @dataclass
127
- class RealtimeModelTurnStartedEvent :
187
+ class RealtimeModelTurnStartedEvent (BaseModel ):
128
188
"""Triggered when the model starts generating a response for a turn."""
129
189
130
- type : Literal ["turn_started" ] = "turn_started"
190
+ model_config = ConfigDict (
191
+ arbitrary_types_allowed = True ,
192
+ validate_assignment = True ,
193
+ extra = "forbid" ,
194
+ frozen = True ,
195
+ )
131
196
197
+ type : Literal ["turn_started" ] = Field (
198
+ default = "turn_started" , description = "Event type identifier."
199
+ )
132
200
133
- @ dataclass
134
- class RealtimeModelTurnEndedEvent :
201
+
202
+ class RealtimeModelTurnEndedEvent ( BaseModel ) :
135
203
"""Triggered when the model finishes generating a response for a turn."""
136
204
137
- type : Literal ["turn_ended" ] = "turn_ended"
205
+ model_config = ConfigDict (
206
+ arbitrary_types_allowed = True ,
207
+ validate_assignment = True ,
208
+ extra = "forbid" ,
209
+ frozen = True ,
210
+ )
211
+
212
+ type : Literal ["turn_ended" ] = Field (default = "turn_ended" , description = "Event type identifier." )
138
213
139
214
140
- @dataclass
141
- class RealtimeModelOtherEvent :
215
+ class RealtimeModelOtherEvent (BaseModel ):
142
216
"""Used as a catchall for vendor-specific events."""
143
217
144
- data : Any
218
+ model_config = ConfigDict (
219
+ arbitrary_types_allowed = True ,
220
+ validate_assignment = True ,
221
+ extra = "forbid" ,
222
+ frozen = True ,
223
+ )
145
224
146
- type : Literal ["other" ] = "other"
225
+ data : Any = Field (..., description = "The vendor-specific event data." )
226
+ type : Literal ["other" ] = Field (default = "other" , description = "Event type identifier." )
147
227
148
228
149
- @dataclass
150
- class RealtimeModelExceptionEvent :
229
+ class RealtimeModelExceptionEvent (BaseModel ):
151
230
"""Exception occurred during model operation."""
152
231
153
- exception : Exception
154
- context : str | None = None
232
+ model_config = ConfigDict (
233
+ arbitrary_types_allowed = True ,
234
+ validate_assignment = True ,
235
+ extra = "forbid" ,
236
+ frozen = True ,
237
+ )
155
238
156
- type : Literal ["exception" ] = "exception"
239
+ exception : Exception = Field (..., description = "The exception that occurred." )
240
+ context : str | None = Field (
241
+ default = None , description = "Additional context about where the exception occurred."
242
+ )
243
+ type : Literal ["exception" ] = Field (default = "exception" , description = "Event type identifier." )
157
244
158
245
159
- @dataclass
160
- class RealtimeModelRawServerEvent :
246
+ class RealtimeModelRawServerEvent (BaseModel ):
161
247
"""Raw events forwarded from the server."""
162
248
163
- data : Any
249
+ model_config = ConfigDict (
250
+ arbitrary_types_allowed = True ,
251
+ validate_assignment = True ,
252
+ extra = "forbid" ,
253
+ frozen = True ,
254
+ )
164
255
165
- type : Literal [ "raw_server_event" ] = "raw_server_event"
166
-
167
-
168
- # TODO (rm) Add usage events
256
+ data : Any = Field (..., description = "The raw server event data." )
257
+ type : Literal [ "raw_server_event" ] = Field (
258
+ default = "raw_server_event" , description = "Event type identifier."
259
+ )
169
260
170
261
171
262
RealtimeModelEvent : TypeAlias = Union [
@@ -185,3 +276,21 @@ class RealtimeModelRawServerEvent:
185
276
RealtimeModelExceptionEvent ,
186
277
RealtimeModelRawServerEvent ,
187
278
]
279
+
280
+
281
+ # Rebuild models after all definitions
282
+ RealtimeModelErrorEvent .model_rebuild ()
283
+ RealtimeModelToolCallEvent .model_rebuild ()
284
+ RealtimeModelAudioEvent .model_rebuild ()
285
+ RealtimeModelAudioInterruptedEvent .model_rebuild ()
286
+ RealtimeModelAudioDoneEvent .model_rebuild ()
287
+ RealtimeModelInputAudioTranscriptionCompletedEvent .model_rebuild ()
288
+ RealtimeModelTranscriptDeltaEvent .model_rebuild ()
289
+ RealtimeModelItemUpdatedEvent .model_rebuild ()
290
+ RealtimeModelItemDeletedEvent .model_rebuild ()
291
+ RealtimeModelConnectionStatusEvent .model_rebuild ()
292
+ RealtimeModelTurnStartedEvent .model_rebuild ()
293
+ RealtimeModelTurnEndedEvent .model_rebuild ()
294
+ RealtimeModelOtherEvent .model_rebuild ()
295
+ RealtimeModelExceptionEvent .model_rebuild ()
296
+ RealtimeModelRawServerEvent .model_rebuild ()
0 commit comments