From d5105a78e6994c94f74af4ee488c8d58713b90cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleix=20Conchillo=20Flaqu=C3=A9?= Date: Fri, 6 Feb 2026 09:45:20 -0800 Subject: [PATCH] STTMuteFilter should call frame.complete() when InterruptionFrame is blocked --- .../processors/filters/stt_mute_filter.py | 6 ++++ tests/test_stt_mute_filter.py | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/pipecat/processors/filters/stt_mute_filter.py b/src/pipecat/processors/filters/stt_mute_filter.py index 9f522a20d..f5d008e28 100644 --- a/src/pipecat/processors/filters/stt_mute_filter.py +++ b/src/pipecat/processors/filters/stt_mute_filter.py @@ -234,6 +234,12 @@ class STTMuteFilter(FrameProcessor): await self.push_frame(frame, direction) else: logger.trace(f"{frame.__class__.__name__} suppressed - STT currently muted") + + # When muted, the InterruptionFrame won't propagate further + # and will never reach the pipeline sink. Complete it here so + # push_interruption_task_frame_and_wait() doesn't hang. + if isinstance(frame, InterruptionFrame): + frame.complete() else: # Pass all other frames through await self.push_frame(frame, direction) diff --git a/tests/test_stt_mute_filter.py b/tests/test_stt_mute_filter.py index 5682aaf22..adf4611df 100644 --- a/tests/test_stt_mute_filter.py +++ b/tests/test_stt_mute_filter.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD 2-Clause License # +import asyncio import unittest from pipecat.frames.frames import ( @@ -14,6 +15,7 @@ from pipecat.frames.frames import ( FunctionCallsStartedFrame, InputAudioRawFrame, InterimTranscriptionFrame, + InterruptionFrame, TranscriptionFrame, UserStartedSpeakingFrame, UserStoppedSpeakingFrame, @@ -327,6 +329,33 @@ class TestSTTMuteFilter(unittest.IsolatedAsyncioTestCase): expected_down_frames=expected_returned_frames, ) + async def test_interruption_frame_completed_when_muted(self): + """Test that InterruptionFrame.complete() is called when the frame is + suppressed due to muting, so push_interruption_task_frame_and_wait() + doesn't hang.""" + filter = STTMuteFilter(config=STTMuteConfig(strategies={STTMuteStrategy.ALWAYS})) + + event = asyncio.Event() + + frames_to_send = [ + BotStartedSpeakingFrame(), + InterruptionFrame(event=event), + BotStoppedSpeakingFrame(), + ] + + expected_returned_frames = [ + BotStartedSpeakingFrame, + BotStoppedSpeakingFrame, + ] + + await run_test( + filter, + frames_to_send=frames_to_send, + expected_down_frames=expected_returned_frames, + ) + + self.assertTrue(event.is_set(), "InterruptionFrame.complete() should be called when muted") + if __name__ == "__main__": unittest.main()