o
    iM                     @  s   d Z ddlmZ ddlmZ ddlmZmZ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 dd	lmZ eZ	 eeB Z	 eG d
d dZdS )a  This module provides functionality to manage and update parts of a model's streamed response.

The manager tracks which parts (in particular, text and tool calls) correspond to which
vendor-specific identifiers (e.g., `index`, `tool_call_id`, etc., as appropriate for a given model),
and produces Pydantic AI-format events as appropriate for consumers of the streaming APIs.

The "vendor-specific identifiers" to use depend on the semantics of the responses of the responses from the vendor,
and are tightly coupled to the specific model being used, and the Pydantic AI Model subclass implementation.

This `ModelResponsePartsManager` is used in each of the subclasses of `StreamedResponse` as a way to consolidate
event-emitting logic.
    )annotations)Hashable)	dataclassfieldreplace)Any)UnexpectedModelBehavior)BuiltinToolCallPartModelResponsePartModelResponseStreamEventPartDeltaEventPartStartEventTextPartTextPartDeltaThinkingPartThinkingPartDeltaToolCallPartToolCallPartDelta   )generate_tool_call_idc                   @  s   e Zd ZU dZeeddZded< 	 eeddZ	ded< 	 d0d
dZ
ddddd1ddZdddddd2d d!Zdddd"d3d'd(Zddd)d4d*d+Zd5d.d/ZdS )6ModelResponsePartsManagerzManages a sequence of parts that make up a model's streamed response.

    Parts are generally added and/or updated by providing deltas, which are tracked by vendor-specific IDs.
    F)default_factoryinitzlist[ManagedPart]_partszdict[VendorId, int]_vendor_id_to_part_indexreturnlist[ModelResponsePart]c                 C  s   dd | j D S )zReturn only model response parts that are complete (i.e., not ToolCallPartDelta's).

        Returns:
            A list of ModelResponsePart objects. ToolCallPartDelta objects are excluded.
        c                 S  s   g | ]	}t |ts|qS  )
