o
    i_                     @  s  U d dl mZ d dlZd dlmZmZ d dlmZmZm	Z	m
Z
mZmZ d dl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 ddlmZ ddlmZ ergddl m!Z!m"Z"m#Z# G dd deZ$G dd deZ%e
d Z&de'd< G dd deddZ(G dd deZ)e$e%B e*B Z+de'd< G dd deZ,G d d! d!eZ-G d"d# d#eZ.G d$d% d%eZ/ee)e,B e-B e.B e/B ed&d'f Z0G d(d) d)Z1G d*d+ d+e1Z2dS ),    )annotationsN)	GeneratorSequence)TYPE_CHECKING	AnnotatedAnyLiteral	TypeAliasoverload)	BaseModelFieldPrivateAttrTypeAdapter)	TypedDict)rtc   )utils)logger)	NOT_GIVEN
NotGivenOr)is_given   )_provider_format)LLMToolToolsetc                   @  s   e Zd ZU dZedd dZded< 	 eddZd	ed
< ded< 	 dZded< 	 dZ	ded< 	 dZ
ded< 	 dZded< 	 eedZded< dS )ImageContentac  
    ImageContent is used to input images into the ChatContext on supported LLM providers / plugins.

    You may need to consult your LLM provider's documentation on supported URL types.

    ```python
    # Pass a VideoFrame directly, which will be automatically converted to a JPEG data URL internally
    async for event in rtc.VideoStream(video_track):
        chat_image = ImageContent(image=event.frame)
        # this instance is now available for your ChatContext

    # Encode your VideoFrame yourself for more control, and pass the result as a data URL (see EncodeOptions for more details)
    from livekit.agents.utils.images import encode, EncodeOptions, ResizeOptions

    image_bytes = encode(
        event.frame,
        EncodeOptions(
            format="PNG",
            resize_options=ResizeOptions(width=512, height=512, strategy="scale_aspect_fit"),
        ),
    )
    chat_image = ImageContent(
        image=f"data:image/png;base64,{base64.b64encode(image_bytes).decode('utf-8')}"
    )

    # With an external URL
    chat_image = ImageContent(image="https://example.com/image.jpg")
    ```
    c                   C  
   t dS )Nimg_r   	shortuuid r!   r!   a/var/www/html/livekit_bhavya/venv/lib/python3.10/site-packages/livekit/agents/llm/chat_context.py<lambda>C      
 zImageContent.<lambda>default_factorystridimage_contentdefaultzLiteral['image_content']typezstr | rtc.VideoFrameimageN
int | Noneinference_widthinference_heightautozLiteral['auto', 'high', 'low']inference_detail
str | None	mime_typezdict[Any, Any]_cache)__name__
__module____qualname____doc__r   r(   __annotations__r,   r/   r0   r2   r4   r   dictr5   r!   r!   r!   r"   r   $   s    
 r   c                   @  s4   e Zd ZU eddZded< ded< dZded	< dS )
AudioContentaudio_contentr*   zLiteral['audio_content']r,   zlist[rtc.AudioFrame]frameNr3   
transcript)r6   r7   r8   r   r,   r:   r?   r!   r!   r!   r"   r<   c   s   
 r<   )	developersystemuser	assistantr	   ChatRolec                   @  sX   e Zd ZU ded< ded< ded< 	 ded< 	 ded< 	 ded< 	 ded< 	 ded	< d
S )MetricsReportfloatstarted_speaking_atstopped_speaking_attranscription_delayend_of_turn_delayon_user_turn_completed_delayllm_node_ttfttts_node_ttfbe2e_latencyN)r6   r7   r8   r:   r!   r!   r!   r"   rE   n   s   
 rE   F)totalc                   @  s   e Zd ZU edd dZded< dZded< d	ed
< ded< dZded< dZded< ee	dZ
ded< edd dZded< eejdZded< edddZded< ed"d d!ZdS )#ChatMessagec                   C  r   Nitem_r   r!   r!   r!   r"   r#      r$   zChatMessage.<lambda>r%   r'   r(   messagezLiteral['message']r,   rD   rolezlist[ChatContent]contentFboolinterruptedNzfloat | Nonetranscript_confidencedict[str, Any]extrac                   C  s   t  S N)rE   r!   r!   r!   r"   r#      s    rE   metricsrF   
created_atzhash is deprecated)r+   
deprecatedzbytes | Nonehashreturnr3   c                 C  s"   dd | j D }|sdS d|S )z
        Returns a string of all text content in the message.

        Multiple text content items will be joined by a newline.
        c                 S     g | ]	}t |tr|qS r!   )
