From 6f45b5df06e5b9050180505650cd1e12ceffaad7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 22 May 2026 18:49:47 +0000 Subject: [PATCH] fix(realtime): set guardrail turn_detection flag only after successful send MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the _guardrail_turn_detection_update_sent flag was set inline during message rewriting in client_ack_messages, before the modified session.update was forwarded to the backend. If _send_to_backend raised (e.g. backend WebSocket disconnect), the exception was caught and the loop continued, but the flag remained True — permanently disabling the guardrail create_response=False injection for the rest of the session. Neither the client_ack_messages path nor the _maybe_send_guardrail_turn_detection_update backup path would retry. Track the injection locally and only set the flag after _send_to_backend returns a truthy sent result, matching the pattern used by _maybe_send_guardrail_turn_detection_update. Co-authored-by: Yassin Kortam --- litellm/litellm_core_utils/realtime_streaming.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/litellm/litellm_core_utils/realtime_streaming.py b/litellm/litellm_core_utils/realtime_streaming.py index 85799c729ad..baba0bce3a0 100644 --- a/litellm/litellm_core_utils/realtime_streaming.py +++ b/litellm/litellm_core_utils/realtime_streaming.py @@ -848,6 +848,7 @@ class RealTimeStreaming: message = await self.websocket.receive_text() ## GUARDRAIL: intercept conversation.item.create for text-based injection. + guardrail_turn_detection_injected = False try: msg_obj = json.loads(message) msg_type = msg_obj.get("type") @@ -905,7 +906,7 @@ class RealTimeStreaming: existing_td["create_response"] = False session["turn_detection"] = existing_td message = json.dumps(msg_obj) - self._guardrail_turn_detection_update_sent = True + guardrail_turn_detection_injected = True verbose_logger.debug( "Injected turn_detection into first session.update for audio transcription guardrails" ) @@ -933,7 +934,14 @@ class RealTimeStreaming: self.store_input(message=message) ## FORWARD TO BACKEND - await self._send_to_backend(message) + # Only mark the guardrail turn_detection update as sent after the + # backend actually accepted the message. Setting the flag earlier + # would permanently disable the injection if ``_send_to_backend`` + # raised — neither this loop nor + # ``_maybe_send_guardrail_turn_detection_update`` would retry. + sent = await self._send_to_backend(message) + if guardrail_turn_detection_injected and sent: + self._guardrail_turn_detection_update_sent = True except Exception as e: verbose_logger.debug(f"Error in client ack messages: {e}")