
    qi                        d Z ddlZddlZddlmZ ddlmZ ddlmZm	Z	m
Z
mZmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4 ddl5m6Z6m7Z7 ddl8m9Z9m:Z: ddl;m<Z< e G d d             Z=e G d d             Z> G d de:      Z? G d de:      Z@ G d de@      ZA G d deA      ZB G d deA      ZC G d deB      ZD G d deC      ZEy) aP  LLM response aggregators for handling conversation context and message aggregation.

This module provides aggregators that process and accumulate LLM responses, user inputs,
and conversation context. These aggregators handle the flow between speech-to-text,
LLM processing, and text-to-speech components in conversational AI pipelines.
    N)abstractmethod)	dataclass)DictListLiteralOptionalSet)logger)BaseInterruptionStrategy)SmartTurnParams)	VADParams)BotStartedSpeakingFrameBotStoppedSpeakingFrameCancelFrameEmulateUserStartedSpeakingFrameEmulateUserStoppedSpeakingFrameEndFrameFrameFunctionCallCancelFrameFunctionCallInProgressFrameFunctionCallResultFrameFunctionCallsStartedFrameInputAudioRawFrameInterimTranscriptionFrameInterruptionFrameLLMFullResponseEndFrameLLMFullResponseStartFrameLLMMessagesAppendFrameLLMMessagesFrameLLMMessagesUpdateFrameLLMRunFrameLLMSetToolChoiceFrameLLMSetToolsFrameLLMTextFrame'OpenAILLMContextAssistantTimestampFrameSpeechControlParamsFrame
StartFrame	TextFrameTranscriptionFrameUserImageRawFrameUserStartedSpeakingFrameUserStoppedSpeakingFrame)OpenAILLMContextOpenAILLMContextFrame)FrameDirectionFrameProcessor)time_now_iso8601c                   <    e Zd ZU dZdZeed<   dZeed<   dZe	ed<   y)	LLMUserAggregatorParamsaz  Parameters for configuring LLM user aggregation behavior.

    .. deprecated:: 0.0.99
        This class is deprecated, use the new universal `LLMContext` and
        `LLMContextAggregatorPair`.

    Parameters:
        aggregation_timeout: Maximum time in seconds to wait for additional
            transcription content before pushing aggregated result. This
            timeout is used only when the transcription is slow to arrive.
        turn_emulated_vad_timeout: Maximum time in seconds to wait for emulated
            VAD when using turn-based analysis. Applied when transcription is
            received but VAD didn't detect speech (e.g., whispered utterances).
        enable_emulated_vad_interruptions: When True, allows emulated VAD events
            to interrupt the bot when it's speaking. When False, emulated speech
            is ignored while the bot is speaking.
    g      ?aggregation_timeoutg?turn_emulated_vad_timeoutF!enable_emulated_vad_interruptionsN)
