fix: reconnect xai asr after finalize#2192
Conversation
|
Race between stop_connection and an in-flight _connect_recognition, with no test coverage test_stop_connection_cancels_pending_finalize_reconnect_task injects a fake task blocked on Event.wait(), so it does not cover the real path where reconnect has already reached _connect_recognition() / recognition.start(). If stop_connection() is called while _connect_recognition() is running: the task is cancelled; Suggestion: Add a test that mocks _connect_recognition so it is already awaiting before stop_connection is called, then verify that recognition is None, there is no second reconnect, and no leaked exceptions. |
Summary
xAI STT is a single-utterance protocol: the server closes the websocket after each
transcript.done. Previously, on a finalize-induced close,on_close()consumed the_close_expectedflag and returned without reconnecting, leavingrecognition = None. Every subsequent turn's audio then hit the base class, which only buffers frames when disconnected and never reconnects — so the second utterance in a session was silently dropped. This is the "first turn works, dead after that" symptom seen in thevoice_assistant_xai_grokgraph.Changes
extension.py— on the planned-close path, schedule_reconnect_after_finalize()to open a fresh connection (bypassing the failure-backoff path, since this is a planned cycle, not an error), with a fallback to the reconnect-manager backoff if the clean reconnect throws. Buffered frames flush fromon_open. A freshXAIASRRecognitionper utterance also avoids reusing a staledone_event/done_payload.self._finalize_reconnect_taskand cancelled onstop_connection()/on_deinit(), so an in-flight reconnect is cleanly aborted on shutdown.Tests
tests/test_reconnect.py— unit tests (mock-based): planned reconnect on finalize-close, fallback to backoff on failure, and cancellation of a pending reconnect onstop_connection.integration_tests/asr_guarder/test_same_session_finalize_reconnect.py— guarder test that runs two audio→finalize cycles in one session and requires a second non-empty final result.