Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ src/deepgram/client.py
# - construct_type keyword args fix (generator uses positional, function requires keyword-only)
# - except Exception broad catch (supports custom transports, generator narrows to WebSocketException)
# - _sanitize_numeric_types in agent socket client (float→int for API)
# - optional message param on control send_ methods (send_keep_alive, send_close_stream, etc.)
# so users don't need to instantiate the type themselves for no-payload control messages
# [temporarily frozen — generator bugs in construct_type call convention and exception handling]
src/deepgram/agent/v1/socket_client.py
src/deepgram/listen/v1/socket_client.py
Expand Down
8 changes: 4 additions & 4 deletions src/deepgram/agent/v1/socket_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ async def send_function_call_response(self, message: AgentV1SendFunctionCallResp
"""
await self._send_model(message)

async def send_keep_alive(self, message: AgentV1KeepAlive) -> None:
async def send_keep_alive(self, message: typing.Optional[AgentV1KeepAlive] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a AgentV1KeepAlive.
"""
await self._send_model(message)
await self._send_model(message or AgentV1KeepAlive())
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AgentV1KeepAlive requires a type field (no default in the model), so AgentV1KeepAlive() will raise a validation error. This means send_keep_alive() is still not callable with no args. Construct the default message with the required type (e.g., the "KeepAlive" literal) when message is omitted.

Suggested change
await self._send_model(message or AgentV1KeepAlive())
if message is None:
message = AgentV1KeepAlive(type="KeepAlive")
await self._send_model(message)

Copilot uses AI. Check for mistakes.

async def send_update_prompt(self, message: AgentV1UpdatePrompt) -> None:
"""
Expand Down Expand Up @@ -292,12 +292,12 @@ def send_function_call_response(self, message: AgentV1SendFunctionCallResponse)
"""
self._send_model(message)

def send_keep_alive(self, message: AgentV1KeepAlive) -> None:
def send_keep_alive(self, message: typing.Optional[AgentV1KeepAlive] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a AgentV1KeepAlive.
"""
self._send_model(message)
self._send_model(message or AgentV1KeepAlive())
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue for the sync client: AgentV1KeepAlive() is missing the required type field, so this default will raise at runtime. Please set the type field when constructing the default keep-alive message.

Suggested change
self._send_model(message or AgentV1KeepAlive())
self._send_model(message or AgentV1KeepAlive(type="keep_alive"))

Copilot uses AI. Check for mistakes.

def send_update_prompt(self, message: AgentV1UpdatePrompt) -> None:
"""
Expand Down
24 changes: 12 additions & 12 deletions src/deepgram/listen/v1/socket_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,26 +81,26 @@ async def send_media(self, message: bytes) -> None:
"""
await self._send(message)

async def send_finalize(self, message: ListenV1Finalize) -> None:
async def send_finalize(self, message: typing.Optional[ListenV1Finalize] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV1Finalize.
"""
await self._send_model(message)
await self._send_model(message or ListenV1Finalize(type="Finalize"))

async def send_close_stream(self, message: ListenV1CloseStream) -> None:
async def send_close_stream(self, message: typing.Optional[ListenV1CloseStream] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV1CloseStream.
"""
await self._send_model(message)
await self._send_model(message or ListenV1CloseStream(type="CloseStream"))

async def send_keep_alive(self, message: ListenV1KeepAlive) -> None:
async def send_keep_alive(self, message: typing.Optional[ListenV1KeepAlive] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV1KeepAlive.
"""
await self._send_model(message)
await self._send_model(message or ListenV1KeepAlive(type="KeepAlive"))
Comment on lines +84 to +103
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR restores optional control-message params, but there are no tests asserting that these send_*() control methods can be called with no arguments (and that they send the expected default payload). Since the repo already has coverage for listen.v1.socket_client behavior in tests/custom/test_transport.py, please add a small unit test that instantiates the socket client with a mock transport and verifies send_keep_alive()/send_close_stream()/send_finalize() work without args.

Copilot uses AI. Check for mistakes.

async def recv(self) -> V1SocketClientResponse:
"""
Expand Down Expand Up @@ -186,26 +186,26 @@ def send_media(self, message: bytes) -> None:
"""
self._send(message)

def send_finalize(self, message: ListenV1Finalize) -> None:
def send_finalize(self, message: typing.Optional[ListenV1Finalize] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV1Finalize.
"""
self._send_model(message)
self._send_model(message or ListenV1Finalize(type="Finalize"))

def send_close_stream(self, message: ListenV1CloseStream) -> None:
def send_close_stream(self, message: typing.Optional[ListenV1CloseStream] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV1CloseStream.
"""
self._send_model(message)
self._send_model(message or ListenV1CloseStream(type="CloseStream"))

def send_keep_alive(self, message: ListenV1KeepAlive) -> None:
def send_keep_alive(self, message: typing.Optional[ListenV1KeepAlive] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV1KeepAlive.
"""
self._send_model(message)
self._send_model(message or ListenV1KeepAlive(type="KeepAlive"))

def recv(self) -> V1SocketClientResponse:
"""
Expand Down
8 changes: 4 additions & 4 deletions src/deepgram/listen/v2/socket_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ async def send_media(self, message: bytes) -> None:
"""
await self._send(message)

async def send_close_stream(self, message: ListenV2CloseStream) -> None:
async def send_close_stream(self, message: typing.Optional[ListenV2CloseStream] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV2CloseStream.
"""
await self._send_model(message)
await self._send_model(message or ListenV2CloseStream(type="CloseStream"))

async def recv(self) -> V2SocketClientResponse:
"""
Expand Down Expand Up @@ -169,12 +169,12 @@ def send_media(self, message: bytes) -> None:
"""
self._send(message)

def send_close_stream(self, message: ListenV2CloseStream) -> None:
def send_close_stream(self, message: typing.Optional[ListenV2CloseStream] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a ListenV2CloseStream.
"""
self._send_model(message)
self._send_model(message or ListenV2CloseStream(type="CloseStream"))

def recv(self) -> V2SocketClientResponse:
"""
Expand Down
24 changes: 12 additions & 12 deletions src/deepgram/speak/v1/socket_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,26 @@ async def send_text(self, message: SpeakV1Text) -> None:
"""
await self._send_model(message)

async def send_flush(self, message: SpeakV1Flush) -> None:
async def send_flush(self, message: typing.Optional[SpeakV1Flush] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a SpeakV1Flush.
"""
await self._send_model(message)
await self._send_model(message or SpeakV1Flush(type="Flush"))

async def send_clear(self, message: SpeakV1Clear) -> None:
async def send_clear(self, message: typing.Optional[SpeakV1Clear] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a SpeakV1Clear.
"""
await self._send_model(message)
await self._send_model(message or SpeakV1Clear(type="Clear"))

async def send_close(self, message: SpeakV1Close) -> None:
async def send_close(self, message: typing.Optional[SpeakV1Close] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a SpeakV1Close.
"""
await self._send_model(message)
await self._send_model(message or SpeakV1Close(type="Close"))

async def recv(self) -> V1SocketClientResponse:
"""
Expand Down Expand Up @@ -187,26 +187,26 @@ def send_text(self, message: SpeakV1Text) -> None:
"""
self._send_model(message)

def send_flush(self, message: SpeakV1Flush) -> None:
def send_flush(self, message: typing.Optional[SpeakV1Flush] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a SpeakV1Flush.
"""
self._send_model(message)
self._send_model(message or SpeakV1Flush(type="Flush"))

def send_clear(self, message: SpeakV1Clear) -> None:
def send_clear(self, message: typing.Optional[SpeakV1Clear] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a SpeakV1Clear.
"""
self._send_model(message)
self._send_model(message or SpeakV1Clear(type="Clear"))

def send_close(self, message: SpeakV1Close) -> None:
def send_close(self, message: typing.Optional[SpeakV1Close] = None) -> None:
"""
Send a message to the websocket connection.
The message will be sent as a SpeakV1Close.
"""
self._send_model(message)
self._send_model(message or SpeakV1Close(type="Close"))

def recv(self) -> V1SocketClientResponse:
"""
Expand Down
Loading