__name__
__module____qualname____doc__r4   float__annotations__r5   r6   bool     ]/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/processors/aggregators/llm_response.pyr3   r3   B   s*    $ "%$'*u*.3%t3r?   r3   c                        e Zd ZU dZdZeed<   y)LLMAssistantAggregatorParamsa  Parameters for configuring LLM assistant aggregation behavior.

    .. deprecated:: 0.0.99
        This class is deprecated, use the new universal `LLMContext` and
        `LLMContextAggregatorPair`.

    Parameters:
        expect_stripped_words: Whether to expect and handle stripped words
            in text frames by adding spaces between tokens. This parameter is
            ignored when used with the newer LLMAssistantAggregator, which
            handles word spacing automatically.
    Texpect_stripped_wordsN)r7   r8   r9   r:   rC   r=   r<   r>   r?   r@   rB   rB   [   s     #'4&r?   rB   c                   Z     e Zd ZdZ fdZdedef fdZdefdZ	de
fdZdefd	Z xZS )
LLMFullResponseAggregatorat  Aggregates complete LLM responses between start and end frames.

    This aggregator collects LLM text frames (tokens) received between
    `LLMFullResponseStartFrame` and `LLMFullResponseEndFrame` and provides
    the complete response via an event handler.

    The aggregator provides an "on_completion" event that fires when a full
    completion is available::

        @aggregator.event_handler("on_completion")
        async def on_completion(
            aggregator: LLMFullResponseAggregator,
            completion: str,
            completed: bool,
        ):
            # Handle the completion
            pass
    c                 b    t        |   di | d| _        d| _        | j	                  d       y)zInitialize the LLM full response aggregator.

        Args:
            **kwargs: Additional arguments passed to parent FrameProcessor.
         Fon_completionNr>   )super__init___aggregation_started_register_event_handlerselfkwargs	__class__s     r@   rJ   z"LLMFullResponseAggregator.__init__   s2     	"6"$$_5r?   frame	directionc                   K   t         |   ||       d{    t        |t              r4| j	                  d| j
                  d       d{    d| _        d| _        n}t        |t              r| j                  |       d{    nSt        |t              r| j                  |       d{    n)t        |t              r| j                  |       d{    | j                  ||       d{    y7 7 7 w7 O7 '7 w)zProcess incoming frames and aggregate LLM text content.

        Args:
            frame: The frame to process.
            direction: The direction of frame flow in the pipeline.
        NrH   FrG   )rI   process_frame
isinstancer   _call_event_handlerrK   rL   r   _handle_llm_startr   _handle_llm_endr$   _handle_llm_text
push_framerO   rR   rS   rQ   s      r@   rU   z'LLMFullResponseAggregator.process_frame   s      g#E9555e./**?D<M<MuUUU "D!DM89((///67&&u---|,''...ooeY/// 	6 V 0-./si   DC84DC:7DC<)D.C>/)DD D2D3D:D<D>D DD_c                    K   d| _         y wNTrL   rO   r]   s     r@   rX   z+LLMFullResponseAggregator._handle_llm_start   s        	c                 v   K   | j                  d| j                  d       d {    d| _        d| _        y 7 w)NrH   TFrG   )rW   rK   rL   ra   s     r@   rY   z)LLMFullResponseAggregator._handle_llm_end   s9     &&8I8I4PPP 	Qs   !979c                 d   K   | j                   sy | xj                  |j                  z  c_        y wN)rL   rK   textrO   rR   s     r@   rZ   z*LLMFullResponseAggregator._handle_llm_text   s%     }}UZZ's   .0)r7   r8   r9   r:   rJ   r   r/   rU   r   rX   r   rY   r(   rZ   __classcell__rQ   s   @r@   rE   rE   m   sF    &60 0> 0,)B '> 
(I (r?   rE   c                        e Zd ZdZ fdZeedee   fd              Z	eede
fd              Zed        Zed        Zed        Zed	        Zed
        Zede
fd       Zed        Z xZS )BaseLLMResponseAggregatora  Base class for all LLM response aggregators.

    These aggregators process incoming frames and aggregate content until they are
    ready to push the aggregation downstream. They maintain conversation state
    and handle message flow between different components in the pipeline.

    The aggregators keep a store (e.g. message list or LLM context) of the current
    conversation, storing messages from both users and the bot.

    .. deprecated:: 0.0.99
        `BaseLLMResponseAggregator` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.
    c                    t        j                         5  t        j                  d       t        j                  | j                  j
                   dt        d       ddd       t        |    di | y# 1 sw Y   xY w)a  Initialize the base LLM response aggregator.

        Args:
            **kwargs: Additional arguments passed to parent FrameProcessor.

        .. deprecated:: 0.0.99
            `BaseLLMResponseAggregator` is deprecated and will be removed in a future version.
            Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
            See `OpenAILLMContext` docstring for migration guide.
        alwaysz (likely created with create_context_aggregator()) is deprecated and will be removed in a future version. Use the universal LLMContext and LLMContextAggregatorPair instead. See OpenAILLMContext docstring for migration guide.   
stacklevelNr>   )	warningscatch_warningssimplefilterwarnrQ   r7   DeprecationWarningrI   rJ   rN   s     r@   rJ   z"BaseLLMResponseAggregator.__init__   sv     $$& 	!!(+MM>>**+ ,F F #	 	"6"	 	s   A	A77B returnc                      y)zGet the messages from the current conversation.

        Returns:
            List of message dictionaries representing the conversation history.
        Nr>   rO   s    r@   messagesz"BaseLLMResponseAggregator.messages        	r?   c                      y)zGet the role for this aggregator.

        Returns:
            The role string (e.g. "user", "assistant") for this aggregator.
        Nr>   rx   s    r@   rolezBaseLLMResponseAggregator.role   rz   r?   c                      y)zAdd the given messages to the conversation.

        Args:
            messages: Messages to append to the conversation history.
        Nr>   rO   ry   s     r@   add_messagesz&BaseLLMResponseAggregator.add_messages        	r?   c                      y)zReset the conversation with the given messages.

        Args:
            messages: Messages to replace the current conversation history.
        Nr>   r~   s     r@   set_messagesz&BaseLLMResponseAggregator.set_messages   r   r?   c                      y)zSet LLM tools to be used in the current conversation.

        Args:
            tools: List of tool definitions for the LLM to use.
        Nr>   rO   toolss     r@   	set_toolsz#BaseLLMResponseAggregator.set_tools   r   r?   c                      y)zSet the tool choice for the LLM.

        Args:
            tool_choice: Tool choice configuration for the LLM context.
        Nr>   rO   tool_choices     r@   set_tool_choicez)BaseLLMResponseAggregator.set_tool_choice  r   r?   c                    K   yw)zReset the internal state of this aggregator.

        This should clear aggregation state but not modify the conversation messages.
        Nr>   rx   s    r@   resetzBaseLLMResponseAggregator.reset        	   aggregationc                    K   yw)zAdd the given aggregation to the conversation store.

        Args:
            aggregation: The aggregated text content to add to the conversation.
        Nr>   rO   r   s     r@   handle_aggregationz,BaseLLMResponseAggregator.handle_aggregation        	r   c                    K   yw)zPush the current aggregation downstream.

        The specific frame type pushed depends on the aggregator implementation
        (e.g. context frame, messages frame).
        Nr>   rx   s    r@   push_aggregationz*BaseLLMResponseAggregator.push_aggregation!  r   r   )r7   r8   r9   r:   rJ   propertyr   r   dictry   strr|   r   r   r   r   r   r   r   rh   ri   s   @r@   rk   rk      s    #, $t*    c              C    r?   rk   c                        e Zd ZdZdedef fdZedee	   fd       Z
edefd       Zed        Zdefd	Zdefd
Zej"                  fdefdZd Zd ZdefdZded   e	z  fdZd Z xZS )LLMContextResponseAggregatora9  Base LLM aggregator that uses an OpenAI LLM context for conversation storage.

    This aggregator maintains conversation state using an OpenAILLMContext and
    pushes OpenAILLMContextFrame objects as aggregation frames. It provides
    common functionality for context-based conversation management.

    .. deprecated:: 0.0.99
        `LLMContextResponseAggregator` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.
    contextr|   c                N    t        |   di | || _        || _        d| _        y)aA  Initialize the context response aggregator.

        Args:
            context: The OpenAI LLM context to use for conversation storage.
            role: The role this aggregator represents (e.g. "user", "assistant").
            **kwargs: Additional arguments passed to parent class.

        .. deprecated:: 0.0.99
            `LLMContextResponseAggregator` is deprecated and will be removed in a future version.
            Use the universal `LLMUserAggregator` and `LLMAssistantAggregator` instead.
            See `OpenAILLMContext` docstring for migration guide.
        rG   Nr>   )rI   rJ   _context_rolerK   )rO   r   r|   rP   rQ   s       r@   rJ   z%LLMContextResponseAggregator.__init__8  s+     	"6"
