§
    œŠtjà9  ã                  óü   — d Z ddlmZ ddlZddlZddlZddl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 ddlmZmZmZmZ erdd	lmZmZ dd
lmZ ddlmZ ddlmZ  G d„ deee         eef         ¦  «        Z dS )z!Tool retry middleware for agents.é    )ÚannotationsN)ÚTYPE_CHECKINGÚAny)ÚToolMessage)ÚGraphBubbleUp)Ú	OnFailureÚRetryOnÚcalculate_delayÚshould_retry_exceptionÚvalidate_retry_params)ÚAgentMiddlewareÚ
AgentStateÚContextTÚ	ResponseT)Ú	AwaitableÚCallable)ÚCommand)ÚToolCallRequest)ÚBaseToolc            	      ór   ‡ — e Zd ZdZddefdddddd	œd.ˆ fd„Zd/d„Zed0d!„¦   «         Zd1d%„Z	d2d+„Z
d3d-„Zˆ xZS )4ÚToolRetryMiddlewarea  Middleware that automatically retries failed tool calls with configurable backoff.

    Supports retrying on specific exceptions and exponential backoff.

    Examples:
        !!! example "Basic usage with default settings (2 retries, exponential backoff)"

            ```python
            from langchain.agents import create_agent
            from langchain.agents.middleware import ToolRetryMiddleware

            agent = create_agent(model, tools=[search_tool], middleware=[ToolRetryMiddleware()])
            ```

        !!! example "Retry specific exceptions only"

            ```python
            from requests.exceptions import RequestException, Timeout

            retry = ToolRetryMiddleware(
                max_retries=4,
                retry_on=(RequestException, Timeout),
                backoff_factor=1.5,
            )
            ```

        !!! example "Custom exception filtering"

            ```python
            from requests.exceptions import HTTPError


            def should_retry(exc: Exception) -> bool:
                # Only retry on 5xx errors
                if isinstance(exc, HTTPError):
                    return 500 <= exc.status_code < 600
                return False


            retry = ToolRetryMiddleware(
                max_retries=3,
                retry_on=should_retry,
            )
            ```

        !!! example "Apply to specific tools with custom error handling"

            ```python
            def format_error(exc: Exception) -> str:
                return "Database temporarily unavailable. Please try again later."


            retry = ToolRetryMiddleware(
                max_retries=4,
                tools=["search_database"],
                on_failure=format_error,
            )
            ```

        !!! example "Apply to specific tools using `BaseTool` instances"

            ```python
            from langchain_core.tools import tool


            @tool
            def search_database(query: str) -> str:
                '''Search the database.'''
                return results


            retry = ToolRetryMiddleware(
                max_retries=4,
                tools=[search_database],  # Pass BaseTool instance
            )
            ```

        !!! example "Constant backoff (no exponential growth)"

            ```python
            retry = ToolRetryMiddleware(
                max_retries=5,
                backoff_factor=0.0,  # No exponential growth
                initial_delay=2.0,  # Always wait 2 seconds
            )
            ```

        !!! example "Raise exception on failure"

            ```python
            retry = ToolRetryMiddleware(
                max_retries=2,
                on_failure="error",  # Re-raise exception instead of returning message
            )
            ```
    é   NÚcontinueg       @g      ð?g      N@T)Úmax_retriesÚtoolsÚretry_onÚ
on_failureÚbackoff_factorÚinitial_delayÚ	max_delayÚjitterr   Úintr   úlist[BaseTool | str] | Noner   r	   r   r   r   Úfloatr   r    r!   ÚboolÚreturnÚNonec               ó°  •— t          ¦   «                              ¦   «          t          ||||¦  «         |dk    r!d}	t          j        |	t
          d¬¦  «         d}n&|dk    r d}	t          j        |	t
          d¬¦  «         d}|| _        |  |�d
