diff --git a/examples/foundational/35-pattern-pair-voice-switching.py b/examples/foundational/35-pattern-pair-voice-switching.py
index 7ed9eb268..013c3eecd 100644
--- a/examples/foundational/35-pattern-pair-voice-switching.py
+++ b/examples/foundational/35-pattern-pair-voice-switching.py
@@ -110,6 +110,7 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
pattern_id="voice_tag",
start_pattern="",
end_pattern="",
+ type="voice",
remove_match=True,
)
diff --git a/src/pipecat/extensions/ivr/ivr_navigator.py b/src/pipecat/extensions/ivr/ivr_navigator.py
index 05748d94f..c4e31e12a 100644
--- a/src/pipecat/extensions/ivr/ivr_navigator.py
+++ b/src/pipecat/extensions/ivr/ivr_navigator.py
@@ -114,15 +114,19 @@ class IVRProcessor(FrameProcessor):
def _setup_xml_patterns(self):
"""Set up XML pattern detection and handlers."""
# Register DTMF pattern
- self._aggregator.add_pattern_pair("dtmf", "", "", remove_match=True)
+ self._aggregator.add_pattern_pair(
+ "dtmf", "", "", type="dtmf", remove_match=True
+ )
self._aggregator.on_pattern_match("dtmf", self._handle_dtmf_action)
# Register mode pattern
- self._aggregator.add_pattern_pair("mode", "", "", remove_match=True)
+ self._aggregator.add_pattern_pair(
+ "mode", "", "", type="mode", remove_match=True
+ )
self._aggregator.on_pattern_match("mode", self._handle_mode_action)
# Register IVR pattern
- self._aggregator.add_pattern_pair("ivr", "", "", remove_match=True)
+ self._aggregator.add_pattern_pair("ivr", "", "", type="ivr", remove_match=True)
self._aggregator.on_pattern_match("ivr", self._handle_ivr_action)
async def process_frame(self, frame: Frame, direction: FrameDirection):
diff --git a/tests/test_pattern_pair_aggregator.py b/tests/test_pattern_pair_aggregator.py
index 8426dcf39..d0e13ffc6 100644
--- a/tests/test_pattern_pair_aggregator.py
+++ b/tests/test_pattern_pair_aggregator.py
@@ -20,8 +20,16 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase):
pattern_id="test_pattern",
start_pattern="",
end_pattern="",
+ type="test",
remove_match=True,
)
+ self.aggregator.add_pattern_pair(
+ pattern_id="code_pattern",
+ start_pattern="",
+ end_pattern="",
+ type="code",
+ remove_match=False,
+ )
# Register the mock handler
self.aggregator.on_pattern_match("test_pattern", self.test_handler)
@@ -30,7 +38,8 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase):
# First part doesn't complete the pattern
result = await self.aggregator.aggregate("Hello pattern")
self.assertIsNone(result)
- self.assertEqual(self.aggregator.text, "Hello pattern")
+ self.assertEqual(self.aggregator.text.text, "Hello pattern")
+ self.assertEqual(self.aggregator.text.type, "test")
# Second part completes the pattern and includes an exclamation point
result = await self.aggregator.aggregate(" content!")
@@ -45,14 +54,15 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase):
# The exclamation point should be treated as a sentence boundary,
# so the result should include just text up to and including "!"
- self.assertEqual(result, "Hello !")
+ self.assertEqual(result.text, "Hello !")
+ self.assertEqual(result.type, "sentence")
# Next sentence should be processed separately
result = await self.aggregator.aggregate(" This is another sentence.")
- self.assertEqual(result, " This is another sentence.")
+ self.assertEqual(result.text, " This is another sentence.")
# Buffer should be empty after returning a complete sentence
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(self.aggregator.text.text, "")
async def test_incomplete_pattern(self):
# Add text with incomplete pattern
@@ -65,11 +75,12 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase):
self.test_handler.assert_not_called()
# Buffer should contain the incomplete text
- self.assertEqual(self.aggregator.text, "Hello pattern content")
+ self.assertEqual(self.aggregator.text.text, "Hello pattern content")
+ self.assertEqual(self.aggregator.text.type, "test")
# Reset and confirm buffer is cleared
await self.aggregator.reset()
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(self.aggregator.text.text, "")
async def test_multiple_patterns(self):
# Set up multiple patterns and handlers
@@ -109,7 +120,7 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase):
self.assertEqual(result, "Hello I am very excited to meet you!")
# Buffer should be empty
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(self.aggregator.text.text, "")
async def test_handle_interruption(self):
# Start with incomplete pattern
@@ -120,7 +131,7 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase):
await self.aggregator.handle_interruption()
# Buffer should be cleared
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(self.aggregator.text.text, "")
# Handler should not have been called
self.test_handler.assert_not_called()
@@ -144,4 +155,4 @@ class TestPatternPairAggregator(unittest.IsolatedAsyncioTestCase):
self.assertEqual(result, "Hello Final sentence.")
# Buffer should be empty
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(self.aggregator.text.text, "")
diff --git a/tests/test_skip_tags_aggregator.py b/tests/test_skip_tags_aggregator.py
index f6cbb7b93..702b991ce 100644
--- a/tests/test_skip_tags_aggregator.py
+++ b/tests/test_skip_tags_aggregator.py
@@ -18,16 +18,18 @@ class TestSkipTagsAggregator(unittest.IsolatedAsyncioTestCase):
# No tags involved, aggregate at end of sentence.
result = await self.aggregator.aggregate("Hello Pipecat!")
- self.assertEqual(result, "Hello Pipecat!")
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(result.text, "Hello Pipecat!")
+ self.assertEqual(result.type, "sentence")
+ self.assertEqual(self.aggregator.text.text, "")
async def test_basic_tags(self):
await self.aggregator.reset()
# Tags involved, avoid aggregation during tags.
result = await self.aggregator.aggregate("My email is foo@pipecat.ai.")
- self.assertEqual(result, "My email is foo@pipecat.ai.")
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(result.text, "My email is foo@pipecat.ai.")
+ self.assertEqual(result.type, "sentence")
+ self.assertEqual(self.aggregator.text.text, "")
async def test_streaming_tags(self):
await self.aggregator.reset()
@@ -35,20 +37,22 @@ class TestSkipTagsAggregator(unittest.IsolatedAsyncioTestCase):
# Tags involved, stream small chunk of texts.
result = await self.aggregator.aggregate("My email is foo.")
self.assertIsNone(result)
- self.assertEqual(self.aggregator.text, "My email is foo.")
+ self.assertEqual(self.aggregator.text.text, "My email is foo.")
result = await self.aggregator.aggregate("bar@pipecat.")
self.assertIsNone(result)
- self.assertEqual(self.aggregator.text, "My email is foo.bar@pipecat.")
+ self.assertEqual(self.aggregator.text.text, "My email is foo.bar@pipecat.")
result = await self.aggregator.aggregate("aifoo.bar@pipecat.aifoo.bar@pipecat.ai.")
- self.assertEqual(result, "My email is foo.bar@pipecat.ai.")
- self.assertEqual(self.aggregator.text, "")
+ self.assertEqual(result.text, "My email is foo.bar@pipecat.ai.")
+ self.assertEqual(self.aggregator.text.text, "")
+ self.assertEqual(self.aggregator.text.type, "sentence")