isinstancer'   .0cr!   r!   r"   
<listcomp>       z,ChatMessage.text_content.<locals>.<listcomp>N
)rU   join)self
text_partsr!   r!   r"   text_content   s   
zChatMessage.text_content)r`   r3   )r6   r7   r8   r   r(   r:   r,   rW   rX   r;   rZ   r\   timer]   r_   propertyrl   r!   r!   r!   r"   rP      s   
 rP   ChatContentc                   @  s|   e Zd ZU edd dZded< dZded< ded	< ded
< ded< eejdZded< ee	dZ
ded< 	 dZded< dS )FunctionCallc                   C  r   rQ   r   r!   r!   r!   r"   r#      r$   zFunctionCall.<lambda>r%   r'   r(   function_callzLiteral['function_call']r,   call_id	argumentsnamerF   r]   rY   rZ   Nr3   group_id)r6   r7   r8   r   r(   r:   r,   rm   r]   r;   rZ   ru   r!   r!   r!   r"   rp      s   
 rp   c                   @  st   e Zd ZU edd dZded< eddZded	< ed
dZded< ded< ded< ded< eejdZ	ded< dS )FunctionCallOutputc                   C  r   rQ   r   r!   r!   r!   r"   r#      r$   zFunctionCallOutput.<lambda>r%   r'   r(   function_call_outputr*   zLiteral['function_call_output']r,    rt   rr   outputrV   is_errorrF   r]   N)
r6   r7   r8   r   r(   r:   r,   rt   rm   r]   r!   r!   r!   r"   rv      s   
 rv   c                   @  s^   e Zd ZU edd dZded< eddZded	< d
Zded< ded< eejdZ	ded< d
S )AgentHandoffc                   C  r   rQ   r   r!   r!   r!   r"   r#      r$   zAgentHandoff.<lambda>r%   r'   r(   agent_handoffr*   zLiteral['agent_handoff']r,   Nr3   old_agent_idnew_agent_idrF   r]   )
r6   r7   r8   r   r(   r:   r,   r}   rm   r]   r!   r!   r!   r"   r{      s   
 r{   c                   @  s   e Zd ZU edd dZded< eddZded	< d
Zded< d
Zded< d
Z	ded< ee
j
dZded< eedZded< d
S )AgentConfigUpdatec                   C  r   rQ   r   r!   r!   r!   r"   r#      r$   zAgentConfigUpdate.<lambda>r%   r'   r(   agent_config_updater*   zLiteral['agent_config_update']r,   Nr3   instructionszlist[str] | Nonetools_addedtools_removedrF   r]   z
list[Tool]_tools)r6   r7   r8   r   r(   r:   r,   r   r   r   rm   r]   r   listr   r!   r!   r!   r"   r      s   
 r   r,   )discriminatorc                   @  s  e Zd ZefdvddZedwddZedxd	d
Zej	dydd
ZdzddZ
eeeeedd{d d!Zd|d$d%Zd}d)d*Zd~d,d-Zd.d.d.d.d.ed/dd8d9Zdd<d=Zd.d.d.d>dd@dAZdBdBdBd.d.d.dCddIdJZedBdKddPdQZedBdKddTdQZedBdKddWdQZedBdKddZdQZedBdKdd\dQZedd`dQZdBdKddbdQZddddeZdfdgddkdlZeddndoZeddpdqZddsdtZduS )ChatContextitemsNotGivenOr[list[ChatItem]]c                 C  s   t |r	|| _d S g | _d S r[   )r   _itemsrj   r   r!   r!   r"   __init__   s   zChatContext.__init__r`   c                 C  s   | g S r[   r!   )clsr!   r!   r"   empty   s   zChatContext.emptylist[ChatItem]c                 C  s   | j S r[   r   rj   r!   r!   r"   r      s   zChatContext.itemsNonec                 C  s
   || _ d S r[   r   r   r!   r!   r"   r      s   
list[ChatMessage]c                 C  s   dd | j D S )zNReturn only chat messages, ignoring function calls, outputs, and other events.c                 S  ra   r!   )rb   rP   rd   itemr!   r!   r"   rf      rg   z(ChatContext.messages.<locals>.<listcomp>r   r   r!   r!   r"   messages   s   zChatContext.messages)r(   rW   r]   r\   rZ   rT   rD   rU   list[ChatContent] | strr(   NotGivenOr[str]rW   NotGivenOr[bool]r]   NotGivenOr[float]r\   NotGivenOr[MetricsReport]rZ   NotGivenOr[dict[str, Any]]rP   c                C  s   i }t |r
||d< t |r||d< t |r||d< t |r"||d< t |r*||d< t|tr;td||gd|}	n
td||d|}	t |rX| j|d}
| j|
|	 |	S | j|	 |	S )	Nr(   rW   r]   r\   rZ   rT   rU   r]   r!   )r   rb   r'   rP   find_insertion_indexr   insertappend)rj   rT   rU   r(   rW   r]   r\   rZ   kwargsrS   idxr!   r!   r"   add_message   s(   
zChatContext.add_messager   ChatItem | Sequence[ChatItem]c                 C  sB   t |tr	t|n|g}|D ]}| j|jd}| j|| qdS )zGInsert an item or list of items into the chat context by creation time.r   N)rb   r   r   r   r]   r   r   )rj   r   r   _itemr   r!   r!   r"   r      s
   zChatContext.insertitem_idr'   ChatItem | Nonec                   s   t  fdd| jD d S )Nc                 3  s    | ]
}|j  kr|V  qd S r[   r(   r   r   r!   r"   	<genexpr>)  s    z(ChatContext.get_by_id.<locals>.<genexpr>)nextr   rj   r   r!   r   r"   	get_by_id(  s   zChatContext.get_by_idr.   c                   s   t  fddt| jD d S )Nc                 3  s"    | ]\}}|j  kr|V  qd S r[   r   )rd   ir   r   r!   r"   r   ,  s     z*ChatContext.index_by_id.<locals>.<genexpr>)r   	enumerater   r   r!   r   r"   index_by_id+  s   zChatContext.index_by_idF)exclude_function_callexclude_instructionsexclude_empty_messageexclude_handoffexclude_config_updatetoolsr   rV   r   r   r   r   r   *NotGivenOr[Sequence[Tool | Toolset | str]]c          
        s   g }ddl m mm d fdd|rt|nt }| jD ]K}	|r.|	jd	v r.q$|r;|	jd
