Rename UserTurnCompletedFrame to UserTurnInferenceCompletedFrame
The old name overlapped semantically with `UserStoppedSpeakingFrame`: both could be read as "the user's turn is done." They're at different layers — `UserStoppedSpeakingFrame` is the acoustic stop signal, while this frame is the post-judgment "inference about the turn is now complete (turn is semantically final)" signal emitted by the LLM mixin (on ✓), an end-of-turn classifier, or a custom producer. The new name pairs naturally with the existing `on_user_turn_inference_triggered` event vocabulary and removes the ambiguity with `UserStoppedSpeakingFrame`.
This commit is contained in:
@@ -1005,7 +1005,7 @@ class UserSpeakingFrame(SystemFrame):
|
||||
|
||||
|
||||
@dataclass
|
||||
class UserTurnCompletedFrame(SystemFrame):
|
||||
class UserTurnInferenceCompletedFrame(SystemFrame):
|
||||
"""Frame indicating that the user turn is semantically complete.
|
||||
|
||||
Emitted by any component that can judge conversational turn
|
||||
|
||||
@@ -4,21 +4,21 @@
|
||||
# SPDX-License-Identifier: BSD 2-Clause License
|
||||
#
|
||||
|
||||
"""User turn stop strategy that finalizes on ``UserTurnCompletedFrame``."""
|
||||
"""User turn stop strategy that finalizes on ``UserTurnInferenceCompletedFrame``."""
|
||||
|
||||
from pipecat.frames.frames import Frame, UserTurnCompletedFrame
|
||||
from pipecat.frames.frames import Frame, UserTurnInferenceCompletedFrame
|
||||
from pipecat.turns.types import ProcessFrameResult
|
||||
from pipecat.turns.user_stop.base_user_turn_stop_strategy import BaseUserTurnStopStrategy
|
||||
|
||||
|
||||
class ExternalUserTurnCompletionStopStrategy(BaseUserTurnStopStrategy):
|
||||
"""Finalize the user turn whenever a ``UserTurnCompletedFrame`` arrives.
|
||||
"""Finalize the user turn whenever a ``UserTurnInferenceCompletedFrame`` arrives.
|
||||
|
||||
Generic stop strategy for pipelines where some external component
|
||||
(LLM with completion markers, STT with built-in turn detection, a
|
||||
dedicated end-of-turn classifier, custom user code, etc.) judges
|
||||
when a turn is semantically complete and emits
|
||||
:class:`~pipecat.frames.frames.UserTurnCompletedFrame`.
|
||||
:class:`~pipecat.frames.frames.UserTurnInferenceCompletedFrame`.
|
||||
|
||||
Pair this with one or more ``deferred(...)``-wrapped detector
|
||||
strategies that drive ``on_user_turn_inference_triggered`` but
|
||||
@@ -34,14 +34,14 @@ class ExternalUserTurnCompletionStopStrategy(BaseUserTurnStopStrategy):
|
||||
instead, which additionally pushes the ``LLMUpdateSettingsFrame``
|
||||
that enables the marker protocol on the LLM.
|
||||
|
||||
If the producer never emits ``UserTurnCompletedFrame``, the
|
||||
If the producer never emits ``UserTurnInferenceCompletedFrame``, the
|
||||
controller's ``user_turn_stop_timeout`` watchdog finalizes the
|
||||
turn after no activity. Tune that timeout if your producer can
|
||||
take longer than the default to respond.
|
||||
"""
|
||||
|
||||
async def process_frame(self, frame: Frame) -> ProcessFrameResult:
|
||||
"""Fire ``on_user_turn_stopped`` whenever ``UserTurnCompletedFrame`` is seen."""
|
||||
if isinstance(frame, UserTurnCompletedFrame):
|
||||
"""Fire ``on_user_turn_stopped`` whenever ``UserTurnInferenceCompletedFrame`` is seen."""
|
||||
if isinstance(frame, UserTurnInferenceCompletedFrame):
|
||||
await self.trigger_user_turn_finalized()
|
||||
return ProcessFrameResult.CONTINUE
|
||||
|
||||
@@ -29,7 +29,7 @@ class LLMTurnCompletionUserTurnStopStrategy(ExternalUserTurnCompletionStopStrate
|
||||
Finalization itself is inherited: when the LLM service's
|
||||
:class:`~pipecat.turns.user_turn_completion_mixin.UserTurnCompletionLLMServiceMixin`
|
||||
detects a ``✓`` marker, it broadcasts a
|
||||
:class:`~pipecat.frames.frames.UserTurnCompletedFrame` and the
|
||||
:class:`~pipecat.frames.frames.UserTurnInferenceCompletedFrame` and the
|
||||
base class fires ``on_user_turn_stopped``. On
|
||||
``incomplete_short`` / ``incomplete_long`` markers the mixin
|
||||
re-prompts internally and no completion frame is emitted, so the
|
||||
|
||||
@@ -26,7 +26,7 @@ from pipecat.frames.frames import (
|
||||
LLMMessagesAppendFrame,
|
||||
LLMRunFrame,
|
||||
LLMTextFrame,
|
||||
UserTurnCompletedFrame,
|
||||
UserTurnInferenceCompletedFrame,
|
||||
)
|
||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||
|
||||
@@ -404,7 +404,7 @@ class UserTurnCompletionLLMServiceMixin(FrameProcessor):
|
||||
)
|
||||
self._turn_suppressed = True
|
||||
|
||||
# No UserTurnCompletedFrame is broadcast here: the turn is
|
||||
# No UserTurnInferenceCompletedFrame is broadcast here: the turn is
|
||||
# explicitly not complete. The re-prompt path is driven by
|
||||
# this mixin's own timeout.
|
||||
|
||||
@@ -427,7 +427,7 @@ class UserTurnCompletionLLMServiceMixin(FrameProcessor):
|
||||
# LLMTurnCompletionUserTurnStopStrategy) can fire
|
||||
# `on_user_turn_stopped`. Must fire before the marker so
|
||||
# downstream consumers see the signal before the response.
|
||||
await self.broadcast_frame(UserTurnCompletedFrame)
|
||||
await self.broadcast_frame(UserTurnInferenceCompletedFrame)
|
||||
|
||||
# Push the marker as a sideband signal that the assistant
|
||||
# aggregator will prepend to the upcoming aggregated text,
|
||||
|
||||
Reference in New Issue
Block a user