„ |D ¦   «         | _        nd	| _        g | _        || _	        || _
        || _        || _        || _        || _        d	S )uv  Initialize `ToolRetryMiddleware`.

        Args:
            max_retries: Maximum number of retry attempts after the initial call.

                Must be `>= 0`.
            tools: Optional list of tools or tool names to apply retry logic to.

                Can be a list of `BaseTool` instances or tool name strings.

                If `None`, applies to all tools.
            retry_on: Either a tuple of exception types to retry on, or a callable
                that takes an exception and returns `True` if it should be retried.

                Default is to retry on all exceptions.
            on_failure: Behavior when all retries are exhausted.

                Options:

                - `'continue'`: Return a `ToolMessage` with error details,
                    allowing the LLM to handle the failure and potentially recover.
                - `'error'`: Re-raise the exception, stopping agent execution.
                - **Custom callable:** Function that takes the exception and returns a
                    string for the `ToolMessage` content, allowing custom error
                    formatting.

                **Deprecated values** (for backwards compatibility):

                - `'return_message'`: Use `'continue'` instead.
                - `'raise'`: Use `'error'` instead.
            backoff_factor: Multiplier for exponential backoff.

                Each retry waits `initial_delay * (backoff_factor ** retry_number)`
                seconds.

                Set to `0.0` for constant delay.
            initial_delay: Initial delay in seconds before first retry.
            max_delay: Maximum delay in seconds between retries.

                Caps exponential backoff growth.
            jitter: Whether to add random jitter (`Â±25%`) to delay to avoid thundering herd.

        Raises:
            ValueError: If `max_retries < 0` or delays are negative.
        Úraisezion_failure='raise' is deprecated and will be removed in a future version. Use on_failure='error' instead.r   )Ú
stacklevelÚerrorÚreturn_messagezuon_failure='return_message' is deprecated and will be removed in a future version. Use on_failure='continue' instead.r   Nc                óJ   — g | ] }t          |t          ¦  «        s|j        n|‘Œ!S © )Ú
isinstanceÚstrÚname)Ú.0Útools     úd/var/www/html/CA-Chatbot/venv/lib/python3.11/site-packages/langchain/agents/middleware/tool_retry.pyú
<listcomp>z0ToolRetryMiddleware.__init__.<locals>.<listcomp>Ô   s.   € Ð dÐ dÐ dÐVZµ*¸TÅ3Ñ2GÔ2GÐ!Q ¤ ÈTÐ dÐ dÐ dó    )ÚsuperÚ__init__r   ÚwarningsÚwarnÚDeprecationWarningr   Ú_tool_filterr   r   r   r   r   r    r!   )Úselfr   r   r   r   r   r   r    r!   ÚmsgÚ	__class__s             €r4   r8   zToolRetryMiddleware.__init__�   s  ø€ õr 	‰Œ×ÒÑÔÐõ 	˜k¨=¸)À^ÑTÔTÐTð ˜Ò Ð ð2ð õ ŒM˜#Õ1¸aÐ@Ñ@Ô@Ð@Ø ˆJˆJØÐ+Ò+Ð+ðJð õ ŒM˜#Õ1¸aÐ@Ñ@Ô@Ð@Ø#ˆJà&ˆÔð 	Ð+ØÐØ dÐ dÐ^cÐ dÑ dÔ dˆDÔÐà $ˆDÔàˆŒ
Ø ˆŒØ$ˆŒØ,ˆÔØ*ˆÔØ"ˆŒØˆŒˆˆr6   Ú	tool_namer0   c                ó&   — | j         €dS || j         v S )zÒCheck if retry logic should apply to this tool.

        Args:
            tool_name: Name of the tool being called.

        Returns:
            `True` if retry logic should apply, `False` otherwise.
        NT)r<   )r=   r@   s     r4   Ú_should_retry_toolz&ToolRetryMiddleware._should_retry_toolà   s    € ð ÔÐ$Ø�4Ø˜DÔ-Ð-Ð-r6   ÚexcÚ	ExceptionÚattempts_madec                ó€   — t          |¦  «        j        }t          |¦  «        }|dk    rdnd}d| › d|› d|› d|› d|› d	�S )
