From 64ed0aae1305e99f1d55d9583dbde194018692a2 Mon Sep 17 00:00:00 2001 From: Mark Backman Date: Mon, 13 Apr 2026 17:28:34 -0400 Subject: [PATCH 1/2] Reconnect Cartesia STT websocket when settings change at runtime Previously settings updates were ignored with a TODO comment. Now when model/language changes via STTUpdateSettingsFrame the service disconnects and reconnects with the new query parameters. Key changes: - Implement _update_settings to disconnect/reconnect on changes - Check `is not State.OPEN` in run_stt to catch CLOSING state - Send `done` command before closing for clean session shutdown - Capture websocket reference in _disconnect_websocket to prevent a concurrent _connect from having its new connection nulled by a stale finally block --- src/pipecat/services/cartesia/stt.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/pipecat/services/cartesia/stt.py b/src/pipecat/services/cartesia/stt.py index 85d43bcd3..e213652c1 100644 --- a/src/pipecat/services/cartesia/stt.py +++ b/src/pipecat/services/cartesia/stt.py @@ -285,8 +285,8 @@ class CartesiaSTTService(WebsocketSTTService): Yields: None - transcription results are handled via WebSocket responses. """ - # If the connection is closed, due to timeout, we need to reconnect when the user starts speaking again - if not self._websocket or self._websocket.state is State.CLOSED: + # If the connection is not open (closed or closing), reconnect + if not self._websocket or self._websocket.state is not State.OPEN: await self._connect() await self._websocket.send(audio) @@ -320,13 +320,12 @@ class CartesiaSTTService(WebsocketSTTService): """ changed = await super()._update_settings(delta) - # TODO: someday we could reconnect here to apply updated settings. - # Code might look something like the below: - # if changed: - # await self._disconnect() - # await self._connect() + if not changed: + return changed - self._warn_unhandled_updated_settings(changed) + if self._websocket: + await self._disconnect() + await self._connect() return changed @@ -351,14 +350,18 @@ class CartesiaSTTService(WebsocketSTTService): await self.push_error(error_msg=f"Unknown error occurred: {e}", exception=e) async def _disconnect_websocket(self): + ws = self._websocket try: - if self._websocket and self._websocket.state is State.OPEN: + if ws and ws.state is State.OPEN: logger.debug("Disconnecting from Cartesia STT") - await self._websocket.close() + await ws.send("done") + await ws.close() except Exception as e: await self.push_error(error_msg=f"Error closing websocket: {e}", exception=e) finally: - self._websocket = None + # Only clear if no concurrent _connect has already replaced it. + if self._websocket is ws: + self._websocket = None await self._call_event_handler("on_disconnected") def _get_websocket(self): From 36b15c92ef49a1460afae8bd1edf96d268a2a454 Mon Sep 17 00:00:00 2001 From: Mark Backman Date: Mon, 13 Apr 2026 17:29:39 -0400 Subject: [PATCH 2/2] Add changelog for #4282 --- changelog/4282.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/4282.added.md diff --git a/changelog/4282.added.md b/changelog/4282.added.md new file mode 100644 index 000000000..a3e31dd57 --- /dev/null +++ b/changelog/4282.added.md @@ -0,0 +1 @@ +- `CartesiaSTTService` now supports runtime settings updates (e.g. changing `language` or `model` via `STTUpdateSettingsFrame`). The service automatically reconnects with the new parameters. Previously, settings updates were silently ignored.