Skip to content

Commit eb2c963

Browse files
committed
fix(websockets): re-apply manual patches after regen
1 parent 75ed739 commit eb2c963

4 files changed

Lines changed: 86 additions & 74 deletions

File tree

src/deepgram/agent/v1/socket_client.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import json
44
import logging
55
import typing
6-
from json.decoder import JSONDecodeError
76

8-
import websockets
97
import websockets.sync.connection as websockets_sync_connection
108
from ...core.events import EventEmitterMixin, EventType
119
from ...core.unchecked_base_model import construct_type
@@ -39,6 +37,26 @@
3937
from websockets import WebSocketClientProtocol # type: ignore
4038

4139
_logger = logging.getLogger(__name__)
40+
41+
42+
def _sanitize_numeric_types(obj: typing.Any) -> typing.Any:
43+
"""
44+
Recursively convert float values that are whole numbers to int.
45+
46+
Workaround for Fern-generated models that type integer API fields
47+
(like sample_rate) as float, causing JSON serialization to produce
48+
values like 44100.0 instead of 44100. The Deepgram API rejects
49+
float representations of integer fields.
50+
51+
See: https://github.com/deepgram/internal-api-specs/issues/205
52+
"""
53+
if isinstance(obj, dict):
54+
return {k: _sanitize_numeric_types(v) for k, v in obj.items()}
55+
elif isinstance(obj, list):
56+
return [_sanitize_numeric_types(item) for item in obj]
57+
elif isinstance(obj, float) and obj.is_integer():
58+
return int(obj)
59+
return obj
4260
V1SocketClientResponse = typing.Union[
4361
AgentV1ReceiveFunctionCallResponse,
4462
AgentV1PromptUpdated,
@@ -70,7 +88,7 @@ async def __aiter__(self):
7088
yield message
7189
else:
7290
try:
73-
yield construct_type(V1SocketClientResponse, json.loads(message)) # type: ignore
91+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
7492
except Exception:
7593
_logger.warning(
7694
"Skipping unknown WebSocket message; update your SDK version to support new message types."
@@ -95,14 +113,14 @@ async def start_listening(self):
95113
else:
96114
json_data = json.loads(raw_message)
97115
try:
98-
parsed = construct_type(V1SocketClientResponse, json_data) # type: ignore
116+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
99117
except Exception:
100118
_logger.warning(
101119
"Skipping unknown WebSocket message; update your SDK version to support new message types."
102120
)
103121
continue
104122
await self._emit_async(EventType.MESSAGE, parsed)
105-
except (websockets.WebSocketException, JSONDecodeError) as exc:
123+
except Exception as exc:
106124
await self._emit_async(EventType.ERROR, exc)
107125
finally:
108126
await self._emit_async(EventType.CLOSE, None)
@@ -142,12 +160,12 @@ async def send_function_call_response(self, message: AgentV1SendFunctionCallResp
142160
"""
143161
await self._send_model(message)
144162

145-
async def send_keep_alive(self, message: AgentV1KeepAlive) -> None:
163+
async def send_keep_alive(self, message: typing.Optional[AgentV1KeepAlive] = None) -> None:
146164
"""
147165
Send a message to the websocket connection.
148166
The message will be sent as a AgentV1KeepAlive.
149167
"""
150-
await self._send_model(message)
168+
await self._send_model(message or AgentV1KeepAlive(type="KeepAlive"))
151169

152170
async def send_update_prompt(self, message: AgentV1UpdatePrompt) -> None:
153171
"""
@@ -179,7 +197,7 @@ async def recv(self) -> V1SocketClientResponse:
179197
return data # type: ignore
180198
json_data = json.loads(data)
181199
try:
182-
return construct_type(V1SocketClientResponse, json_data) # type: ignore
200+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
183201
except Exception:
184202
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
185203
return json_data # type: ignore
@@ -196,7 +214,7 @@ async def _send_model(self, data: typing.Any) -> None:
196214
"""
197215
Send a Pydantic model to the websocket connection.
198216
"""
199-
await self._send(data.dict())
217+
await self._send(_sanitize_numeric_types(data.dict()))
200218

201219

202220
class V1SocketClient(EventEmitterMixin):
@@ -210,7 +228,7 @@ def __iter__(self):
210228
yield message
211229
else:
212230
try:
213-
yield construct_type(V1SocketClientResponse, json.loads(message)) # type: ignore
231+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
214232
except Exception:
215233
_logger.warning(
216234
"Skipping unknown WebSocket message; update your SDK version to support new message types."
@@ -235,14 +253,14 @@ def start_listening(self):
235253
else:
236254
json_data = json.loads(raw_message)
237255
try:
238-
parsed = construct_type(V1SocketClientResponse, json_data) # type: ignore
256+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
239257
except Exception:
240258
_logger.warning(
241259
"Skipping unknown WebSocket message; update your SDK version to support new message types."
242260
)
243261
continue
244262
self._emit(EventType.MESSAGE, parsed)
245-
except (websockets.WebSocketException, JSONDecodeError) as exc:
263+
except Exception as exc:
246264
self._emit(EventType.ERROR, exc)
247265
finally:
248266
self._emit(EventType.CLOSE, None)
@@ -282,12 +300,12 @@ def send_function_call_response(self, message: AgentV1SendFunctionCallResponse)
282300
"""
283301
self._send_model(message)
284302

285-
def send_keep_alive(self, message: AgentV1KeepAlive) -> None:
303+
def send_keep_alive(self, message: typing.Optional[AgentV1KeepAlive] = None) -> None:
286304
"""
287305
Send a message to the websocket connection.
288306
The message will be sent as a AgentV1KeepAlive.
289307
"""
290-
self._send_model(message)
308+
self._send_model(message or AgentV1KeepAlive(type="KeepAlive"))
291309

292310
def send_update_prompt(self, message: AgentV1UpdatePrompt) -> None:
293311
"""
@@ -319,7 +337,7 @@ def recv(self) -> V1SocketClientResponse:
319337
return data # type: ignore
320338
json_data = json.loads(data)
321339
try:
322-
return construct_type(V1SocketClientResponse, json_data) # type: ignore
340+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
323341
except Exception:
324342
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
325343
return json_data # type: ignore
@@ -336,4 +354,4 @@ def _send_model(self, data: typing.Any) -> None:
336354
"""
337355
Send a Pydantic model to the websocket connection.
338356
"""
339-
self._send(data.dict())
357+
self._send(_sanitize_numeric_types(data.dict()))

src/deepgram/listen/v1/socket_client.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import json
44
import logging
55
import typing
6-
from json.decoder import JSONDecodeError
76

8-
import websockets
97
import websockets.sync.connection as websockets_sync_connection
108
from ...core.events import EventEmitterMixin, EventType
119
from ...core.unchecked_base_model import construct_type
@@ -37,7 +35,7 @@ async def __aiter__(self):
3735
yield message
3836
else:
3937
try:
40-
yield construct_type(V1SocketClientResponse, json.loads(message)) # type: ignore
38+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
4139
except Exception:
4240
_logger.warning(
4341
"Skipping unknown WebSocket message; update your SDK version to support new message types."
@@ -62,14 +60,14 @@ async def start_listening(self):
6260
else:
6361
json_data = json.loads(raw_message)
6462
try:
65-
parsed = construct_type(V1SocketClientResponse, json_data) # type: ignore
63+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
6664
except Exception:
6765
_logger.warning(
6866
"Skipping unknown WebSocket message; update your SDK version to support new message types."
6967
)
7068
continue
7169
await self._emit_async(EventType.MESSAGE, parsed)
72-
except (websockets.WebSocketException, JSONDecodeError) as exc:
70+
except Exception as exc:
7371
await self._emit_async(EventType.ERROR, exc)
7472
finally:
7573
await self._emit_async(EventType.CLOSE, None)
@@ -81,26 +79,26 @@ async def send_media(self, message: bytes) -> None:
8179
"""
8280
await self._send(message)
8381

84-
async def send_finalize(self, message: ListenV1Finalize) -> None:
82+
async def send_finalize(self, message: typing.Optional[ListenV1Finalize] = None) -> None:
8583
"""
8684
Send a message to the websocket connection.
8785
The message will be sent as a ListenV1Finalize.
8886
"""
89-
await self._send_model(message)
87+
await self._send_model(message or ListenV1Finalize(type="Finalize"))
9088

91-
async def send_close_stream(self, message: ListenV1CloseStream) -> None:
89+
async def send_close_stream(self, message: typing.Optional[ListenV1CloseStream] = None) -> None:
9290
"""
9391
Send a message to the websocket connection.
9492
The message will be sent as a ListenV1CloseStream.
9593
"""
96-
await self._send_model(message)
94+
await self._send_model(message or ListenV1CloseStream(type="CloseStream"))
9795

98-
async def send_keep_alive(self, message: ListenV1KeepAlive) -> None:
96+
async def send_keep_alive(self, message: typing.Optional[ListenV1KeepAlive] = None) -> None:
9997
"""
10098
Send a message to the websocket connection.
10199
The message will be sent as a ListenV1KeepAlive.
102100
"""
103-
await self._send_model(message)
101+
await self._send_model(message or ListenV1KeepAlive(type="KeepAlive"))
104102

105103
async def recv(self) -> V1SocketClientResponse:
106104
"""
@@ -111,7 +109,7 @@ async def recv(self) -> V1SocketClientResponse:
111109
return data # type: ignore
112110
json_data = json.loads(data)
113111
try:
114-
return construct_type(V1SocketClientResponse, json_data) # type: ignore
112+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
115113
except Exception:
116114
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
117115
return json_data # type: ignore
@@ -142,7 +140,7 @@ def __iter__(self):
142140
yield message
143141
else:
144142
try:
145-
yield construct_type(V1SocketClientResponse, json.loads(message)) # type: ignore
143+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
146144
except Exception:
147145
_logger.warning(
148146
"Skipping unknown WebSocket message; update your SDK version to support new message types."
@@ -167,14 +165,14 @@ def start_listening(self):
167165
else:
168166
json_data = json.loads(raw_message)
169167
try:
170-
parsed = construct_type(V1SocketClientResponse, json_data) # type: ignore
168+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
171169
except Exception:
172170
_logger.warning(
173171
"Skipping unknown WebSocket message; update your SDK version to support new message types."
174172
)
175173
continue
176174
self._emit(EventType.MESSAGE, parsed)
177-
except (websockets.WebSocketException, JSONDecodeError) as exc:
175+
except Exception as exc:
178176
self._emit(EventType.ERROR, exc)
179177
finally:
180178
self._emit(EventType.CLOSE, None)
@@ -186,26 +184,26 @@ def send_media(self, message: bytes) -> None:
186184
"""
187185
self._send(message)
188186

189-
def send_finalize(self, message: ListenV1Finalize) -> None:
187+
def send_finalize(self, message: typing.Optional[ListenV1Finalize] = None) -> None:
190188
"""
191189
Send a message to the websocket connection.
192190
The message will be sent as a ListenV1Finalize.
193191
"""
194-
self._send_model(message)
192+
self._send_model(message or ListenV1Finalize(type="Finalize"))
195193

196-
def send_close_stream(self, message: ListenV1CloseStream) -> None:
194+
def send_close_stream(self, message: typing.Optional[ListenV1CloseStream] = None) -> None:
197195
"""
198196
Send a message to the websocket connection.
199197
The message will be sent as a ListenV1CloseStream.
200198
"""
201-
self._send_model(message)
199+
self._send_model(message or ListenV1CloseStream(type="CloseStream"))
202200

203-
def send_keep_alive(self, message: ListenV1KeepAlive) -> None:
201+
def send_keep_alive(self, message: typing.Optional[ListenV1KeepAlive] = None) -> None:
204202
"""
205203
Send a message to the websocket connection.
206204
The message will be sent as a ListenV1KeepAlive.
207205
"""
208-
self._send_model(message)
206+
self._send_model(message or ListenV1KeepAlive(type="KeepAlive"))
209207

210208
def recv(self) -> V1SocketClientResponse:
211209
"""
@@ -216,7 +214,7 @@ def recv(self) -> V1SocketClientResponse:
216214
return data # type: ignore
217215
json_data = json.loads(data)
218216
try:
219-
return construct_type(V1SocketClientResponse, json_data) # type: ignore
217+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
220218
except Exception:
221219
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
222220
return json_data # type: ignore

0 commit comments

Comments
 (0)