!#r?   rv   c                 6    | j                   j                         S )zxGet messages from the LLM context.

        Returns:
            List of message dictionaries from the context.
        )r   get_messagesrx   s    r@   ry   z%LLMContextResponseAggregator.messagesL  s     }}))++r?   c                     | j                   S )zmGet the role for this aggregator.

        Returns:
            The role string for this aggregator.
        )r   rx   s    r@   r|   z!LLMContextResponseAggregator.roleU  s     zzr?   c                     | j                   S )zyGet the OpenAI LLM context.

        Returns:
            The OpenAILLMContext instance used by this aggregator.
        )r   rx   s    r@   r   z$LLMContextResponseAggregator.context^  s     }}r?   c                     t        j                         5  t        j                  d       t        j                  dt        d       ddd       | j                         S # 1 sw Y   | j                         S xY w)zCreate a context frame with the current context.

        .. deprecated:: 0.0.82
            This method is deprecated and will be removed in a future version.

        Returns:
            LLMContextFrame containing the current context.
        rm   zget_context_frame() is deprecated and will be removed in a future version. To trigger an LLM response, use LLMRunFrame instead.rn   ro   N)rq   rr   rs   rt   ru   _get_context_framerx   s    r@   get_context_framez.LLMContextResponseAggregator.get_context_frameg  sh     $$& 	!!(+MM R"	 &&((	 &&((s   2AA7c                 .    t        | j                        S )N)r   )r.   r   rx   s    r@   r   z/LLMContextResponseAggregator._get_context_framey  s    $T]];;r?   rS   c                 d   K   | j                         }| j                  ||       d{    y7 w)zPush a context frame in the specified direction.

        Args:
            direction: The direction to push the frame (upstream or downstream).
        N)r   r[   )rO   rS   rR   s      r@   push_context_framez/LLMContextResponseAggregator.push_context_frame|  s*      '')ooeY///s   &0.0c                 :    | j                   j                  |       y)zwAdd messages to the context.

        Args:
            messages: Messages to add to the conversation context.
        N)r   r   r~   s     r@   r   z)LLMContextResponseAggregator.add_messages       	""8,r?   c                 :    | j                   j                  |       y)zySet the context messages.

        Args:
            messages: Messages to replace the current context messages.
        N)r   r   r~   s     r@   r   z)LLMContextResponseAggregator.set_messages  r   r?   r   c                 :    | j                   j                  |       y)ztSet tools in the context.

        Args:
            tools: List of tool definitions to set in the context.
        N)r   r   r   s     r@   r   z&LLMContextResponseAggregator.set_tools  s     	&r?   r   )noneautorequiredc                 :    | j                   j                  |       y)z{Set tool choice in the context.

        Args:
            tool_choice: Tool choice configuration for the context.
        N)r   r   r   s     r@   r   z,LLMContextResponseAggregator.set_tool_choice  s     	%%k2r?   c                    K   d| _         yw)zReset the aggregation state.rG   N)rK   rx   s    r@   r   z"LLMContextResponseAggregator.reset  s     rb   )r7   r8   r9   r:   r-   r   rJ   r   r   r   ry   r|   r   r.   r   r   r/   
