Skip to content

Commit 0e2a77a

Browse files
committed
fix: re-apply manual patches after regen
- Float→int type fixes for speaker/channel/num_words fields - _sanitize_numeric_types helper in agent socket client - construct_type keyword arg fix (generator uses positional, function requires keyword-only) - Broad exception catch in socket clients (supports custom transports) - Remove .bak files and update .fernignore
1 parent a51380e commit 0e2a77a

20 files changed

+70
-1828
lines changed

.fernignore

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,21 @@
44
# This file is manually maintained and should not be regenerated
55
src/deepgram/client.py
66

7-
# WireMock mappings: removed duplicate empty-body /v1/listen stub that causes
8-
# non-deterministic matching failures
9-
# [temporarily frozen — .bak preserves our patch during regen]
10-
wiremock/wiremock-mappings.json.bak
11-
12-
# Wire test with manual fix: transcribe_file() requires request=bytes parameter
13-
# [temporarily frozen — .bak preserves our patch during regen]
14-
tests/wire/test_listen_v1_media.py.bak
15-
167
# WebSocket socket clients:
17-
# - Optional message parameter defaults for send_flush, send_close, send_clear,
18-
# send_finalize, send_close_stream, send_keep_alive
19-
# - construct_type instead of parse_obj_as (skip_validation for unknown WS messages)
20-
# - except Exception (broad catch for custom transports)
8+
# - construct_type keyword args fix (generator uses positional, function requires keyword-only)
9+
# - except Exception broad catch (supports custom transports, generator narrows to WebSocketException)
2110
# - _sanitize_numeric_types in agent socket client (float→int for API)
22-
# [temporarily frozen — .bak preserves our patches during regen]
23-
src/deepgram/speak/v1/socket_client.py.bak
24-
src/deepgram/listen/v1/socket_client.py.bak
25-
src/deepgram/listen/v2/socket_client.py.bak
26-
src/deepgram/agent/v1/socket_client.py.bak
11+
# [temporarily frozen — generator bugs in construct_type call convention and exception handling]
12+
src/deepgram/agent/v1/socket_client.py
13+
src/deepgram/listen/v1/socket_client.py
14+
src/deepgram/listen/v2/socket_client.py
15+
src/deepgram/speak/v1/socket_client.py
2716

2817
# Type files with manual int type corrections (Fern generates float for speaker/channel/num_words)
29-
# [temporarily frozen — .bak preserves our patches during regen]
30-
src/deepgram/types/listen_v1response_results_utterances_item.py.bak
31-
src/deepgram/types/listen_v1response_results_utterances_item_words_item.py.bak
32-
src/deepgram/types/listen_v1response_results_channels_item_alternatives_item_paragraphs_paragraphs_item.py.bak
33-
34-
# Redact type with Union[str, Sequence[str]] support (Fern narrows to Union[Literal, Any])
35-
# [temporarily frozen — .bak preserves our patch during regen]
36-
src/deepgram/types/listen_v1redact.py.bak
37-
38-
# Listen client files with Union[str, Sequence[str]] array param support
39-
# [temporarily frozen — .bak preserves our patches during regen]
40-
src/deepgram/listen/v1/client.py.bak
41-
src/deepgram/listen/v2/client.py.bak
18+
# [temporarily frozen — waiting on internal-api-specs#205]
19+
src/deepgram/types/listen_v1response_results_utterances_item.py
20+
src/deepgram/types/listen_v1response_results_utterances_item_words_item.py
21+
src/deepgram/types/listen_v1response_results_channels_item_alternatives_item_paragraphs_paragraphs_item.py
4222

4323
# Hand-written custom tests
4424
tests/custom/test_text_builder.py

src/deepgram/agent/v1/socket_client.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,26 @@
3737
from websockets import WebSocketClientProtocol # type: ignore
3838

3939
_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
4060
V1SocketClientResponse = typing.Union[
4161
AgentV1ReceiveFunctionCallResponse,
4262
AgentV1PromptUpdated,
@@ -67,7 +87,7 @@ async def __aiter__(self):
6787
yield message
6888
else:
6989
try:
70-
yield construct_type(V1SocketClientResponse, json.loads(message)) # type: ignore
90+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
7191
except Exception:
7292
_logger.warning(
7393
"Skipping unknown WebSocket message; update your SDK version to support new message types."
@@ -92,14 +112,14 @@ async def start_listening(self):
92112
else:
93113
json_data = json.loads(raw_message)
94114
try:
95-
parsed = construct_type(V1SocketClientResponse, json_data) # type: ignore
115+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
96116
except Exception:
97117
_logger.warning(
98118
"Skipping unknown WebSocket message; update your SDK version to support new message types."
99119
)
100120
continue
101121
await self._emit_async(EventType.MESSAGE, parsed)
102-
except (websockets.WebSocketException, JSONDecodeError) as exc:
122+
except Exception as exc:
103123
await self._emit_async(EventType.ERROR, exc)
104124
finally:
105125
await self._emit_async(EventType.CLOSE, None)
@@ -169,7 +189,7 @@ async def recv(self) -> V1SocketClientResponse:
169189
return data # type: ignore
170190
json_data = json.loads(data)
171191
try:
172-
return construct_type(V1SocketClientResponse, json_data) # type: ignore
192+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
173193
except Exception:
174194
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
175195
return json_data # type: ignore
@@ -186,7 +206,7 @@ async def _send_model(self, data: typing.Any) -> None:
186206
"""
187207
Send a Pydantic model to the websocket connection.
188208
"""
189-
await self._send(data.dict())
209+
await self._send(_sanitize_numeric_types(data.dict()))
190210

191211

192212
class V1SocketClient(EventEmitterMixin):
@@ -200,7 +220,7 @@ def __iter__(self):
200220
yield message
201221
else:
202222
try:
203-
yield construct_type(V1SocketClientResponse, json.loads(message)) # type: ignore
223+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
204224
except Exception:
205225
_logger.warning(
206226
"Skipping unknown WebSocket message; update your SDK version to support new message types."
@@ -225,14 +245,14 @@ def start_listening(self):
225245
else:
226246
json_data = json.loads(raw_message)
227247
try:
228-
parsed = construct_type(V1SocketClientResponse, json_data) # type: ignore
248+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
229249
except Exception:
230250
_logger.warning(
231251
"Skipping unknown WebSocket message; update your SDK version to support new message types."
232252
)
233253
continue
234254
self._emit(EventType.MESSAGE, parsed)
235-
except (websockets.WebSocketException, JSONDecodeError) as exc:
255+
except Exception as exc:
236256
self._emit(EventType.ERROR, exc)
237257
finally:
238258
self._emit(EventType.CLOSE, None)
@@ -302,7 +322,7 @@ def recv(self) -> V1SocketClientResponse:
302322
return data # type: ignore
303323
json_data = json.loads(data)
304324
try:
305-
return construct_type(V1SocketClientResponse, json_data) # type: ignore
325+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
306326
except Exception:
307327
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
308328
return json_data # type: ignore
@@ -319,4 +339,4 @@ def _send_model(self, data: typing.Any) -> None:
319339
"""
320340
Send a Pydantic model to the websocket connection.
321341
"""
322-
self._send(data.dict())
342+
self._send(_sanitize_numeric_types(data.dict()))

0 commit comments

Comments
 (0)