
    OKi8                        S r SSKJr  SSKrSSKrSSKrSSKJrJr  SSK	J
r
  SSKJrJrJrJrJr  SSKJrJrJrJr  \(       a  SSKJrJr  SS	KJr  SS
KJr  SSKJr   " S S\\\   \\4   5      rg)z!Tool retry middleware for agents.    )annotationsN)TYPE_CHECKINGAny)ToolMessage)	OnFailureRetryOncalculate_delayshould_retry_exceptionvalidate_retry_params)AgentMiddleware
AgentStateContextT	ResponseT)	AwaitableCallable)Command)ToolCallRequest)BaseToolc            	         ^  \ rS rSrSrSS\4SSSSS	S
.                 SU 4S jjjrSS jr\SS j5       r	          SS jr
      SS jr      SS jrSrU =r$ )ToolRetryMiddleware   a	  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jitterc                 > [         TU ]  5         [        XXu5        US:X  a  Sn	[        R                  " U	[
        SS9  SnO$US:X  a  Sn	[        R                  " U	[
        SS9  SnXl        U   Ub:  U V
s/ s H&  n
[        U
[        5      (       d  U
R                  OU
PM(     sn
U l
        OS	U l
        / U l        X0l        X@l        XPl        X`l        Xpl        Xl        g	s  sn
f )
u~  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   N)super__init__r   warningswarnDeprecationWarningr   
isinstancestrname_tool_filterr   r   r   r   r   r    r!   )selfr   r   r   r   r   r   r    r!   msgtool	__class__s              h/var/www/html/dynamic-report/venv/lib/python3.13/site-packages/langchain/agents/middleware/tool_retry.pyr(   ToolRetryMiddleware.__init__   s    r 	 	k)T  2  MM#1a@ J++J  MM#1a@#J& 	^c d^cVZ*T32G2GT!Q^c dD $D
 $,*" !es   4-Cc                :    U R                   c  gXR                   ;   $ )zCheck 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.
T)r/   )r0   	tool_names     r4   _should_retry_tool&ToolRetryMiddleware._should_retry_tool   s"     $----    c                z    [        U5      R                  n[        U5      nUS:X  a  SOSnSU  SU SU SU SU S	3$ )
zFormat 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__r-   )r7   excattempts_madeexc_typeexc_msgattempt_words         r4   _format_failure_message+ToolRetryMiddleware._format_failure_message   s[     9%%c($1Q$6yJYK}oQ|n M:Ry(;=	
r:   c                    U R                   S:X  a  Ue[        U R                   5      (       a  U R                  U5      nOU R                  XU5      n[        UUUSS9$ )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%   )contenttool_call_idr.   status)r   callablerG   r   )r0   r7   rK   rB   rC   rJ   s         r4   _handle_failure#ToolRetryMiddleware._handle_failure   s]    " ??g%IDOO$$ooc*G229=QG%	
 	
r:   c           
        UR                   (       a  UR                   R                  OUR                  S   nU R                  U5      (       d  U" U5      $ UR                  S   n[	        U R
                  S-   5       H  n U" U5      s  $    Sn	[#        U	5      e! [         a  nUS-   n[        X`R                  5      (       d  U R                  X4Xg5      s SnAs  $ XPR
                  :  a]  [        UU R                  U R                  U R                  U R                  S9nUS:  a  [        R                   " U5         SnAM   SnAM  U R                  X4Xg5      s SnAs  $ SnAff = f)an  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.
r.   idr<   Nr   r   r    r!   r   2Unexpected: retry loop completed without returning)r2   r.   	tool_callr8   ranger   	Exceptionr
   r   rN   r	   r   r   r    r!   timesleepRuntimeError
r0   requesthandlerr7   rK   r=   rB   rC   delayr1   s
             r4   wrap_tool_call"ToolRetryMiddleware.wrap_tool_call   sB   " *1GLL%%7;L;LV;T	 &&y117##((. T--12G]w'' 3: C37  ] '! .c==AA//	\\ ---+'+':':&*&8&8"&..#{{E qy

5)) !
  //	\\/]s1    B
E%#0E E%A E E E% E%c           
       #    UR                   (       a  UR                   R                  OUR                  S   nU R                  U5      (       d  U" U5      I Sh  vN $ UR                  S   n[	        U R
                  S-   5       H  n U" U5      I Sh  vN s  $    Sn	[#        U	5      e NP N! [         a  nUS-   n[        X`R                  5      (       d  U R                  X4Xg5      s SnAs  $ XPR
                  :  af  [        UU R                  U R                  U R                  U R                  S9nUS:  a%  [        R                   " U5      I Sh  vN     SnAM   SnAM  U R                  X4Xg5      s SnAs  $ SnAff = f7f)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.
r.   NrQ   r<   rR   r   rS   )r2   r.   rT   r8   rU   r   rV   r
   r   rN   r	   r   r   r    r!   asynciorX   rY   rZ   s
             r4   awrap_tool_call#ToolRetryMiddleware.awrap_tool_callZ  sV    $ *1GLL%%7;L;LV;T	 &&y11 )))((. T--12G]$W--- 3: C3G * . ] '! .c==AA//	\\ ---+'+':':&*&8&8"&..#{{E qy%mmE222 !
  //	\\/]s   AFB+.F
B/B-B/F-B//
F90E?)F*F1A#E?EE?F&E?7F8F?FF)	r/   r   r   r!   r    r   r   r   r   )r   intr   zlist[BaseTool | str] | Noner   r   r   r   r   floatr   re   r    re   r!   boolreturnNone)r7   r-   rg   rf   )r7   r-   rB   rV   rC   rd   rg   r-   )
r7   r-   rK   z
str | NonerB   rV   rC   rd   rg   r   )r[   r   r\   z7Callable[[ToolCallRequest], ToolMessage | Command[Any]]rg   ToolMessage | Command[Any])r[   r   r\   zBCallable[[ToolCallRequest], Awaitable[ToolMessage | Command[Any]]]rg   ri   )rA   
__module____qualname____firstlineno____doc__rV   r(   r8   staticmethodrG   rN   r^   rb   __static_attributes____classcell__)r3   s   @r4   r   r      s'   _H -1&L * #"] ] +	]
 ] ] ] ] ] ] 
] ]~. 
 
&

,6
=F
WZ
	
@8  8  I8  
$	8 t9  9  T9  
$	9  9 r:   r   )rm   
__future__r   ra   rW   r)   typingr   r   langchain_core.messagesr   "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:   r4   <module>rz      s[    ' "    % /  _ ^3'A(u /*Y*?9*TU u r:   