kr;|	jdv r;q$|rF|	jd
krF|	jsFq$|rN|	jdkrNq$|rV|	jdkrVq$t	|rj|	jdksd|	jdkrj|	j
|vrjq$||	 q$t|S )Nr   )FunctionToolRawFunctionToolr   r   Sequence[Tool | Toolset | str]r`   Generator[str, None, None]c                 3  sX    | D ]&}t |tr|V  qt | fr|jjV  qt |r)|jE d H  qqd S r[   )rb   r'   infort   r   )r   toolr   r   r   get_tool_namesr!   r"   r   <  s   

z(ChatContext.copy.<locals>.get_tool_namesrq   rw   rS   rA   r@   r|   r   rq   rw   )r   r   r`   r   )tool_contextr   r   r   setr   r,   rT   rU   r   rt   r   r   )
rj   r   r   r   r   r   r   r   valid_toolsr   r!   r   r"   copy.  s2   




zChatContext.copy	max_itemsintc                  s   t | j|kr	| S tdd | jD d | j| d }|r3|d jdv r3|d |r3|d jdv s% rFt fdd|D sF|d  || jdd< | S )zTruncate the chat context to the last N items in place.

        Removes leading function calls to avoid partial function outputs.
        Preserves the first instruction message (system/developer) by adding it back
        to the beginning.
        c                 s  s(    | ]}|j d kr|jdv r|V  qdS )rS   r   N)r,   rT   r   r!   r!   r"   r   y  s    z'ChatContext.truncate.<locals>.<genexpr>Nr   r   c                 3  s    | ]	}|j  j kV  qd S r[   r   r   r   r!   r"   r     s    )lenr   r   r,   popanyr   )rj   r   	new_itemsr!   r   r"   truncatem  s    	
zChatContext.truncate)r   r   r   other_chat_ctxc                C  s   dd | j D }|jD ]8}|r|jdv rq|r"|jdkr"|jdv r"q|r*|jdkr*q|j|vrC| j|jd}| j || ||j q| S )zkAdd messages from `other_chat_ctx` into this one, avoiding duplicates, and keep items sorted by created_at.c                 S  s   h | ]}|j qS r!   r   r   r!   r!   r"   	<setcomp>  s    z$ChatContext.merge.<locals>.<setcomp>r   rS   r   r   r   )	r   r   r,   rT   r(   r   r]   r   add)rj   r   r   r   r   existing_idsr   r   r!   r!   r"   merge  s"   	



