Skip to content

Commit f543b05

Browse files
committed
chore: unfreeze files pending regen
Copied 7 temporarily frozen files to .bak and updated .fernignore to protect patched versions while letting Fern overwrite originals.
1 parent e4557d9 commit f543b05

8 files changed

Lines changed: 1112 additions & 7 deletions

.fernignore

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@ src/deepgram/client.py
1111
# - optional message param on control send_ methods (send_keep_alive, send_close_stream, etc.)
1212
# so users don't need to instantiate the type themselves for no-payload control messages
1313
# [temporarily frozen — generator bugs in construct_type call convention and exception handling]
14-
src/deepgram/agent/v1/socket_client.py
15-
src/deepgram/listen/v1/socket_client.py
16-
src/deepgram/listen/v2/socket_client.py
17-
src/deepgram/speak/v1/socket_client.py
14+
# [REGEN: .bak copies preserved, originals unfrozen for Fern to overwrite]
15+
src/deepgram/agent/v1/socket_client.py.bak
16+
src/deepgram/listen/v1/socket_client.py.bak
17+
src/deepgram/listen/v2/socket_client.py.bak
18+
src/deepgram/speak/v1/socket_client.py.bak
1819

1920
# Type files with manual int type corrections (Fern generates float for speaker/channel/num_words)
2021
# [temporarily frozen — waiting on internal-api-specs#205]
21-
src/deepgram/types/listen_v1response_results_utterances_item.py
22-
src/deepgram/types/listen_v1response_results_utterances_item_words_item.py
23-
src/deepgram/types/listen_v1response_results_channels_item_alternatives_item_paragraphs_paragraphs_item.py
22+
# [REGEN: .bak copies preserved, originals unfrozen for Fern to overwrite]
23+
src/deepgram/types/listen_v1response_results_utterances_item.py.bak
24+
src/deepgram/types/listen_v1response_results_utterances_item_words_item.py.bak
25+
src/deepgram/types/listen_v1response_results_channels_item_alternatives_item_paragraphs_paragraphs_item.py.bak
2426