a6  Format the failure message when retries are exhausted.

        Args:
            tool_name: Name of the tool that failed.
            exc: The exception that caused the failure.
            attempts_made: Number of attempts actually made.

        Returns:
            Formatted error message string.
        é   ÚattemptÚattemptszTool 'z' failed after ú z with z: z. Please try again.)ÚtypeÚ__name__r0   )r@   rC   rE   Úexc_typeÚexc_msgÚattempt_words         r4   Ú_format_failure_messagez+ToolRetryMiddleware._format_failure_messageí   s}   € õ ˜‘9”9Ô%ˆÝ�c‘(”(ˆØ$1°QÒ$6Ð$6�y�y¸Jˆð=�Yð =ð =¨}ð =ð =¸|ð =ð =Øð=ð =Ø 'ð=ð =ð =ð	
r6   Útool_call_idú
str | Noner   c                óÄ   — | j         dk    r|‚t          | j         ¦  «        r|                       |¦  «        }n|                      |||¦  «        }t          |||d¬¦  «        S )aÎ  Handle failure when all retries are exhausted.

        Args:
            tool_name: Name of the tool that failed.
            tool_call_id: ID of the tool call (may be `None`).
            exc: The exception that caused the failure.
            attempts_made: Number of attempts actually made.

        Returns:
            `ToolMessage` with error details.

        Raises:
            Exception: If `on_failure` is `'error'`, re-raises the exception.
        r+   )ÚcontentrQ   r1   Ústatus)r   ÚcallablerP   r   )r=   r@   rQ   rC   rE   rT   s         r4   Ú_handle_failurez#ToolRetryMiddleware._handle_failure  sv   € ð" Œ?˜gÒ%Ð%ØˆIå�D”OÑ$Ô$ð 	RØ—o’o cÑ*Ô*ˆGˆGà×2Ò2°9¸cÀ=ÑQÔQˆGåØØ%ØØð	
ñ 
ô 
ð 	
r6   Úrequestr   Úhandlerú7Callable[[ToolCallRequest], ToolMessage | Command[Any]]úToolMessage | Command[Any]c           	     ó^  — |j         r|j         j        n|j        d         }|                      |¦  «        s ||¦  «        S |j        d         }t	          | j        dz   ¦  «        D ]¸}	  ||¦  «        c S # t          $ r ‚ t          $ r’}|dz   }t          || j	        ¦  «        s‚ || j        k     rCt          || j        | j        | j        | j        ¬¦  «        }|dk    rt          j        |¦  «         n|                      ||||¦  «        cY d}~c S Y d}~Œ±d}~ww xY wd}	t%          |	¦  «        ‚)a®  Intercept tool execution and retry on failure.

        Args:
            request: Tool call request with call dict, `BaseTool`, state, and runtime.
            handler: Callable to execute the tool (can be called multiple times).

        Returns:
            `ToolMessage` or `Command` (the final result).

        Raises:
            RuntimeError: If the retry loop completes without returning. This should not happen.
        r1   ÚidrG   ©r   r   r    r!   r   Nú2Unexpected: retry loop completed without returning)r3   r1   Ú	tool_callrB   Úranger   r   rD   r   r   r
   r   r   r    r!   ÚtimeÚsleeprW   ÚRuntimeError©
