
    g3fih)                        d Z ddlm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mZ erddlmZmZ dd	lmZ  G d
 de      Zy)z"Model retry middleware for agents.    )annotationsN)TYPE_CHECKING)	AIMessage)	OnFailureRetryOncalculate_delayshould_retry_exceptionvalidate_retry_params)AgentMiddlewareModelResponse)	AwaitableCallable)ModelRequestc                       e Zd ZdZdefdddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d fd	Zdd
ZddZ	 	 	 	 	 	 ddZ	 	 	 	 	 	 ddZ	 xZ
S )ModelRetryMiddlewarea	  Middleware that automatically retries failed model 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 ModelRetryMiddleware

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

        !!! example "Retry specific exceptions only"

            ```python
            from anthropic import RateLimitError
            from openai import APITimeoutError

            retry = ModelRetryMiddleware(
                max_retries=4,
                retry_on=(APITimeoutError, RateLimitError),
                backoff_factor=1.5,
            )
            ```

        !!! example "Custom exception filtering"

            ```python
            from anthropic import APIStatusError


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


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

        !!! example "Custom error handling"

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


            retry = ModelRetryMiddleware(
                max_retries=4,
                on_failure=format_error,
            )
            ```

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

            ```python
            retry = ModelRetryMiddleware(
                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 = ModelRetryMiddleware(
                max_retries=2,
                on_failure="error",  # Re-raise exception instead of returning message
            )
            ```
       continueg       @g      ?g      N@T)max_retriesretry_on
on_failurebackoff_factorinitial_delay	max_delayjitterc                   t         |           t        ||||       || _        g | _        || _        || _        || _        || _        || _	        || _
        y)u  Initialize `ModelRetryMiddleware`.

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

                Must be `>= 0`.
            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 an `AIMessage` with error details,
                    allowing the agent to continue with an error response.
                - `'error'`: Re-raise the exception, stopping agent execution.
                - **Custom callable:** Function that takes the exception and returns a
                    string for the `AIMessage` content, allowing custom error
                    formatting.
            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.
        N)super__init__r
   r   toolsr   r   r   r   r   r   )	selfr   r   r   r   r   r   r   	__class__s	           e/var/www/auto_recruiter/arenv/lib/python3.12/site-packages/langchain/agents/middleware/model_retry.pyr   zModelRetryMiddleware.__init__j   s\    \ 	 	k=)^T&
 $,*"    c                    t        |      j                  }t        |      }|dk(  rdnd}d| d| d| d| }t        |      S )	a  Format the failure message when retries are exhausted.

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

        Returns:
            `AIMessage` with formatted error message.
           attemptattemptszModel call failed after  z with z: content)type__name__strr   )r   excattempts_madeexc_typeexc_msgattempt_wordr)   s          r!   _format_failure_messagez,ModelRetryMiddleware._format_failure_message   s[     9%%c($1Q$6yJ&}oQ|nF8*TVW^V_` 	 ))r"   c                    | j                   dk(  r|t        | j                         r| j                  |      }t        |      }n| j                  ||      }t	        |g      S )a\  Handle failure when all retries are exhausted.

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

        Returns:
            `ModelResponse` with error details.

        Raises:
            Exception: If `on_failure` is `'error'`, re-raises the exception.
        errorr(   )result)r   callabler   r2   r   )r   r-   r.   r)   ai_msgs        r!   _handle_failurez$ModelRetryMiddleware._handle_failure   sX     ??g%IDOO$ooc*Gw/F11#}EFVH--r"   c           	        t        | j                  dz         D ]  }	  ||      c S  d}t        |      # t        $ r}|dz   }t        || j                        s| j                  ||      cY d}~c S || j                  k  rSt        || j                  | j                  | j                  | j                        }|dkD  r/t        j                  |       n| j                  ||      cY d}~c S Y d}~d}~ww xY w)a8  Intercept model execution and retry on failure.

        Args:
            request: Model request with model, messages, state, and runtime.
            handler: Callable to execute the model (can be called multiple times).

        Returns:
            `ModelResponse` or `AIMessage` (the final result).
        r$   Nr   r   r   r   r   2Unexpected: retry loop completed without returning)ranger   	Exceptionr	   r   r8   r   r   r   r   r   timesleepRuntimeErrorr   requesthandlerr%   r-   r.   delaymsgs           r!   wrap_model_callz$ModelRetryMiddleware.wrap_model_call   s     T--12 	DGDw''	D: C37  D '! .c4==A//]CC T---+'+':':&*&8&8"&..#{{E qy

5)  //]CC/Ds'   5	C7,C2*C72A3C2%C72C7c           	     "  K   t        | j                  dz         D ]  }	  ||       d{   c S  d}t        |      7 # t        $ r}|dz   }t        || j                        s| j                  ||      cY d}~c S || j                  k  r\t        || j                  | j                  | j                  | j                        }|dkD  r8t        j                  |       d{  7   n| j                  ||      cY d}~c S Y d}~d}~ww xY ww)aI  Intercept and control async model execution with retry logic.

        Args:
            request: Model request with model, messages, state, and runtime.
            handler: Async callable to execute the model and returns `ModelResponse`.

        Returns:
            `ModelResponse` or `AIMessage` (the final result).
        r$   Nr:   r   r;   )r<   r   r=   r	   r   r8   r   r   r   r   r   asyncior?   r@   rA   s           r!   awrap_model_callz%ModelRetryMiddleware.awrap_model_call   s      T--12 	DGD$W---	D: C39 . D '! .c4==A//]CC T---+'+':':&*&8&8"&..#{{E qy%mmE222  //]CC/Ds`   DA?ADA	D
,D6D7D>A$D"C%#D:D;DDD)r   intr   r   r   r   r   floatr   rK   r   rK   r   boolreturnNone)r-   r=   r.   rJ   rM   r   )r-   r=   r.   rJ   rM   r   )rB   r   rC   z'Callable[[ModelRequest], ModelResponse]rM   ModelResponse | AIMessage)rB   r   rC   z2Callable[[ModelRequest], Awaitable[ModelResponse]]rM   rO   )r+   
__module____qualname____doc__r=   r   r2   r8   rF   rI   __classcell__)r    s   @r!   r   r      s    Md &L * #": : 	:
 : : : : : 
:x*$.0- -  9-  
#	- ^- -  D-  
#	- r"   r   )rR   
__future__r   rH   r>   typingr   langchain_core.messagesr   "langchain.agents.middleware._retryr   r   r   r	   r
   !langchain.agents.middleware.typesr   r   collections.abcr   r   r   r    r"   r!   <module>r[      s>    ( "     -  M3>R ? R r"   