DOWNSTREAMr   r   r   r   r   r   r   rh   ri   s   @r@   r   r   +  s    
$#3 $3 $( ,$t* , , c    )#8 )$<$9 < DRC\C\ 0. 0--'t '373M+NQU+U 3r?   r   c                   .    e Zd ZdZdddedee   f fdZ fdZde	fd	Z
d
edef fdZd Zd ZdefdZd
efdZd
efdZd
efdZd
efdZd
efdZd
efdZd
efdZd
e fdZ!de"fdZ#de$fdZ%de&fdZ'd
e(fdZ)de*fdZ+d Z,d  Z-d! Z.d" Z/ xZ0S )#LLMUserContextAggregatoraK  User LLM aggregator that processes speech-to-text transcriptions.

    This aggregator handles the complex logic of aggregating user speech transcriptions
    from STT services. It manages multiple scenarios including:

    - Transcriptions received between VAD events
    - Transcriptions received outside VAD events
    - Interim vs final transcriptions
    - User interruptions during bot speech
    - Emulated VAD for whispered or short utterances

    The aggregator uses timeouts to handle cases where transcriptions arrive
    after VAD events or when no VAD is available.

    .. deprecated:: 0.0.99
        `LLMUserContextAggregator` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.
    Nparamsr   r   c                   t        |   d|dd| |xs
 t               | _        d| _        d| _        d|v r`t        j                         5  t        j                  d       t        j                  dt               ddd       |d   | j                  _        d| _        d| _        d| _        d| _        d| _        d| _        t%        j&                         | _        d| _        y# 1 sw Y   hxY w)	a6  Initialize the user context aggregator.

        Args:
            context: The OpenAI LLM context for conversation storage.
            params: Configuration parameters for aggregation behavior.
            **kwargs: Additional arguments. Supports deprecated 'aggregation_timeout'.

        .. deprecated:: 0.0.99
            `LLMUserContextAggregator` is deprecated and will be removed in a future version.
            Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
            See `OpenAILLMContext` docstring for migration guide.
        userr   r|   Nr4   rm   zDParameter 'aggregation_timeout' is deprecated, use 'params' instead.Fr>   )rI   rJ   r3   _params_vad_params_turn_paramsrq   rr   rs   rt   ru   r4   _user_speaking_bot_speaking_was_bot_speaking_emulating_vad_seen_interim_results_waiting_for_aggregationasyncioEvent_aggregation_event_aggregation_taskrO   r   r   rP   rQ   s       r@   rJ   z!LLMUserContextAggregator.__init__  s    ( 	@v@@:!8!:047; F*((* %%h/Z& 066K/LDLL,#"!&#%*"(-%")--/!%# s   0C$$C-c                    K   t         |           d{    d| _        d| _        d| _        | j
                  D cg c]  }|j                          d{    c} y7 J7 c c}w w)z8Reset the aggregation state and interruption strategies.NF)rI   r   r   r   r   _interruption_strategies)rO   srQ   s     r@   r   zLLMUserContextAggregator.reset  sZ     gmo!&%*"(-%"&"?"?@Qqwwy@	 	 
@s2   A)A 'A)A$A"
A$A)"A$$A)r   c                 \   K   | j                   j                  | j                  |d       yw)zAdd the aggregated user text to the context.

        Args:
            aggregation: The aggregated user text to add as a user message.
        r|   contentN)r   add_messager|   r   s     r@   r   z+LLMUserContextAggregator.handle_aggregation  s#      	!!499"MNs   *,rR   rS   c                 ,  K   t         |   ||       d{    t        |t              r4| j	                  ||       d{    | j                  |       d{    yt        |t              r4| j	                  ||       d{    | j                  |       d{    yt        |t              r4| j                  |       d{    | j	                  ||       d{    yt        |t              r4| j                  |       d{    | j	                  ||       d{    yt        |t              r4| j                  |       d{    | j	                  ||       d{    yt        |t              r4| j                  |       d{    | j	                  ||       d{    yt        |t               r4| j#                  |       d{    | j	                  ||       d{    yt        |t$              r4| j'                  |       d{    | j	                  ||       d{    yt        |t(              r| j+                  |       d{    yt        |t,              r| j/                  |       d{    yt        |t0              r| j3                  |       d{    yt        |t4              r| j7                  |       d{    yt        |t8              r| j;                  |       d{    yt        |t<              r| j?                  |j@                         yt        |tB              r| jE                  |jF                         yt        |tH              r=|jJ                  | _&        |jN                  | _(        | j	                  ||       d{    y| j	                  ||       d{    y7 7 7 z7 R7 <7 7 7 7 7 7 7 [7 D7 7 7 7 7 7 z7 S7 ,7 7 b7 Iw)zProcess frames for user speech aggregation and context management.

        Args:
            frame: The frame to process.
            direction: The direction of frame flow in the pipeline.
        N))rI   rU   rV   r'   r[   _startr   _stopr   _cancelr   _handle_input_audior+   _handle_user_started_speakingr,   _handle_user_stopped_speakingr   _handle_bot_started_speakingr   _handle_bot_stopped_speakingr)   _handle_transcriptionr   _handle_interim_transcriptionr!   _handle_llm_runr   _handle_llm_messages_appendr    _handle_llm_messages_updater#   r   r   r"   r   r   r&   
vad_paramsr   turn_paramsr   r\   s      r@   rU   z&LLMUserContextAggregator.process_frame  s<     g#E9555eZ( //%333++e$$$x( //%333**U###{+,,u%%%//%33312**5111//%3337844U;;;//%3337844U;;;//%3336733E::://%3336733E::://%33312,,U3338944U;;;{+&&u---5622599956225999/0NN5;;'45  !2!2378$//D % 1 1D//%333//%333c 	6
 4$ 4#%313;3;3:3:33;-99 43s  PO)POPO*POPO)PO	P"O #)PO#P&O&')PO)P*O,+)PO/P.O2/)PO5P2O83)PO;P6O>7)P P!)P
P)P4P5)PP
)PP	B$P-P.PP	PPPPPP P#P&P)P,P/P2P5P8P;P>PPPP
PPPPc                    K   | j                   }| j                          d{    | j                  |       d{    t        | j                        }| j                  |       d{    y7 L7 57 	wz7Process the current aggregation and push it downstream.N)rK   r   r   r.   r   r[   rO   r   rR   s      r@   _process_aggregationz-LLMUserContextAggregator._process_aggregation6  sa     ''jjl%%k222%dmm4ooe$$$ 	2$s1    A5A/A5A1-A5)A3*A51A53A5c                 T  K   t        | j                        dkD  r| j                  r| j                  r| j	                          d{   }|rFt        j                  d       | j                          d{    | j                          d{    yt        j                  d       | j                          d{    y| j                          d{    y| j                  s7| j                  r*| j                  st        j                  d       d| _        yyyy7 7 7 7 h7 Qw)zMPush the current aggregation based on interruption strategies and conditions.r   NzBInterruption conditions met - pushing interruption and aggregationz9Interruption conditions not met - not pushing aggregationz6User stopped speaking but no new aggregation received.F)lenrK   interruption_strategiesr   %_should_interrupt_based_on_strategiesr
   debugbroadcast_interruptionr   r   r   r   warning)rO   should_interrupts     r@   r   z)LLMUserContextAggregator.push_aggregation>  s     t  !A%++0B0B)-)S)S)U#U #LL\ 5577733555LL!\]**,&& //111 ++0F0FtOaOaNNST%*D" Pb0F++ $V 85 ' 2s[   AD(D.D(5D 6D(D"-D(;D$<D(D&A
D( D("D($D(&D(rv   c                     K   dt         f fd}t         j                  D cg c]  } ||       d{    c}      S 7 c c}w w)zCheck if interruption should occur based on configured strategies.

        Returns:
            True if any interruption strategy indicates interruption should occur.
        strategyc                    K   | j                  j                         d {    | j                          d {   S 7 7 wre   )append_textrK   r   )r   rO   s    r@   r   zXLLMUserContextAggregator._should_interrupt_based_on_strategies.<locals>.should_interruptg  s<     &&t'8'8999!22444 :4s   A?AAAAN)r   anyr   )rO   r   r   s   `  r@   r   z>LLMUserContextAggregator._should_interrupt_based_on_strategies`  sD     	5-E 	5 t7T7TU!*1---UVV-Us%    AAAAAAAc                 ,   K   | j                          y wre   )_create_aggregation_taskrg   s     r@   r   zLLMUserContextAggregator._startm  s     %%'s   c                 @   K   | j                          d {    y 7 wre   _cancel_aggregation_taskrg   s     r@   r   zLLMUserContextAggregator._stopp       ++---   c                 @   K   | j                          d {    y 7 wre   r   rg   s     r@   r   z LLMUserContextAggregator._cancels  r   r   c                 @   K   | j                          d {    y 7 wre   )r   rg   s     r@   r   z(LLMUserContextAggregator._handle_llm_runv  s     %%'''r   c                    K   | j                  |j                         |j                  r| j                          d {    y y 7 wre   )r   ry   run_llmr   rg   s     r@   r   z4LLMUserContextAggregator._handle_llm_messages_appendy  9     %..)==))+++ +   ;AAAc                    K   | j                  |j                         |j                  r| j                          d {    y y 7 wre   )r   ry   r   r   rg   s     r@   r   z4LLMUserContextAggregator._handle_llm_messages_update~  r   r   c                    K   | j                   D ]0  }|j                  |j                  |j                         d {    2 y 7 wre   )r   append_audioaudiosample_rate)rO   rR   r   s      r@   r   z,LLMUserContextAggregator._handle_input_audio  s>     -- 	AA..e.?.?@@@	A@s   9AAAc                    K   d| _         d| _        | j                  | _        |j                  s| j
                  rd| _        y y y w)NTF)r   r   r   r   emulatedr   rg   s     r@   r   z6LLMUserContextAggregator._handle_user_started_speaking  sD     "(,%!%!3!3
 ~~$"5"5"'D #6~s   AAr]   c                   K   d| _         t        | j                        dkD  r&| j                  s| j	                          d {    y y | j                  s5| j
                  r(| j                  s| j                  j                          y y y y 7 Hw)NFr   )	r   r   rK   r   r   r   r   r   setra   s     r@   r   z6LLMUserContextAggregator._handle_user_stopped_speaking  s     # t  !A%--++--- .
 ++0F0FtOaOa##'') Pb0F+	 .s   ?BB
A	Bc                    K   d| _         y wr_   r   ra   s     r@   r   z5LLMUserContextAggregator._handle_bot_started_speaking  s     !rb   c                    K   d| _         y w)NFr  ra   s     r@   r   z5LLMUserContextAggregator._handle_bot_stopped_speaking  s     "rb   c                    K   |j                   }|j                         sy | xj                  | j                  rd| n|z  c_        d| _        | j                  j                          y w)N F)rf   striprK   r   r   r  )rO   rR   rf   s      r@   r   z.LLMUserContextAggregator._handle_transcription  sX     zz zz|4+<+<qZ$F%*"##%s   A&A(c                    K   d| _         y wr_   )r   ra   s     r@   r   z6LLMUserContextAggregator._handle_interim_transcription  s     %)"rb   c                 f    | j                   s%| j                  | j                               | _         y y re   )r   create_task_aggregation_task_handlerrx   s    r@   r   z1LLMUserContextAggregator._create_aggregation_task  s,    %%%)%5%5d6T6T6V%WD" &r?   c                 ~   K   | j                   r+| j                  | j                          d {    d | _         y y 7 wre   )r   cancel_taskrx   s    r@   r   z1LLMUserContextAggregator._cancel_aggregation_task  s9     !!""4#9#9:::%)D" ":s   +=;=c                 (  K   	 	 | j                   s| j                  j                  }n[| j                  r| j                  j                  }n8| j
                  r| j
                  j                  n| j                  j                  }t        j                  | j                  j                         |       d {    | j                          d {    | j                  j'                          7 77 !# t        j                  $ rl | j                  s| j                          d {  7   | j                   r8| j                  t!               t"        j$                         d {  7   d| _         Y w xY w# | j                  j'                          w xY ww)N)timeoutF)r   r   r4   r   r5   r   	stop_secsr   wait_forr   wait_maybe_emulate_user_speakingTimeoutErrorr   r   r[   r   r/   UPSTREAMclear)rO   r  s     r@   r  z2LLMUserContextAggregator._aggregation_task_handler  sJ    00. **"ll>>G&&"llDDG
  ++ ((22!\\CC 
 &&t'>'>'C'C'EwWWW77999 ''--/c F X9'' 
0**//111 &&//79>;R;R   +0D'
0 ''--/sq   FB0C1 5C-6C1 C/C1 F-C1 /C1 12E0#D&$<E0 E#!E0-E3 /E00E3 3FFc                   K   | j                   s| j                  st        | j                        dkD  r| j                  rD| j
                  j                  s.t        j                  d       | j                          d{    y| j                  t               t        j                         d{    d| _        yyyy7 @7 w)zMaybe emulate user speaking based on transcription.

        Emulate user speaking if we got a transcription but it was not
        detected by VAD. Behavior when bot is speaking depends on the
        enable_emulated_vad_interruptions parameter.
        r   z2Ignoring user speaking emulation, bot is speaking.NT)r   r   r   rK   r   r   r6   r
   r   r   r[   r   r/   r  r   rx   s    r@   r  z5LLMUserContextAggregator._maybe_emulate_user_speaking  s      ##11D%%&*!!$,,*X*XQRjjl"" oo&E&GI`I`aaa&*# + 2 $ # bs$   A;C=B>>0C.C /C C)1r7   r8   r9   r:   r-   r   r3   rJ   r   r   r   r   r/   rU   r   r   r=   r   r'   r   r   r   r   r   r!   r   r   r   r    r   r   r   r+   r   r,   r   r   r   r   r   r)   r   r   r   r   r   r  r  rh   ri   s   @r@   r   r     s)   0 59	+&!+& 01	+&ZAOC O84 84> 84t%+DWT W(* (. ..; .(; (,7M ,
,7M ,
A/A A	(9Q 	(*5M *"4K "#4K #&1C &*5N *X*
20h+r?   r   c                   T    e Zd ZdZdddedee   f fdZede	fd       Z
d	efd
ZdefdZdefdZdefdZdefdZdedef fdZd ZdefdZdefdZdefdZdefdZ de!fdZ"defdZ#defdZ$defdZ%defdZ&de'fdZ(de)fdZ*de+fdZ,d e-j\                  fd!Z/ xZ0S )"LLMAssistantContextAggregatora'  Assistant LLM aggregator that processes bot responses and function calls.

    This aggregator handles the complex logic of processing assistant responses including:

    - Text frame aggregation between response start/end markers
    - Function call lifecycle management
    - Context updates with timestamps
    - Tool execution and result handling
    - Interruption handling during responses

    The aggregator manages function calls in progress and coordinates between
    text generation and tool execution phases of LLM responses.

    .. deprecated:: 0.0.99
        `LLMAssistantContextAggregator` is deprecated and will be removed in a future version.
        Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
        See `OpenAILLMContext` docstring for migration guide.
    Nr   r   r   c                j   t        |   d|dd| |xs
 t               | _        d|v r`t	        j
                         5  t	        j                  d       t	        j                  dt               ddd       |d   | j                  _	        d| _
        i | _        t               | _        y# 1 sw Y   ;xY w)	aB  Initialize the assistant context aggregator.

        Args:
            context: The OpenAI LLM context for conversation storage.
            params: Configuration parameters for aggregation behavior.
            **kwargs: Additional arguments. Supports deprecated 'expect_stripped_words'.

        .. deprecated:: 0.0.99
            `LLMAssistantContextAggregator` is deprecated and will be removed in a future version.
            Use the universal `LLMContext` and `LLMContextAggregatorPair` instead.
            See `OpenAILLMContext` docstring for migration guide.
        	assistantr   rC   rm   zFParameter 'expect_stripped_words' is deprecated, use 'params' instead.Nr   r>   )rI   rJ   rB   r   rq   rr   rs   rt   ru   rC   rL   _function_calls_in_progressr  _context_updated_tasksr   s       r@   rJ   z&LLMAssistantContextAggregator.__init__"  s    ( 	E{EfE?!=!?"f,((* %%h/\& 288O1PDLL.]_(9<# s   0B))B2rv   c                 ,    t        | j                        S )zCheck if there are any function calls currently in progress.

        Returns:
            True if function calls are in progress, False otherwise.
        )r=   r   rx   s    r@   has_function_calls_in_progressz<LLMAssistantContextAggregator.has_function_calls_in_progressG  s     D4455r?   r   c                 H   K   | j                   j                  d|d       yw)zAdd the aggregated assistant text to the context.

        Args:
            aggregation: The aggregated assistant text to add as an assistant message.
        r  r   N)r   r   r   s     r@   r   z0LLMAssistantContextAggregator.handle_aggregationP  s      	!!;;"OPs    "rR   c                    K   yw)zHandle a function call that is in progress.

        Args:
            frame: The function call in progress frame to handle.
        Nr>   rg   s     r@    handle_function_call_in_progressz>LLMAssistantContextAggregator.handle_function_call_in_progressX  r   r   c                    K   yw)zHandle the result of a completed function call.

        Args:
            frame: The function call result frame to handle.
        Nr>   rg   s     r@   handle_function_call_resultz9LLMAssistantContextAggregator.handle_function_call_result`  r   r   c                    K   yw)z|Handle cancellation of a function call.

        Args:
            frame: The function call cancel frame to handle.
        Nr>   rg   s     r@   handle_function_call_cancelz9LLMAssistantContextAggregator.handle_function_call_cancelh  r   r   c                    K   yw)zHandle a user image frame associated with a function call.

        Args:
            frame: The user image frame to handle.
        Nr>   rg   s     r@   handle_user_image_framez5LLMAssistantContextAggregator.handle_user_image_framep  r   r   rS   c                 j  K   t         |   ||       d{    t        |t              r4| j	                  |       d{    | j                  ||       d{    yt        |t              r| j                  |       d{    yt        |t              r| j                  |       d{    yt        |t              r| j                  |       d{    yt        |t              r| j                  |       d{    yt        |t              r| j                  |       d{    yt        |t               r| j#                  |       d{    yt        |t$              r| j'                  |j(                         yt        |t*              r| j-                  |j.                         yt        |t0              r| j3                  |       d{    yt        |t4              r| j7                  |       d{    yt        |t8              r| j;                  |       d{    yt        |t<              r| j?                  |       d{    yt        |t@              r<|jB                  r0|jB                  jD                  r| jG                  |       d{    yt        |tH              r3| jK                          d{    | j                  ||       d{    y| j                  ||       d{    y7 7 7 7 7 d7 =7 7 7 7 I7 "7 7 7 7 a7 I7 0w)zProcess frames for assistant response aggregation and function call management.

        Args:
            frame: The frame to process.
            direction: The direction of frame flow in the pipeline.
        N)&rI   rU   rV   r   _handle_interruptionsr[   r   rX   r   rY   r(   _handle_textr!   r   r   r   r    r   r#   r   r   r"   r   r   r   _handle_function_calls_startedr   !_handle_function_call_in_progressr   _handle_function_call_resultr   _handle_function_call_cancelr*   requesttool_call_id_handle_user_image_framer   r   r\   s      r@   rU   z+LLMAssistantContextAggregator.process_framex  s     g#E9555e./,,U333//%33389((///67&&u---y)##E***{+&&u---5622599956225999/0NN5;;'45  !2!238955e<<<:;88???6733E:::6733E:::01emmHbHb//66667'')))//%333//%333G 	6 43/-*-99 =?::6)33s1  L3L(L3 L	L3L)L3L)L3.L/)L3L)L3L)L3,L-)L3LBL3L!)L3L$)L3,L'-)L3L)AL3"L+#(L3L-L3%L/&L3 L1L3	L3L3L3L3L3L3L3L3!L3$L3'L3)L3+L3-L3/L31L3c                 Z  K   | j                   sy| j                   j                         }| j                          d{    |r| j                  |       d{    | j	                          d{    t        t                     }| j                  |       d{    y7 e7 L7 67 w)z6Push the current assistant aggregation with timestamp.N)	timestamp)rK   r  r   r   r   r%   r1   r[   )rO   r   timestamp_frames      r@   r   z.LLMAssistantContextAggregator.push_aggregation  s       ''--/jjl))+666 %%''' BL\L^_ooo... 	 7 	( 	/sE   ;B+B#B+B%B+0B'1,B+B)B+%B+'B+)B+c                 ^   K   | j                  t        j                         d {    y 7 wre   )r   r/   r  rg   s     r@   r   z-LLMAssistantContextAggregator._handle_llm_run  s      %%n&=&=>>>s   #-+-c                    K   | j                  |j                         |j                  r(| j                  t        j
                         d {    y y 7 wre   )r   ry   r   r   r/   r  rg   s     r@   r   z9LLMAssistantContextAggregator._handle_llm_messages_append  A     %..)==)).*A*ABBB B   A
AAAc                    K   | j                  |j                         |j                  r(| j                  t        j
                         d {    y y 7 wre   )r   ry   r   r   r/   r  rg   s     r@   r   z9LLMAssistantContextAggregator._handle_llm_messages_update  r<  r=  c                    K   | j                          d {    d| _        | j                          d {    y 7 $7 w)Nr   )r   rL   r   rg   s     r@   r.  z3LLMAssistantContextAggregator._handle_interruptions  s7     ##%%%jjl 	&s   ?;?=??c                   K   |j                   D cg c]  }|j                   d|j                    }}t        j                  |  d|        |j                   D ]  }d | j
                  |j                  <    y c c}w w)N:z FunctionCallsStartedFrame: )function_callsfunction_namer5  r
   r   r   )rO   rR   ffunction_namesfunction_calls        r@   r0  z<LLMAssistantContextAggregator._handle_function_calls_started  s     INI]I]^AQ__-Qq~~.>?^^v9.9IJK"11 	PMKOD,,]-G-GH	P _s   A?"A:AA?c                    K   t        j                  |  d|j                   d|j                   d       | j	                  |       d {    || j
                  |j                  <   y 7 w)Nz FunctionCallInProgressFrame: [rA  ])r
   r   rC  r5  r&  r   rg   s     r@   r1  z?LLMAssistantContextAggregator._handle_function_call_in_progress  si     f3E4G4G3H%J\J\I]]^_	
 33E:::?D((););< 	;s   AA*	A(
A*c                 p  K   t        j                  |  d|j                   d|j                   d       |j                  | j                  vr$t        j
                  d|j                   d       y | j                  |j                  = |j                  }| j                  |       d {    d}|j                  rJ|r|j                  |j                  }n/|j                  |j                  }nt        | j                         }|r'| j                  t        j                         d {    |r|j                  rs|j                   d|j                   d}| j                  |j                         |      }| j                   j#                  |       |j%                  | j&                         y y y 7 	7 w)Nz FunctionCallResultFrame: [rA  rH  z&FunctionCallResultFrame tool_call_id [] is not runningFz:on_context_updated)r
   r   rC  r5  r   r   
propertiesr(  resultr   r=   r   r/   r  on_context_updatedr  r!  addadd_done_callback_context_updated_task_finished)rO   rR   rK  r   	task_nametasks         r@   r2  z:LLMAssistantContextAggregator._handle_function_call_result  s    f/0C0C/DAeFXFXEYYZ[	
 T%E%EENN89K9K8LL\] ,,U-?-?@%%
..u555 <<j00<$,,*-- #4#C#CDD)).*A*ABBB
 *77 ../q1C1C0DDWXI##J$A$A$CYOD''++D1""4#F#FG	 8:- 	6" Cs&   B&F6(F1)B F6)F4*BF64F6c                 >  K   t        j                  |  d|j                   d|j                   d       | j                  j                  |j                        }|r>|j                  r1| j                  |       d {    | j                  |j                  = y y y 7 w)Nz FunctionCallCancelFrame: [rA  rH  )r
   r   rC  r5  r   getcancel_on_interruptionr*  )rO   rR   rF  s      r@   r3  z:LLMAssistantContextAggregator._handle_function_call_cancel  s     f/0C0C/DAeFXFXEYYZ[	
 88<<U=O=OP]AA225999001C1CD B=9s   A:B<B=Bc                   K   t        j                  |  d|j                  j                   d|j                  j                   d       |j                  j                  | j
                  vr.t        j                  d|j                  j                   d       y | j
                  |j                  j                  = |j                  r9|j                  j                  r#|j                  j                  d        d {    | j                  |       d {    | j                          d {    | j                  t        j                         d {    y 7 ]7 F7 07 w)Nz UserImageRawFrame: [rA  rH  z UserImageRawFrame tool_call_id [rJ  )r
   r   r4  rC  r5  r   r   result_callbackr,  r   r   r/   r  rg   s     r@   r6  z6LLMAssistantContextAggregator._handle_user_image_frame  s    f)%--*E*E)FaHbHbGccde	
 ==%%T-M-MMNN25==3M3M2NN^_ ,,U]]-G-GH ==U]]::--//555**5111##%%%%%n&=&=>>>	 61%>sH   C8E :E;E EE +E,&E EE E E E r]   c                 6   K   | xj                   dz  c_         y wN   r`   ra   s     r@   rX   z/LLMAssistantContextAggregator._handle_llm_start  s     s   c                 j   K   | xj                   dz  c_         | j                          d {    y 7 wrY  )rL   r   ra   s     r@   rY   z-LLMAssistantContextAggregator._handle_llm_end!  s&     ##%%%s   )313c                   K   |j                   sy | j                  j                  rC| xj                  | j                  rd|j                   z  c_        y |j                  z  c_        y | xj                  |j                  z  c_        y w)Nr
  )append_to_contextr   rC   rK   rf   rg   s     r@   r/  z*LLMAssistantContextAggregator._handle_text%  sd     &&<<--T5F5F1UZZL!1VEJJV+s   BB	rR  c                 :    | j                   j                  |       y re   )r!  discard)rO   rR  s     r@   rP  z<LLMAssistantContextAggregator._context_updated_task_finished.  s    ##++D1r?   )1r7   r8   r9   r:   r-   r   rB   rJ   r   r=   r#  r   r   r   r&  r   r(  r   r*  r*   r,  r   r/   rU   r   r!   r   r   r   r    r   r   r.  r   r0  r1  r2  r3  r6  r   rX   r   rY   r(   r/  r   TaskrP  rh   ri   s   @r@   r  r    sX   . :>	#?!#? 56	#?J 6 6 6QC Q<W 7N 7N 3D *4 *4> *4X/$?; ?C7M C
