Skip to content
Closed
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ def __init__(self, realtime_model: RealtimeModel) -> None:

self._client = AsyncPhonic(
api_key=self._opts.api_key,
reconnect_conversation_on_abnormal_disconnect=True,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Voice sessions can go silent with no error when the provider connection drops for good

Automatic reconnection is turned on (reconnect_conversation_on_abnormal_disconnect=True at livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py:389) without handling the case where reconnecting ultimately fails, so a dropped call ends quietly instead of reporting a failure.
Impact: When the connection cannot be restored, the agent simply stops talking and listening and nothing is notified, so the call hangs instead of erroring out or being recovered.

Silent break in the reconnectable socket iterator swallows abnormal-close errors

With the flag enabled, client.conversations.connect() yields a ReconnectableAsyncConversationsSocketClient instead of AsyncConversationsSocketClient (phonic SDK phonic/conversations/client.py:1258-1286). Its __aiter__ catches ConnectionClosed and only re-raises when the close code is neither normal (1000) nor "reconnectable" (1006/1012/1001-restarting); for a 1006 abnormal close where reconnect is impossible (no conversation_id yet) or exhausted (10 attempts), it just breaks without raising (phonic/conversations/reconnectable_socket_client.py:193-206, 155-191).

The plugin's _recv_task (livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py:956-995) therefore returns normally. In _main_task (...:926-938) recv_task is done with no exception, so no _emit_error(..., recoverable=True) is raised; the code cancels the peers, closes the socket and the current generation, and the session ends without surfacing any error to AgentSession.

Before this change, the plain socket iterator propagated ConnectionClosedError on abnormal closes, so the plugin logged and emitted a recoverable error.

Prompt for agents
Enabling reconnect_conversation_on_abnormal_disconnect makes phonic's connect() return a ReconnectableAsyncConversationsSocketClient whose __aiter__ swallows ConnectionClosed for abnormal/reconnectable close codes (1006/1012/1001-restarting) once reconnection is impossible or exhausted: it breaks out of the loop instead of raising. As a result RealtimeSession._recv_task in livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py finishes normally, _main_task sees no exception, and the session tears down without emitting any error, leaving the agent silently dead. Consider detecting an unexpected end of the receive loop (e.g. loop exited while _session_should_close is not set) and emitting a recoverable error / raising so the agent session can react.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Tool results and audio sent while the connection is being restored are dropped without notice

Messages such as tool results are handed to the connection while it is being re-established (via the client created at livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py:389), where they are quietly discarded, so the assistant can wait forever for a result that was never delivered.
Impact: After a brief network hiccup the conversation can stall mid tool call, with the assistant never responding.

Reconnectable client no-ops sends while reconnecting, but the plugin already marked the tool call as answered

All send_* methods of ReconnectableAsyncConversationsSocketClient are guarded by _is_send_safe() and silently return when _reconnecting is True (phonic/conversations/reconnectable_socket_client.py:106-107, 221-263). The reconnect window includes an exponential backoff sleep of up to 5s per attempt (...:178-191).

In update_chat_ctx the plugin removes the call id from self._pending_tool_call_ids before calling send_tool_call_output (livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py:475-488), so a dropped send is never retried and no error is raised; Phonic resumes the conversation still waiting for that tool output. The same silent drop applies to send_say, send_generate_reply, send_reset and buffered audio chunks in _send_task.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

)

self._socket: AsyncConversationsSocketClient | None = None
Expand Down