async def _process_complete_patterns(self, text: str) -> Tuple[str, bool]:
        """Process all complete pattern pairs in the text.

        Searches for all complete pattern pairs in the text, calls the
        appropriate handlers, and optionally removes the matches.

        Args:
            text: The text to process.

        Returns:
            Tuple of (processed_text, was_modified) where:
            - processed_text is the text after processing patterns
            - was_modified indicates whether any changes were made
        """
        processed_text = text
        modified = False

        for pattern_id, pattern_info in self._patterns.items():
            # Escape special regex characters in the patterns
            start = re.escape(pattern_info["start"])
            end = re.escape(pattern_info["end"])
            remove_match = pattern_info["remove_match"]

            # Create regex to match from start pattern to end pattern
            # The .*? is non-greedy to handle nested patterns
            regex = f"{start}(.*?){end}"

            # Find all matches
            match_iter = re.finditer(regex, processed_text, re.DOTALL)
            matches = list(match_iter)  # Convert to list for safe iteration

            for match in matches:
                content = match.group(1)  # Content between patterns
                full_match = match.group(0)  # Full match including patterns

                # Create pattern match object
                pattern_match = PatternMatch(
                    pattern_id=pattern_id, full_match=full_match, content=content
                )

                # Call the appropriate handler if registered
                if pattern_id in self._handlers:
                    try:
                        await self._handlers[pattern_id](pattern_match)
                    except Exception as e:
                        logger.error(f"Error in pattern handler for {pattern_id}: {e}")

                # Remove the pattern from the text if configured
                if remove_match:
                    processed_text = processed_text.replace(full_match, "", 1)
                    modified = True

        return processed_text, modified
Process all complete pattern pairs in the text.

        Searches for all complete pattern pairs in the text, calls the
        appropriate handlers, and optionally removes the matches.

        Args:
            text: The text to process.

        Returns:
            Tuple of (processed_text, was_modified) where:
            - processed_text is the text after processing patterns
            - was_modified indicates whether any changes were made
        
src/pipecat/utils/text/pattern_pair_aggregator.py