33import pytest
44from vision_agents .core .agents .conversation import InMemoryConversation
55from vision_agents .core .edge .types import Participant
6- from vision_agents .core .turn_detection import TurnEndedEvent , TurnStartedEvent
6+ from vision_agents .core .turn_detection import TurnEnded , TurnStarted
77from vision_agents .core .vad .silero import SileroVADSessionPool
88from vision_agents .plugins .smart_turn .smart_turn_detection import SmartTurnDetection
99
@@ -34,26 +34,21 @@ async def test_turn_detection_chunks(self, smart_turn, mia_audio_16khz):
3434 participant = Participant (user_id = "mia" , id = "mia" , original = {})
3535 conversation = InMemoryConversation (instructions = "be nice" , messages = [])
3636
37- event_order = []
38-
39- # Subscribe to events
40- @smart_turn .events .subscribe
41- async def on_start (event : TurnStartedEvent ):
42- logger .info (f"Smart turn turn started on { event .session_id } " )
43- event_order .append ("start" )
44-
45- @smart_turn .events .subscribe
46- async def on_stop (event : TurnEndedEvent ):
47- logger .info (f"Smart turn turn ended on { event .session_id } " )
48- event_order .append ("stop" )
49-
5037 for pcm in mia_audio_16khz .chunks (chunk_size = 304 ):
5138 await smart_turn .process_audio (pcm , participant , conversation )
5239
53- # Wait for background processing to complete
5440 await smart_turn .wait_for_processing_complete ()
5541
56- assert event_order == ["start" , "stop" ] or event_order == [
42+ items = await smart_turn .output .collect (timeout = 1.0 )
43+ kinds = [
44+ "start"
45+ if isinstance (item , TurnStarted )
46+ else "stop"
47+ if isinstance (item , TurnEnded )
48+ else None
49+ for item in items
50+ ]
51+ assert kinds == ["start" , "stop" ] or kinds == [
5752 "start" ,
5853 "stop" ,
5954 "start" ,
@@ -63,39 +58,51 @@ async def on_stop(event: TurnEndedEvent):
6358 async def test_turn_detection (self , smart_turn , mia_audio_16khz ):
6459 participant = Participant (user_id = "mia" , id = "mia" , original = {})
6560 conversation = InMemoryConversation (instructions = "be nice" , messages = [])
66- event_order = []
67-
68- # Subscribe to events
69- @smart_turn .events .subscribe
70- async def on_start (event : TurnStartedEvent ):
71- logger .info (f"Smart turn turn started on { event .session_id } " )
72- event_order .append ("start" )
73-
74- @smart_turn .events .subscribe
75- async def on_stop (event : TurnEndedEvent ):
76- logger .info (f"Smart turn turn ended on { event .session_id } " )
77- event_order .append ("stop" )
7861
7962 await smart_turn .process_audio (mia_audio_16khz , participant , conversation )
8063
81- # Wait for background processing to complete
8264 await smart_turn .wait_for_processing_complete ()
8365
84- # Verify that turn detection is working - we should get at least some turn events
66+ items = await smart_turn .output .collect (timeout = 1.0 )
67+ kinds = [
68+ "start"
69+ if isinstance (item , TurnStarted )
70+ else "stop"
71+ if isinstance (item , TurnEnded )
72+ else None
73+ for item in items
74+ ]
8575 # With continuous processing, we may get multiple start/stop cycles
86- assert event_order == ["start" , "stop" ] or event_order == [
76+ assert kinds == ["start" , "stop" ] or kinds == [
8777 "start" ,
8878 "stop" ,
8979 "start" ,
9080 "stop" ,
9181 ]
9282
83+ async def test_silence_does_not_start_segment (self , smart_turn , silence_1s_16khz ):
84+ participant = Participant (user_id = "mia" , id = "mia" , original = {})
85+ conversation = InMemoryConversation (instructions = "be nice" , messages = [])
86+
87+ await smart_turn .process_audio (silence_1s_16khz , participant , conversation )
88+ await smart_turn .wait_for_processing_complete ()
89+
90+ items = await smart_turn .output .collect (timeout = 0.5 )
91+ assert items == []
92+
93+ async def test_speech_starts_segment (self , smart_turn , mia_audio_16khz ):
94+ participant = Participant (user_id = "mia" , id = "mia" , original = {})
95+ conversation = InMemoryConversation (instructions = "be nice" , messages = [])
96+
97+ await smart_turn .process_audio (mia_audio_16khz , participant , conversation )
98+ await smart_turn .wait_for_processing_complete ()
99+
100+ items = await smart_turn .output .collect (timeout = 1.0 )
101+ assert any (isinstance (item , TurnStarted ) for item in items )
102+
93103 """
94104 TODO
95105 - Test that the 2nd turn detect includes the audio from the first turn
96106 - Test that turn detection is ran after 8s of audio
97107 - Test that turn detection is run after speech and 2s of silence
98- - Test that silence doens't start a new segmetn
99- - Test that speaking starts a new segment
100-
101108 """
0 commit comments