isinstancer   ).0pr   r   `/var/www/html/karishye-ai-python/venv/lib/python3.10/site-packages/pydantic_ai/_parts_manager.py
<listcomp>D   s    z7ModelResponsePartsManager.get_parts.<locals>.<listcomp>)r   )selfr   r   r!   	get_parts>   s   z#ModelResponsePartsManager.get_partsN)idthinking_tagsignore_leading_whitespacevendor_part_idVendorId | Nonecontentstrr%   
str | Noner&   tuple[str, str] | Noner'   boolModelResponseStreamEvent | Nonec                C  st  d}|du r| j rt| j d }| j | }t|tr||f}n<| j|}|dur[| j | }	|rJt|	trJ||d krC| j| dS | j||dS t|	trT|	|f}nt	d|	|rq||d krq| j|d | j|ddS |du r|rt|dks|
 rdS t| j }
t||d}|dur|
| j|< | j | t|
|dS |\}}t|d	}||| j |< t||d
S )a  Handle incoming text content, creating or updating a TextPart in the manager as appropriate.

        When `vendor_part_id` is None, the latest part is updated if it exists and is a TextPart;
        otherwise, a new TextPart is created. When a non-None ID is specified, the TextPart corresponding
        to that vendor ID is either created or updated.

        Args:
            vendor_part_id: The ID the vendor uses to identify this piece
                of text. If None, a new part will be created unless the latest part is already
                a TextPart.
            content: The text content to append to the appropriate TextPart.
            id: An optional id for the text part.
            thinking_tags: If provided, will handle content between the thinking tags as thinking parts.
            ignore_leading_whitespace: If True, will ignore leading whitespace in the content.

        Returns:
            - A `PartStartEvent` if a new part was created.
            - A `PartDeltaEvent` if an existing part was updated.
            - `None` if no new event is emitted (e.g., the first text part was all whitespace).

        Raises:
            UnexpectedModelBehavior: If attempting to apply text content to a part that is not a TextPart.
        Nr   )r(   r*   z+Cannot apply a text delta to existing_part=r    )r*   r%   indexpart)content_deltar2   delta)r   lenr   r   r   getr   pophandle_thinking_deltar   isspaceappendr   r   applyr   )r#   r(   r*   r%   r&   r'   existing_text_part_and_index
part_indexlatest_partexisting_partnew_part_indexr3   existing_text_part
part_deltar   r   r!   handle_text_deltaF   sF    







z+ModelResponsePartsManager.handle_text_deltar*   r%   	signatureprovider_nameHashable | NonerG   rH   r   c                C  s.  d}|du r| j rt| j d }| j | }t|tr||f}n| j|}|dur>| j | }	t|	ts:td|	|	|f}|du rr|dusJ|durnt| j }
t|pSd|||d}|durb|
| j|< | j | t|
|dS td|dusz|dur|\}}t	|||d}|
|| j |< t||d	S td
)a  Handle incoming thinking content, creating or updating a ThinkingPart in the manager as appropriate.

        When `vendor_part_id` is None, the latest part is updated if it exists and is a ThinkingPart;
        otherwise, a new ThinkingPart is created. When a non-None ID is specified, the ThinkingPart corresponding
        to that vendor ID is either created or updated.

        Args:
            vendor_part_id: The ID the vendor uses to identify this piece
                of thinking. If None, a new part will be created unless the latest part is already
                a ThinkingPart.
            content: The thinking content to append to the appropriate ThinkingPart.
            id: An optional id for the thinking part.
            signature: An optional signature for the thinking content.
            provider_name: An optional provider name for the thinking part.

        Returns:
            A `PartStartEvent` if a new part was created, or a `PartDeltaEvent` if an existing part was updated.

        Raises:
            UnexpectedModelBehavior: If attempting to apply a thinking delta to a part that is not a ThinkingPart.
        Nr   z/Cannot apply a thinking delta to existing_part=r0   rF   r1   z9Cannot create a ThinkingPart with no content or signature)r4   signature_deltarH   r5   z9Cannot update a ThinkingPart with no content or signature)r   r7   r   r   r   r8   r   r<   r   r   r=   r   )r#   r(   r*   r%   rG   rH    existing_thinking_part_and_indexr?   r@   rA   rB   r3   existing_thinking_partrD   r   r   r!   r:      s>   





z/ModelResponsePartsManager.handle_thinking_delta)	tool_nameargstool_call_idrM   rN   str | dict[str, Any] | NonerO   c                C  sz  d}|du r'|du r&| j r&t| j d }| j | }t|ttB tB r&||f}n#| j|}|durJ| j | }t|ttB tB sFtd|||f}|du rt|||d}	|		 pZ|	}
|durgt| j | j|< t| j }| j 
|
 t|
ttB rt||
dS dS |\}}t|||d}	|	|}|| j |< t|ttB rt|trt||dS |jr|	jst|	|jd}	t||	dS dS )at  Handle or update a tool call, creating or updating a `ToolCallPart`, `BuiltinToolCallPart`, or `ToolCallPartDelta`.

        Managed items remain as `ToolCallPartDelta`s until they have at least a tool_name, at which
        point they are upgraded to `ToolCallPart`s.

        If `vendor_part_id` is None, updates the latest matching ToolCallPart (or ToolCallPartDelta)
        if any. Otherwise, a new part (or delta) may be created.

        Args:
            vendor_part_id: The ID the vendor uses for this tool call.
                If None, the latest matching tool call may be updated.
            tool_name: The name of the tool. If None, the manager does not enforce
                a name match when `vendor_part_id` is None.
            args: Arguments for the tool call, either as a string, a dictionary of key-value pairs, or None.
            tool_call_id: An optional string representing an identifier for this tool call.

        Returns:
            - A `PartStartEvent` if a new ToolCallPart or BuiltinToolCallPart is created.
            - A `PartDeltaEvent` if an existing part is updated.
            - `None` if no new event is emitted (e.g., the part is still incomplete).

        Raises:
            UnexpectedModelBehavior: If attempting to apply a tool call delta to a part that is not
                a ToolCallPart, BuiltinToolCallPart, or ToolCallPartDelta.
        Nr   z0Cannot apply a tool call delta to existing_part=)tool_name_delta
args_deltarO   r1   )rO   r5   )r   r7   r   r   r	   r   r   r8   r   as_partr<   r   r=   rO   r   r   )r#   r(   rM   rN   rO    existing_matching_part_and_indexr?   r@   rA   r6   r3   rB   updated_partr   r   r!   handle_tool_call_delta   sH   "





z0ModelResponsePartsManager.handle_tool_call_delta)rO   r%   c          	      C  s   t |||pt |d}|du rt| j}| j| n*| j|}|dur5t| j| t r5|}|| j|< nt| j}| j| || j|< t||dS )a4  Immediately create or fully-overwrite a ToolCallPart with the given information.

        This does not apply a delta; it directly sets the tool call part contents.

        Args:
            vendor_part_id: The vendor's ID for this tool call part. If not
                None and an existing part is found, that part is overwritten.
            tool_name: The name of the tool being invoked.
            args: The arguments for the tool call, either as a string, a dictionary, or None.
            tool_call_id: An optional string identifier for this tool call.
            id: An optional identifier for this tool call part.

        Returns:
            ModelResponseStreamEvent: A `PartStartEvent` indicating that a new tool call part
            has been added to the manager, or replaced an existing part.
        )rM   rN   rO   r%   Nr1   )	r   _generate_tool_call_idr7   r   r<   r   r8   r   r   )	r#   r(   rM   rN   rO   r%   new_partrB   maybe_part_indexr   r   r!   handle_tool_call_part4  s"   


z/ModelResponsePartsManager.handle_tool_call_partr3   r
   c                C  s   |du rt | j}| j| n,| j|}|dur,t| j| t|r,|}|| j|< nt | j}| j| || j|< t||dS )a  Create or overwrite a ModelResponsePart.

        Args:
            vendor_part_id: The vendor's ID for this tool call part. If not
                None and an existing part is found, that part is overwritten.
            part: The ModelResponsePart.

        Returns:
            ModelResponseStreamEvent: A `PartStartEvent` indicating that a new part
            has been added to the manager, or replaced an existing part.
        Nr1   )r7   r   r<   r   r8   r   typer   )r#   r(   r3   rB   rY   r   r   r!   handle_partc  s   


z%ModelResponsePartsManager.handle_part)r   r   )r(   r)   r*   r+   r%   r,   r&   r-   r'   r.   r   r/   )r(   rI   r*   r,   r%   r,   rG   r,   rH   r,   r   r   )
r(   rI   rM   r,   rN   rP   rO   r,   r   r/   )r(   rI   rM   r+   rN   rP   rO   r,   r%   r,   r   r   )r(   rI   r3   r
   r   r   )__name__
__module____qualname____doc__r   listr   __annotations__dictr   r$   rE   r:   rV   rZ   r\   r   r   r   r!   r   2   s0   
 
YKX/r   N) r`   
__future__r   _annotationscollections.abcr   dataclassesr   r   r   typingr   pydantic_ai.exceptionsr   pydantic_ai.messagesr	   r
   r   r   r   r   r   r   r   r   r   _utilsr   rW   VendorIdManagedPartr   r   r   r   r!   <module>   s    4