Make end call tool can be cancelled
This commit is contained in:
@@ -7,11 +7,13 @@ from pipecat.frames.frames import (
|
||||
BotStartedSpeakingFrame,
|
||||
BotStoppedSpeakingFrame,
|
||||
InterruptionFrame,
|
||||
VADUserStartedSpeakingFrame,
|
||||
)
|
||||
from services.pipecat.call_lifecycle import (
|
||||
CallEndCoordinator,
|
||||
playback_marker_for,
|
||||
)
|
||||
from services.pipecat.processors import CallEndingUserMuteStrategy
|
||||
|
||||
|
||||
class CallEndCoordinatorTest(unittest.IsolatedAsyncioTestCase):
|
||||
@@ -66,6 +68,59 @@ class CallEndCoordinatorTest(unittest.IsolatedAsyncioTestCase):
|
||||
|
||||
self.assertEqual(self.reasons, ["tool_only"])
|
||||
|
||||
async def test_interruptible_end_keeps_input_open_and_can_be_cancelled(self):
|
||||
self.coordinator.begin_response()
|
||||
self.coordinator.begin("user_goodbye", interruptible=True)
|
||||
await self.coordinator.finish_after_current_speech(has_text=True)
|
||||
await self.coordinator.observe(BotStartedSpeakingFrame())
|
||||
|
||||
self.assertTrue(self.coordinator.ending)
|
||||
self.assertTrue(self.coordinator.accepts_input)
|
||||
self.assertTrue(self.coordinator.cancel_pending_end())
|
||||
self.assertFalse(self.coordinator.ending)
|
||||
self.assertTrue(self.coordinator.accepts_input)
|
||||
self.assertTrue(self.coordinator.speaking)
|
||||
|
||||
await self.coordinator.observe(BotStoppedSpeakingFrame())
|
||||
self.assertFalse(self.coordinator.speaking)
|
||||
self.assertEqual(self.reasons, [])
|
||||
|
||||
async def test_committed_end_rejects_cancellation(self):
|
||||
self.coordinator.begin("required_shutdown")
|
||||
|
||||
self.assertFalse(self.coordinator.accepts_input)
|
||||
self.assertFalse(self.coordinator.cancel_pending_end())
|
||||
self.assertTrue(self.coordinator.ending)
|
||||
|
||||
async def test_late_arm_and_finish_cannot_restore_cancelled_end(self):
|
||||
self.coordinator.begin("user_goodbye", interruptible=True)
|
||||
self.assertTrue(self.coordinator.cancel_pending_end())
|
||||
|
||||
self.coordinator.arm_after_speech()
|
||||
await self.coordinator.arm_after_tracked_speech()
|
||||
await self.coordinator.finish_after_current_speech(has_text=False)
|
||||
await self.coordinator.finish()
|
||||
await self.coordinator.observe(BotStartedSpeakingFrame())
|
||||
await self.coordinator.observe(BotStoppedSpeakingFrame())
|
||||
|
||||
self.assertEqual(self.reasons, [])
|
||||
|
||||
async def test_voice_turn_start_cancels_interruptible_end_before_muting(self):
|
||||
strategy = CallEndingUserMuteStrategy(
|
||||
lambda: not self.coordinator.accepts_input,
|
||||
is_user_interruption=lambda frame: isinstance(
|
||||
frame, VADUserStartedSpeakingFrame
|
||||
),
|
||||
cancel_pending_end=self.coordinator.cancel_pending_end,
|
||||
)
|
||||
self.coordinator.begin("user_goodbye", interruptible=True)
|
||||
|
||||
muted = await strategy.process_frame(VADUserStartedSpeakingFrame())
|
||||
|
||||
self.assertFalse(muted)
|
||||
self.assertFalse(self.coordinator.ending)
|
||||
self.assertEqual(self.reasons, [])
|
||||
|
||||
async def test_workflow_end_waits_for_every_queued_fixed_speech(self):
|
||||
first_completion = self.coordinator.track_speech()
|
||||
second_completion = self.coordinator.track_speech()
|
||||
@@ -134,6 +189,19 @@ class CallEndCoordinatorTest(unittest.IsolatedAsyncioTestCase):
|
||||
await marker.completion.mark_played()
|
||||
self.assertTrue(completion.done())
|
||||
|
||||
async def test_interrupted_fixed_end_does_not_finish_after_cancellation(self):
|
||||
completion = self.coordinator.track_speech()
|
||||
marker = playback_marker_for(completion)
|
||||
marker.completion.mark_queued()
|
||||
self.coordinator.begin("user_goodbye", interruptible=True)
|
||||
await self.coordinator.arm_after_tracked_speech()
|
||||
|
||||
self.assertTrue(self.coordinator.cancel_pending_end())
|
||||
await self.coordinator.observe(InterruptionFrame())
|
||||
|
||||
self.assertTrue(completion.done())
|
||||
self.assertEqual(self.reasons, [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user