C7M C
1B 
P:S PE=X E(H8O (HTE8O E?4E ?,)B &'> &,	 ,27<< 2r?   r  c                   N     e Zd ZdZ	 ddddeee      dee   f fdZd Z	 xZ
S )	LLMUserResponseAggregatora  User response aggregator that outputs LLMMessagesFrame instead of context frames.

    .. deprecated:: 0.0.79
        This class is deprecated and will be removed in a future version.
        Use `LLMUserContextAggregator` or another LLM-specific subclass instead.

    This aggregator extends LLMUserContextAggregator but pushes LLMMessagesFrame
    objects downstream instead of OpenAILLMContextFrame objects. This is useful
    when you need message-based output rather than context-based output.
    Nr   ry   r   c                    t        j                         5  t        j                  d       t        j                  dt        d       ddd       t        |   dt        |      |d| y# 1 sw Y   %xY w)a  Initialize the user response aggregator.

        Args:
            messages: Initial messages for the conversation context.
            params: Configuration parameters for aggregation behavior.
            **kwargs: Additional arguments passed to parent class.
        rm   zLLMUserResponseAggregator is deprecated and will be removed in a future version. Use LLMUserContextAggregator or another LLM-specific subclass instead.rn   ro   Nr   r   r>   rq   rr   rs   rt   ru   rI   rJ   r-   rO   ry   r   rP   rQ   s       r@   rJ   z"LLMUserResponseAggregator.__init__>  sk     $$& 	!!(+MMY"		 	U!1(!;FUfU	 	   2A,,A5c                   K   | j                   }| j                          d{    | j                  |       d{    t        | j                  j
                        }| j                  |       d{    y7 V7 ?7 	wr   )rK   r   r   r   r   ry   r[   r   s      r@   r   z.LLMUserResponseAggregator._process_aggregationV  sg     ''jjl%%k222 !7!78ooe$$$ 	2$s1    A?A9A?A;7A?3A=4A?;A?=A?re   )r7   r8   r9   r:   r   r   r   r3   rJ   r   rh   ri   s   @r@   rb  rb  2  sF    	 *.V 59	V4:&V 01	V0%r?   rb  c                   N     e Zd ZdZ	 ddddeee      dee   f fdZd Z	 xZ
S )	LLMAssistantResponseAggregatora  Assistant response aggregator that outputs LLMMessagesFrame instead of context frames.

    .. deprecated:: 0.0.79
        This class is deprecated and will be removed in a future version.
        Use `LLMAssistantContextAggregator` or another LLM-specific subclass instead.

    This aggregator extends LLMAssistantContextAggregator but pushes LLMMessagesFrame
    objects downstream instead of OpenAILLMContextFrame objects. This is useful
    when you need message-based output rather than context-based output.
    Nr   ry   r   c                    t        j                         5  t        j                  d       t        j                  dt        d       ddd       t        |   dt        |      |d| y# 1 sw Y   %xY w)a  Initialize the assistant response aggregator.

        Args:
            messages: Initial messages for the conversation context.
            params: Configuration parameters for aggregation behavior.
            **kwargs: Additional arguments passed to parent class.
        rm   zLLMAssistantResponseAggregator is deprecated and will be removed in a future version. Use LLMAssistantContextAggregator or another LLM-specific subclass instead.rn   ro   Nrd  r>   re  rf  s       r@   rJ   z'LLMAssistantResponseAggregator.__init__k  sk     $$& 	!!(+MM^"		 	U!1(!;FUfU	 	rg  c                 0  K   t        | j                        dkD  rt| j                  | j                         d{    | j                          d{    t	        | j
                  j                        }| j                  |       d{    yy7 V7 @7 
w)z>Push the aggregated assistant response as an LLMMessagesFrame.r   N)r   rK   r   r   r   r   ry   r[   rg   s     r@   r   z/LLMAssistantResponseAggregator.push_aggregation  s~     t  !A%))$*;*;<<< **,$T]]%;%;<E//%((( &<  )s3   7BBBB7B	B
BBBre   )r7   r8   r9   r:   r   r   r   rB   rJ   r   rh   ri   s   @r@   rj  rj  _  sF    	 *.V :>	V4:&V 56	V0
)r?   rj  )Fr:   r   rq   abcr   dataclassesr   typingr   r   r   r   r	   logurur
   6pipecat.audio.interruptions.base_interruption_strategyr   -pipecat.audio.turn.smart_turn.base_smart_turnr   pipecat.audio.vad.vad_analyzerr   pipecat.frames.framesr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   1pipecat.processors.aggregators.openai_llm_contextr-   r.   "pipecat.processors.frame_processorr/   r0   pipecat.utils.timer1   r3   rB   rE   rk   r   r   r  rb  rj  r>   r?   r@   <module>rx     s      ! 5 5  [ I 4                 B N / 4 4 40 ' ' '"B( B(Jv vr|#< |~a+; a+Ha2$@ a2H	*% 8 *%Z.)%B .)r?   