zChatContext.mergeT)exclude_imageexclude_audioexclude_timestampr   exclude_metricsr   r   r   r   r   rY   c          	        s   g }| j D ]6}|r|jdv rq|r|jdkrq|jdkr6| }|r+dd |jD |_|r6dd |jD |_|| qt  |rF d |rM d d	 fd
d|D iS )Nr   r   rS   c                 S     g | ]	}t |ts|qS r!   )rb   r   rc   r!   r!   r"   rf     rg   z'ChatContext.to_dict.<locals>.<listcomp>c                 S  r   r!   )rb   r<   rc   r!   r!   r"   rf     rg   r]   r\   r   c                   s   g | ]}|j d dd dqS )jsonTF)modeexclude_noneexclude_defaultsexclude)
model_dumpr   exclude_fieldsr!   r"   rf     s    )r   r,   
model_copyrU   r   r   r   )	rj   r   r   r   r   r   r   r   r   r!   r   r"   to_dict  s,   




zChatContext.to_dict)inject_dummy_user_messageformat%Literal['openai', 'openai.responses']r    tuple[list[dict], Literal[None]]c                C     d S r[   r!   rj   r   r   r!   r!   r"   to_provider_format  s   zChatContext.to_provider_formatLiteral['google'];tuple[list[dict], _provider_format.google.GoogleFormatData]c                C  r   r[   r!   r   r!   r!   r"   r        Literal['aws']9tuple[list[dict], _provider_format.aws.BedrockFormatData]c                C  r   r[   r!   r   r!   r!   r"   r     r   Literal['anthropic']Atuple[list[dict], _provider_format.anthropic.AnthropicFormatData]c                C  r   r[   r!   r   r!   r!   r"   r     r   Literal['mistralai']c                C  r   r[   r!   r   r!   r!   r"   r     r   r   r   tuple[list[dict], Any]c                 K  r   r[   r!   )rj   r   r   r!   r!   r"   r     s   VLiteral['openai', 'openai.responses', 'google', 'aws', 'anthropic', 'mistralai'] | strc                K  s   ||d< |dkrt jj| fi |S |dkr t jj| fi |S |dkr.t jj| fi |S |dkr<t jj| fi |S |dkrJt jj| fi |S |dkrXt jj| fi |S td| )	ab  Convert the chat context to a provider-specific format.

        If ``inject_dummy_user_message`` is ``True``, a dummy user message will be added
        to the beginning or end of the chat context depending on the provider.

        This is necessary because some providers expect a user message to be present for
        generating a response.
        r   openaizopenai.responsesgoogleaws	anthropic	mistralaizUnsupported provider format: )	r   r   to_chat_ctxto_responses_chat_ctxr   r   r   r   
ValueError)rj   r   r   r   r!   r!   r"   r     s   rF   c                C  s8   t tt| jD ]}| j| j|kr|d   S q	dS )z
        Returns the index to insert an item by creation time.

        Iterates in reverse, assuming items are sorted by `created_at`.
        Finds the position after the last item with `created_at <=` the given timestamp.
        r   r   )reversedranger   r   r]   )rj   r]   r   r!   r!   r"   r   #  s
   z ChatContext.find_insertion_indexr   )keep_last_turnsllm_vr   r   c             	     s4  g }|   D ]}|jdvrq|jddu rq|jpd }|r&|| q|s+| S tdtt	||d }|dkrA|g }}n|d |  || d  }}|sT| S d
dd	 |D  }	|	sd| S t }
|
jd
dd |
jdd|	 d g }|j|
d4 I d H #}|2 z3 d H W }|jr|jjr||jj q6 W d   I d H  n1 I d H sw   Y  d
| }|s| S |r|d jntd}g }| jD ]}|jdv r|j|k rq|jdkr|jdv rq|| q|| _|r|d jd n|d jd }| jdd| |ddid |D ]	}| j| q| S )N)rB   rC   
is_summaryTrx   r   r   rh   c                 s  s*    | ]}|j  d |jpd  V  qdS )z: rx   N)rT   rl   strip)rd   mr!   r!   r"   r   L  s   ( z)ChatContext._summarize.<locals>.<genexpr>rA   zCompress older chat history into a short, faithful summary.
Focus on user goals, constraints, decisions, key facts/preferences/entities, and pending tasks.
Exclude chit-chat and greetings. Be concise.r   rB   zConversation to summarize:

)chat_ctxinfr   rS   gư>rC   z[history summary]
)rT   rU   r]   rZ   )r   rT   rZ   getrl   r  r   maxminr   ri   r   r   chatdeltarU   r]   rF   r   r,   r   )rj   r   r   to_summarizemsgtexttail_nheadtailsource_textr  chunksstreamchunksummarytail_start_ts	preserveditcreated_at_hintr!   r!   r"   
_summarize0  s|   