2527
# Hand-written custom tests
2628
tests/custom/test_text_builder.py
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
# This file was auto-generated by Fern from our API Definition.
2+
3+
import json
4+
import logging
5+
import typing
6+
from json.decoder import JSONDecodeError
7+
8+
import websockets
9+
import websockets.sync.connection as websockets_sync_connection
10+
from ...core.events import EventEmitterMixin, EventType
11+
from ...core.unchecked_base_model import construct_type
12+
from .types.agent_v1agent_audio_done import AgentV1AgentAudioDone
13+
from .types.agent_v1agent_started_speaking import AgentV1AgentStartedSpeaking
14+
from .types.agent_v1agent_thinking import AgentV1AgentThinking
15+
from .types.agent_v1conversation_text import AgentV1ConversationText
16+
from .types.agent_v1error import AgentV1Error
17+
from .types.agent_v1function_call_request import AgentV1FunctionCallRequest
18+
from .types.agent_v1inject_agent_message import AgentV1InjectAgentMessage
19+
from .types.agent_v1inject_user_message import AgentV1InjectUserMessage
20+
from .types.agent_v1injection_refused import AgentV1InjectionRefused
21+
from .types.agent_v1keep_alive import AgentV1KeepAlive
22+
from .types.agent_v1prompt_updated import AgentV1PromptUpdated
23+
from .types.agent_v1receive_function_call_response import AgentV1ReceiveFunctionCallResponse
24+
from .types.agent_v1send_function_call_response import AgentV1SendFunctionCallResponse
25+
from .types.agent_v1settings import AgentV1Settings
26+
from .types.agent_v1settings_applied import AgentV1SettingsApplied
27+
from .types.agent_v1speak_updated import AgentV1SpeakUpdated
28+
from .types.agent_v1update_prompt import AgentV1UpdatePrompt
29+
from .types.agent_v1update_speak import AgentV1UpdateSpeak
30+
from .types.agent_v1user_started_speaking import AgentV1UserStartedSpeaking
31+
from .types.agent_v1warning import AgentV1Warning
32+
from .types.agent_v1welcome import AgentV1Welcome
33+
34+
try:
35+
from websockets.legacy.client import WebSocketClientProtocol # type: ignore
36+
except ImportError:
37+
from websockets import WebSocketClientProtocol # type: ignore
38+
39+
_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
60+
V1SocketClientResponse = typing.Union[
61+
AgentV1ReceiveFunctionCallResponse,
62+
AgentV1PromptUpdated,
63+
AgentV1SpeakUpdated,
64+
AgentV1InjectionRefused,
65+
AgentV1Welcome,
66+
AgentV1SettingsApplied,
67+
AgentV1ConversationText,
68+
AgentV1UserStartedSpeaking,
69+
AgentV1AgentThinking,
70+
AgentV1FunctionCallRequest,
71+
AgentV1AgentStartedSpeaking,
72+
AgentV1AgentAudioDone,
73+
AgentV1Error,
74+
AgentV1Warning,
75+
bytes,
76+
]
77+
78+
79+
class AsyncV1SocketClient(EventEmitterMixin):
80+
def __init__(self, *, websocket: WebSocketClientProtocol):
81+
super().__init__()
82+
self._websocket = websocket
83+
84+
async def __aiter__(self):
85+
async for message in self._websocket:
86+
if isinstance(message, bytes):
87+
yield message
88+
else:
89+
try:
90+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
91+
except Exception:
92+
_logger.warning(
93+
"Skipping unknown WebSocket message; update your SDK version to support new message types."
94+
)
95+
continue
96+
97+
async def start_listening(self):
98+
"""
99+
Start listening for messages on the websocket connection.
100+
101+
Emits events in the following order:
102+
- EventType.OPEN when connection is established
103+
- EventType.MESSAGE for each message received
104+
- EventType.ERROR if an error occurs
105+
- EventType.CLOSE when connection is closed
106+
"""
107+
await self._emit_async(EventType.OPEN, None)
108+
try:
109+
async for raw_message in self._websocket:
110+
if isinstance(raw_message, bytes):
111+
parsed = raw_message
112+
else:
113+
json_data = json.loads(raw_message)
114+
try:
115+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
116+
except Exception:
117+
_logger.warning(
118+
"Skipping unknown WebSocket message; update your SDK version to support new message types."
119+
)
120+
continue
121+
await self._emit_async(EventType.MESSAGE, parsed)
122+
except Exception as exc:
123+
await self._emit_async(EventType.ERROR, exc)
124+
finally:
125+
await self._emit_async(EventType.CLOSE, None)
126+
127+
async def send_settings(self, message: AgentV1Settings) -> None:
128+
"""
129+
Send a message to the websocket connection.
130+
The message will be sent as a AgentV1Settings.
131+
"""
132+
await self._send_model(message)
133+
134+
async def send_update_speak(self, message: AgentV1UpdateSpeak) -> None:
135+
"""
136+
Send a message to the websocket connection.
137+
The message will be sent as a AgentV1UpdateSpeak.
138+
"""
139+
await self._send_model(message)
140+
141+
async def send_inject_user_message(self, message: AgentV1InjectUserMessage) -> None:
142+
"""
143+
Send a message to the websocket connection.
144+
The message will be sent as a AgentV1InjectUserMessage.
145+
"""
146+
await self._send_model(message)
147+
148+
async def send_inject_agent_message(self, message: AgentV1InjectAgentMessage) -> None:
149+
"""
150+
Send a message to the websocket connection.
151+
The message will be sent as a AgentV1InjectAgentMessage.
152+
"""
153+
await self._send_model(message)
154+
155+
async def send_function_call_response(self, message: AgentV1SendFunctionCallResponse) -> None:
156+
"""
157+
Send a message to the websocket connection.
158+
The message will be sent as a AgentV1SendFunctionCallResponse.
159+
"""
160+
await self._send_model(message)
161+
162+
async def send_keep_alive(self, message: typing.Optional[AgentV1KeepAlive] = None) -> None:
163+
"""
164+
Send a message to the websocket connection.
165+
The message will be sent as a AgentV1KeepAlive.
166+
"""
167+
await self._send_model(message or AgentV1KeepAlive(type="KeepAlive"))
168+
169+
async def send_update_prompt(self, message: AgentV1UpdatePrompt) -> None:
170+
"""
171+
Send a message to the websocket connection.
172+
The message will be sent as a AgentV1UpdatePrompt.
173+
"""
174+
await self._send_model(message)
175+
176+
async def send_media(self, message: bytes) -> None:
177+
"""
178+
Send a message to the websocket connection.
179+
The message will be sent as a bytes.
180+
"""
181+
await self._send(message)
182+
183+
async def recv(self) -> V1SocketClientResponse:
184+
"""
185+
Receive a message from the websocket connection.
186+
"""
187+
data = await self._websocket.recv()
188+
if isinstance(data, bytes):
189+
return data # type: ignore
190+
json_data = json.loads(data)
191+
try:
192+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
193+
except Exception:
194+
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
195+
return json_data # type: ignore
196+
197+
async def _send(self, data: typing.Any) -> None:
198+
"""
199+
Send a message to the websocket connection.
200+
"""
201+
if isinstance(data, dict):
202+
data = json.dumps(data)
203+
await self._websocket.send(data)
204+
205+
async def _send_model(self, data: typing.Any) -> None:
206+
"""
207+
Send a Pydantic model to the websocket connection.
208+
"""
209+
await self._send(_sanitize_numeric_types(data.dict()))
210+
211+
212+
class V1SocketClient(EventEmitterMixin):
213+
def __init__(self, *, websocket: websockets_sync_connection.Connection):
214+
super().__init__()
215+
self._websocket = websocket
216+
217+
def __iter__(self):
218+
for message in self._websocket:
219+
if isinstance(message, bytes):
220+
yield message
221+
else:
222+
try:
223+
yield construct_type(type_=V1SocketClientResponse, object_=json.loads(message)) # type: ignore
224+
except Exception:
225+
_logger.warning(
226+
"Skipping unknown WebSocket message; update your SDK version to support new message types."
227+
)
228+
continue
229+
230+
def start_listening(self):
231+
"""
232+
Start listening for messages on the websocket connection.
233+
234+
Emits events in the following order:
235+
- EventType.OPEN when connection is established
236+
- EventType.MESSAGE for each message received
237+
- EventType.ERROR if an error occurs
238+
- EventType.CLOSE when connection is closed
239+
"""
240+
self._emit(EventType.OPEN, None)
241+
try:
242+
for raw_message in self._websocket:
243+
if isinstance(raw_message, bytes):
244+
parsed = raw_message
245+
else:
246+
json_data = json.loads(raw_message)
247+
try:
248+
parsed = construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
249+
except Exception:
250+
_logger.warning(
251+
"Skipping unknown WebSocket message; update your SDK version to support new message types."
252+
)
253+
continue
254+
self._emit(EventType.MESSAGE, parsed)
255+
except Exception as exc:
256+
self._emit(EventType.ERROR, exc)
257+
finally:
258+
self._emit(EventType.CLOSE, None)
259+
260+
def send_settings(self, message: AgentV1Settings) -> None:
261+
"""
262+
Send a message to the websocket connection.
263+
The message will be sent as a AgentV1Settings.
264+
"""
265+
self._send_model(message)
266+
267+
def send_update_speak(self, message: AgentV1UpdateSpeak) -> None:
268+
"""
269+
Send a message to the websocket connection.
270+
The message will be sent as a AgentV1UpdateSpeak.
271+
"""
272+
self._send_model(message)
273+
274+
def send_inject_user_message(self, message: AgentV1InjectUserMessage) -> None:
275+
"""
276+
Send a message to the websocket connection.
277+
The message will be sent as a AgentV1InjectUserMessage.
278+
"""
279+
self._send_model(message)
280+
281+
def send_inject_agent_message(self, message: AgentV1InjectAgentMessage) -> None:
282+
"""
283+
Send a message to the websocket connection.
284+
The message will be sent as a AgentV1InjectAgentMessage.
285+
"""
286+
self._send_model(message)
287+
288+
def send_function_call_response(self, message: AgentV1SendFunctionCallResponse) -> None:
289+
"""
290+
Send a message to the websocket connection.
291+
The message will be sent as a AgentV1SendFunctionCallResponse.
292+
"""
293+
self._send_model(message)
294+
295+
def send_keep_alive(self, message: typing.Optional[AgentV1KeepAlive] = None) -> None:
296+
"""
297+
Send a message to the websocket connection.
298+
The message will be sent as a AgentV1KeepAlive.
299+
"""
300+
self._send_model(message or AgentV1KeepAlive(type="KeepAlive"))
301+
302+
def send_update_prompt(self, message: AgentV1UpdatePrompt) -> None:
303+
"""
304+
Send a message to the websocket connection.
305+
The message will be sent as a AgentV1UpdatePrompt.
306+
"""
307+
self._send_model(message)
308+
309+
def send_media(self, message: bytes) -> None:
310+
"""
311+
Send a message to the websocket connection.
312+
The message will be sent as a bytes.
313+
"""
314+
self._send(message)
315+
316+
def recv(self) -> V1SocketClientResponse:
317+
"""
318+
Receive a message from the websocket connection.
319+
"""
320+
data = self._websocket.recv()
321+
if isinstance(data, bytes):
322+
return data # type: ignore
323+
json_data = json.loads(data)
324+
try:
325+
return construct_type(type_=V1SocketClientResponse, object_=json_data) # type: ignore
326+
except Exception:
327+
_logger.warning("Skipping unknown WebSocket message; update your SDK version to support new message types.")
328+
return json_data # type: ignore
329+
330+
def _send(self, data: typing.Any) -> None:
331+
"""
332+
Send a message to the websocket connection.
333+
"""
334+
if isinstance(data, dict):
335+
data = json.dumps(data)
336+
self._websocket.send(data)
337+
338+
def _send_model(self, data: typing.Any) -> None:
339+
"""
340+
Send a Pydantic model to the websocket connection.
341+
"""
342+
self._send(_sanitize_numeric_types(data.dict()))

0 commit comments

Comments
 (0)