fix(workflow): track fixed speech at transport output

This commit is contained in:
Xin Wang
2026-08-06 10:21:36 +08:00
parent 5cb13a3cac
commit aaca128f82
6 changed files with 384 additions and 46 deletions
+64 -6
View File
@@ -3,8 +3,15 @@ from __future__ import annotations
import asyncio
import unittest
from pipecat.frames.frames import BotStartedSpeakingFrame, BotStoppedSpeakingFrame
from services.pipecat.call_lifecycle import CallEndCoordinator
from pipecat.frames.frames import (
BotStartedSpeakingFrame,
BotStoppedSpeakingFrame,
InterruptionFrame,
)
from services.pipecat.call_lifecycle import (
CallEndCoordinator,
playback_marker_for,
)
class CallEndCoordinatorTest(unittest.IsolatedAsyncioTestCase):
@@ -65,17 +72,68 @@ class CallEndCoordinatorTest(unittest.IsolatedAsyncioTestCase):
self.coordinator.begin("workflow_completed")
await self.coordinator.arm_after_tracked_speech()
await self.coordinator.observe(BotStartedSpeakingFrame())
await self.coordinator.observe(BotStoppedSpeakingFrame())
first_marker = playback_marker_for(first_completion)
second_marker = playback_marker_for(second_completion)
self.assertIsNotNone(first_marker)
self.assertIsNotNone(second_marker)
await first_marker.completion.mark_played()
self.assertTrue(first_completion.done())
self.assertFalse(second_completion.done())
self.assertEqual(self.reasons, [])
await self.coordinator.observe(BotStartedSpeakingFrame())
await self.coordinator.observe(BotStoppedSpeakingFrame())
await second_marker.completion.mark_played()
self.assertTrue(second_completion.done())
self.assertEqual(self.reasons, ["workflow_completed"])
async def test_previous_speech_stop_does_not_complete_fixed_speech(self):
await self.coordinator.observe(BotStartedSpeakingFrame())
completion = self.coordinator.track_speech()
marker = playback_marker_for(completion)
self.coordinator.begin("workflow_completed")
await self.coordinator.arm_after_tracked_speech()
await self.coordinator.observe(BotStoppedSpeakingFrame())
self.assertFalse(completion.done())
self.assertEqual(self.reasons, [])
await marker.completion.mark_played()
self.assertEqual(self.reasons, ["workflow_completed"])
async def test_delayed_previous_speech_boundary_cannot_claim_marker(self):
completion = self.coordinator.track_speech()
marker = playback_marker_for(completion)
self.coordinator.begin("workflow_completed")
await self.coordinator.arm_after_tracked_speech()
await self.coordinator.observe(BotStartedSpeakingFrame())
await self.coordinator.observe(BotStoppedSpeakingFrame())
self.assertFalse(completion.done())
self.assertEqual(self.reasons, [])
await marker.completion.mark_played()
self.assertEqual(self.reasons, ["workflow_completed"])
async def test_interruption_completes_marker_already_in_output_queue(self):
completion = self.coordinator.track_speech()
marker = playback_marker_for(completion)
marker.completion.mark_queued()
await self.coordinator.observe(InterruptionFrame())
self.assertTrue(completion.done())
async def test_interruption_does_not_complete_marker_not_yet_queued(self):
completion = self.coordinator.track_speech()
marker = playback_marker_for(completion)
await self.coordinator.observe(InterruptionFrame())
self.assertFalse(completion.done())
marker.completion.mark_queued()
await marker.completion.mark_played()
self.assertTrue(completion.done())
if __name__ == "__main__":
unittest.main()