@@ -2467,7 +2467,8 @@ def _make_runner():
24672467 runner .adapters = {}
24682468 return runner
24692469
2470- def _call_should_reply (self , runner , voice_mode , msg_type , response = "Hello" , agent_msgs = None ):
2470+ def _call_should_reply (self , runner , voice_mode , msg_type , response = "Hello" ,
2471+ agent_msgs = None , already_sent = False ):
24712472 from gateway .platforms .base import MessageType , MessageEvent , SessionSource
24722473 from gateway .config import Platform
24732474 runner ._voice_mode ["ch1" ] = voice_mode
@@ -2476,28 +2477,32 @@ def _call_should_reply(self, runner, voice_mode, msg_type, response="Hello", age
24762477 user_id = "1" , user_name = "test" , chat_type = "channel" ,
24772478 )
24782479 event = MessageEvent (source = source , text = "test" , message_type = msg_type )
2479- return runner ._should_send_voice_reply (event , response , agent_msgs or [])
2480+ return runner ._should_send_voice_reply (
2481+ event , response , agent_msgs or [], already_sent = already_sent ,
2482+ )
2483+
2484+ # -- Streaming OFF (existing behavior, must not change) --
24802485
24812486 def test_voice_input_runner_skips (self ):
2482- """Voice input: runner skips — base adapter handles via play_tts ."""
2487+ """Streaming OFF + voice input: runner skips — base adapter handles."""
24832488 from gateway .platforms .base import MessageType
24842489 runner = self ._make_runner ()
2485- assert self ._call_should_reply (runner , "all" , MessageType .VOICE ) is False
2490+ assert self ._call_should_reply (runner , "all" , MessageType .VOICE , already_sent = False ) is False
24862491
24872492 def test_text_input_voice_all_runner_fires (self ):
2488- """Text input + voice_mode=all: runner generates TTS."""
2493+ """Streaming OFF + text input + voice_mode=all: runner generates TTS."""
24892494 from gateway .platforms .base import MessageType
24902495 runner = self ._make_runner ()
2491- assert self ._call_should_reply (runner , "all" , MessageType .TEXT ) is True
2496+ assert self ._call_should_reply (runner , "all" , MessageType .TEXT , already_sent = False ) is True
24922497
24932498 def test_text_input_voice_off_no_tts (self ):
2494- """Text input + voice_mode=off: no TTS."""
2499+ """Streaming OFF + text input + voice_mode=off: no TTS."""
24952500 from gateway .platforms .base import MessageType
24962501 runner = self ._make_runner ()
24972502 assert self ._call_should_reply (runner , "off" , MessageType .TEXT ) is False
24982503
24992504 def test_text_input_voice_only_no_tts (self ):
2500- """Text input + voice_mode=voice_only: no TTS for text."""
2505+ """Streaming OFF + text input + voice_mode=voice_only: no TTS for text."""
25012506 from gateway .platforms .base import MessageType
25022507 runner = self ._make_runner ()
25032508 assert self ._call_should_reply (runner , "voice_only" , MessageType .TEXT ) is False
@@ -2523,6 +2528,43 @@ def test_agent_tts_tool_dedup(self):
25232528 ]}]
25242529 assert self ._call_should_reply (runner , "all" , MessageType .TEXT , agent_msgs = agent_msgs ) is False
25252530
2531+ # -- Streaming ON (already_sent=True) --
2532+
2533+ def test_streaming_on_voice_input_runner_fires (self ):
2534+ """Streaming ON + voice input: runner handles TTS (base adapter has no text)."""
2535+ from gateway .platforms .base import MessageType
2536+ runner = self ._make_runner ()
2537+ assert self ._call_should_reply (runner , "all" , MessageType .VOICE , already_sent = True ) is True
2538+
2539+ def test_streaming_on_text_input_runner_fires (self ):
2540+ """Streaming ON + text input: runner handles TTS (same as before)."""
2541+ from gateway .platforms .base import MessageType
2542+ runner = self ._make_runner ()
2543+ assert self ._call_should_reply (runner , "all" , MessageType .TEXT , already_sent = True ) is True
2544+
2545+ def test_streaming_on_voice_off_no_tts (self ):
2546+ """Streaming ON + voice_mode=off: no TTS regardless of streaming."""
2547+ from gateway .platforms .base import MessageType
2548+ runner = self ._make_runner ()
2549+ assert self ._call_should_reply (runner , "off" , MessageType .VOICE , already_sent = True ) is False
2550+
2551+ def test_streaming_on_empty_response_no_tts (self ):
2552+ """Streaming ON + empty response: no TTS."""
2553+ from gateway .platforms .base import MessageType
2554+ runner = self ._make_runner ()
2555+ assert self ._call_should_reply (runner , "all" , MessageType .VOICE , response = "" , already_sent = True ) is False
2556+
2557+ def test_streaming_on_agent_tts_dedup (self ):
2558+ """Streaming ON + agent called TTS: runner skips (dedup still works)."""
2559+ from gateway .platforms .base import MessageType
2560+ runner = self ._make_runner ()
2561+ agent_msgs = [{"role" : "assistant" , "tool_calls" : [
2562+ {"id" : "1" , "type" : "function" , "function" : {"name" : "text_to_speech" , "arguments" : "{}" }}
2563+ ]}]
2564+ assert self ._call_should_reply (
2565+ runner , "all" , MessageType .VOICE , agent_msgs = agent_msgs , already_sent = True ,
2566+ ) is False
2567+
25262568
25272569class TestUDPKeepalive :
25282570 """UDP keepalive prevents Discord from dropping the voice session."""
0 commit comments