r=   rX   rY   r@   rQ   rH   rC   rE   Údelayr>   s
             r4   Úwrap_tool_callz"ToolRetryMiddleware.wrap_tool_call!  s—  € ð" *1¬ÐT�G”LÔ%Ð%¸7Ô;LÈVÔ;Tˆ	ð ×&Ò& yÑ1Ô1ð 	$Ø�7˜7Ñ#Ô#Ð#àÔ(¨Ô.ˆõ ˜TÔ-°Ñ1Ñ2Ô2ð 	]ð 	]ˆGð]Ø�w˜wÑ'Ô'Ð'Ð'Ð'øÝ ð ð ð ð Ýð ]ð ]ð ]Ø '¨!¡�õ .¨c°4´=ÑAÔAð àð ˜TÔ-Ò-Ð-å+ØØ'+Ô':Ø&*Ô&8Ø"&¤.Ø#œ{ðñ ô �Eð ˜q’y�yÝœ
 5Ñ)Ô)Ð)øð  ×/Ò/°	¸<ÈÈmÑ\Ô\Ð\Ð\Ð\Ð\Ð\Ð\Ð\Ð\øøøøøøøøøð/]øøøð4 CˆÝ˜3ÑÔÐs   Á(
A5Á5DÂ	B DÄ	DÄDúBCallable[[ToolCallRequest], Awaitable[ToolMessage | Command[Any]]]c           	   ƒ  ó†  K  — |j         r|j         j        n|j        d         }|                      |¦  «        s ||¦  «        ƒ d{V —†S |j        d         }t	          | j        dz   ¦  «        D ]Ä}	  ||¦  «        ƒ d{V —†c S # t          $ r ‚ t          $ r˜}|dz   }t          || j	        ¦  «        s‚ || j        k     rIt          || j        | j        | j        | j        ¬¦  «        }|dk    rt          j        |¦  «        ƒ d{V —† n|                      ||||¦  «        cY d}~c S Y d}~Œ½d}~ww xY wd}	t%          |	¦  «        ‚)aÌ  Intercept and control async tool execution with retry logic.

        Args:
            request: Tool call request with call `dict`, `BaseTool`, state, and runtime.
            handler: Async callable to execute the tool and returns `ToolMessage` or `Command`.

        Returns:
            `ToolMessage` or `Command` (the final result).

        Raises:
            RuntimeError: If the retry loop completes without returning. This should not happen.
        r1   Nr]   rG   r^   r   r_   )r3   r1   r`   rB   ra   r   r   rD   r   r   r
   r   r   r    r!   Úasynciorc   rW   rd   re   s
             r4   Úawrap_tool_callz#ToolRetryMiddleware.awrap_tool_call_  sÑ  è è € ð" *1¬ÐT�G”LÔ%Ð%¸7Ô;LÈVÔ;Tˆ	ð ×&Ò& yÑ1Ô1ð 	*Ø ˜ Ñ)Ô)Ð)Ð)Ð)Ð)Ð)Ð)Ð)àÔ(¨Ô.ˆõ ˜TÔ-°Ñ1Ñ2Ô2ð 	]ð 	]ˆGð]Ø$˜W WÑ-Ô-Ð-Ð-Ð-Ð-Ð-Ð-Ð-Ð-Ð-øÝ ð ð ð ð Ýð ]ð ]ð ]Ø '¨!¡�õ .¨c°4´=ÑAÔAð àð ˜TÔ-Ò-Ð-å+ØØ'+Ô':Ø&*Ô&8Ø"&¤.Ø#œ{ðñ ô �Eð ˜q’y�yÝ%œm¨EÑ2Ô2Ð2Ð2Ð2Ð2Ð2Ð2Ð2øð  ×/Ò/°	¸<ÈÈmÑ\Ô\Ð\Ð\Ð\Ð\Ð\Ð\Ð\Ð\øøøøøøøøøð/]øøøð4 CˆÝ˜3ÑÔÐs   Á0BÂD/ÂBD*ÄD/Ä*D/)r   r"   r   r#   r   r	   r   r   r   r$   r   r$   r    r$   r!   r%   r&   r'   )r@   r0   r&   r%   )r@   r0   rC   rD   rE   r"   r&   r0   )
r@   r0   rQ   rR   rC   rD   rE   r"   r&   r   )rX   r   rY   rZ   r&   r[   )rX   r   rY   rh   r&   r[   )rL   Ú
__module__Ú__qualname__Ú__doc__rD   r8   rB   ÚstaticmethodrP   rW   rg   rk   Ú__classcell__)r?   s   @r4   r   r      së   ø€ € € € € ð_ð _ðH Ø-1Ø&˜LØ *Ø #Ø"ØØð]ð ]ð ]ð ]ð ]ð ]ð ]ð ]ð~.ð .ð .ð .ð ð
ð 
ð 
ñ „\ð
ð&
ð 
ð 
ð 
ð@< ð < ð < ð < ð|< ð < ð < ð < ð < ð < ð < ð < r6   r   )!rn   Ú
__future__r   rj   rb   r9   Útypingr   r   Úlangchain_core.messagesr   Úlanggraph.errorsr   Ú"langchain.agents.middleware._retryr   r	   r
   r   r   Ú!langchain.agents.middleware.typesr   r   r   r   Úcollections.abcr   r   Úlanggraph.typesr   r   Úlangchain.toolsr   r   r.   r6   r4   ú<module>rz      s†  ðØ 'Ð 'à "Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø %Ð %Ð %Ð %Ð %Ð %Ð %Ð %à /Ð /Ð /Ð /Ð /Ð /Ø *Ð *Ð *Ð *Ð *Ð *ðð ð ð ð ð ð ð ð ð ð ð ð ð ð _Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^àð )Ø3Ð3Ð3Ð3Ð3Ð3Ð3Ð3à'Ð'Ð'Ð'Ð'Ð'àAÐAÐAÐAÐAÐAØ(Ð(Ð(Ð(Ð(Ð(ð| ð | ð | ð | ð | ˜/¨*°YÔ*?ÀÈ9Ð*TÔUñ | ô | ð | ð | ð | r6   