(


 zChatContext._summarizedatac                 C  s"   t tt }||d }| |S )Nr   )r   r   ChatItemvalidate_python)r   r  item_adapterr   r!   r!   r"   	from_dict  s   zChatContext.from_dictc                 C     dS )NFr!   r   r!   r!   r"   readonly     zChatContext.readonlyotherc                 C  s,  | |u rdS t | jt |jkrdS t| j|jddD ]x\}}|j|jks+|j|jkr. dS |jdkrN|jdkrN|j|jksJ|j|jksJ|j|jkrM dS q|jdkrn|jdkrn|j|jksj|j	|j	ksj|j
|j
krm dS q|jdkr|jdkr|j|jks|j	|j	ks|j|jks|j|jkr dS qdS )a  
        Return True if `other` has the same sequence of items with matching
        essential fields (IDs, types, and payload) as this context.

        Comparison rules:
          - Messages: compares the full `content` list, `role` and `interrupted`.
          - Function calls: compares `name`, `call_id`, and `arguments`.
          - Function call outputs: compares `name`, `call_id`, `output`, and `is_error`.

        Does not consider timestamps or other metadata.
        TF)strictrS   rq   rw   )r   r   zipr(   r,   rT   rW   rU   rt   rr   rs   ry   rz   )rj   r#  abr!   r!   r"   is_equivalent  s.   $$zChatContext.is_equivalentN)r   r   )r`   r   r`   r   )r   r   r`   r   )r`   r   )rT   rD   rU   r   r(   r   rW   r   r]   r   r\   r   rZ   r   r`   rP   )r   r   r`   r   )r   r'   r`   r   )r   r'   r`   r.   )r   rV   r   rV   r   rV   r   rV   r   rV   r   r   r`   r   )r   r   r`   r   )
r   r   r   rV   r   rV   r   rV   r`   r   )r   rV   r   rV   r   rV   r   rV   r   rV   r   rV   r`   rY   )r   r   r   rV   r`   r   )r   r   r   rV   r`   r   )r   r   r   rV   r`   r   )r   r   r   rV   r`   r   )r   r   r   rV   r`   r   )r   r'   r   r   r`   r   )r   r   r   rV   r   r   r`   r   )r]   rF   r`   r   )r   r   r   r   r`   r   )r  rY   r`   r   r`   rV   )r#  r   r`   rV   )r6   r7   r8   r   r   classmethodr   rn   r   setterr   r   r   r   r   r   r   r   r   r
   r   r   r  r  r!  r(  r!   r!   r!   r"   r      s    
	
#


?'&0
!Vr   c                   @  s@   e Zd ZdZdZG dd dee ZdddZe	dddZ
dS )_ReadOnlyChatContextz@A read-only wrapper for ChatContext that prevents modifications.zttrying to modify a read-only chat context, please use .copy() and agent.update_chat_ctx() to modify the chat contextc                   @  sL   e Zd ZdddZe Z Z Z Z Z Z	Z
e Z Z ZZdd	d
ZdS )z#_ReadOnlyChatContext._ImmutableListargsr   r   r`   r   c                 O  s   t tj ttjr[   )r   errorr-  	error_msgRuntimeError)rj   r.  r   r!   r!   r"   _raise_error  s   
z0_ReadOnlyChatContext._ImmutableList._raise_errorr   c                 C  s   t | S r[   )r   r   r!   r!   r"   r     s   z(_ReadOnlyChatContext._ImmutableList.copyN)r.  r   r   r   r`   r   r)  )r6   r7   r8   r2  r   extendr   removeclearsortreverse__setitem____delitem____iadd____imul__r   r!   r!   r!   r"   _ImmutableList  s
    
r<  r   r   c                 C  s   |  || _d S r[   )r<  r   r   r!   r!   r"   r     s   z_ReadOnlyChatContext.__init__r`   rV   c                 C  r   )NTr!   r   r!   r!   r"   r!    r"  z_ReadOnlyChatContext.readonlyN)r   r   r*  )r6   r7   r8   r9   r0  r   r  r<  r   rn   r!  r!   r!   r!   r"   r-    s    
r-  )3
__future__r   rm   collections.abcr   r   typingr   r   r   r   r	   r
   pydanticr   r   r   r   typing_extensionsr   livekitr   rx   r   logr   typesr   r   
utils.miscr   r   llmr   r   r   r   r<   rD   r:   rE   rP   r'   ro   rp   rv   r{   r   r  r   r-  r!   r!   r!   r"   <module>   sD    ?)
   T