
    g3fi#                        d Z ddlmZmZ ddl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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 ddlm Z  de!de
de"e   e"e   z  de#fdZ$ e de       G d de             Z%y)a  This module provides a ValidationNode class that can be used to validate tool calls
in a langchain graph. It applies a pydantic schema to tool_calls in the models' outputs,
and returns a ToolMessage with the validated content. If the schema is not valid, it
returns a ToolMessage with the error message. The ValidationNode can be used in a
StateGraph with a "messages" key. If multiple tool calls are requested, they will be run in parallel.
    )CallableSequence)Anycast)	AIMessage
AnyMessageToolCallToolMessage)RunnableConfig)get_executor_for_config)BaseToolcreate_schema_from_function)is_basemodel_subclass)RunnableCallable)LangGraphDeprecatedSinceV10)	BaseModelValidationError)r   )r   )
deprecatederrorcallschemareturnc                     t        |        dS )z"Default error formatting function.z-

Respond after fixing all validation errors.)repr)r   r   r   s      _/var/www/auto_recruiter/arenv/lib/python3.12/site-packages/langgraph/prebuilt/tool_validator.py_default_format_errorr   "   s     5k]IJJ    zpValidationNode is deprecated. Please use `create_agent` from `langchain.agents` with custom tool error handling.)categoryc                        e Zd ZdZdddddeeee   z  ez     dee	e
ee   gef   dz  dedee   dz  d	df
 fd
Zdee   eeef   z  d	eeef   fdZdee   eeef   z  ded	efdZ xZS )ValidationNodea	  A node that validates all tools requests from the last `AIMessage`.

    It can be used either in `StateGraph` with a `'messages'` key.

    !!! note

        This node does not actually **run** the tools, it only validates the tool calls,
        which is useful for extraction and other use cases where you need to generate
        structured output that conforms to a complex schema without losing the original
        messages and tool IDs (for use in multi-turn conversations).

    Returns:
        (Union[Dict[str, List[ToolMessage]], Sequence[ToolMessage]]): A list of
            `ToolMessage` objects with the validated content or error messages.

    Example:
        ```python title="Example usage for re-prompting the model to generate a valid response:"
        from typing import Literal, Annotated
        from typing_extensions import TypedDict

        from langchain_anthropic import ChatAnthropic
        from pydantic import BaseModel, field_validator

        from langgraph.graph import END, START, StateGraph
        from langgraph.prebuilt import ValidationNode
        from langgraph.graph.message import add_messages

        class SelectNumber(BaseModel):
            a: int

            @field_validator("a")
            def a_must_be_meaningful(cls, v):
                if v != 37:
                    raise ValueError("Only 37 is allowed")
                return v

        builder = StateGraph(Annotated[list, add_messages])
        llm = ChatAnthropic(model="claude-3-5-haiku-latest").bind_tools([SelectNumber])
        builder.add_node("model", llm)
        builder.add_node("validation", ValidationNode([SelectNumber]))
        builder.add_edge(START, "model")

        def should_validate(state: list) -> Literal["validation", "__end__"]:
            if state[-1].tool_calls:
                return "validation"
            return END

        builder.add_conditional_edges("model", should_validate)

        def should_reprompt(state: list) -> Literal["model", "__end__"]:
            for msg in state[::-1]:
                # None of the tool calls were errors
                if msg.type == "ai":
                    return END
                if msg.additional_kwargs.get("is_error"):
                    return "model"
            return END

        builder.add_conditional_edges("validation", should_reprompt)

        graph = builder.compile()
        res = graph.invoke(("user", "Select a number, any number"))
        # Show the retry logic
        for msg in res:
            msg.pretty_print()
        ```
    N
validation)format_errornametagsschemasr"   r#   r$   r   c                   t         |   | j                  d||d       |xs t        | _        i | _        |D ]O  }t        |t              r|j                  t        d|j                   d      t        |j                  t              rt        |j                        s&t        d|j                   d|j                   d      |j                  | j
                  |j                  <   t        |t              rFt        |t        t        f      r0t!        t        t           |      | j
                  |j"                  <   t%        |      r't'        d	|      }|| j
                  |j"                  <   :t        d
t        |       d       y)a  Initialize the ValidationNode.

        Args:
            schemas: A list of schemas to validate the tool calls with. These can be
                any of the following:
                - A pydantic BaseModel class
                - A BaseTool instance (the args_schema will be used)
                - A function (a schema will be created from the function signature)
            format_error: A function that takes an exception, a ToolCall, and a schema
                and returns a formatted error string. By default, it returns the
                exception repr and a message to respond after fixing validation errors.
            name: The name of the node.
            tags: A list of tags to add to the node.
        NF)r#   r$   tracezTool z& does not have an args_schema defined.zVValidation node only works with tools that have a pydantic BaseModel args_schema. Got z with args_schema: .
ValidationzPUnsupported input to ValidationNode. Expected BaseModel, tool or function. Got: )super__init___funcr   _format_errorschemas_by_name
isinstancer   args_schema
ValueErrorr#   typer   
issubclassr   BaseModelV1r   __name__callabler   )selfr%   r"   r#   r$   r   
base_model	__class__s          r   r+   zValidationNode.__init__t   sq   . 	T4uM)B-B;= 	F&(+%%-$},RS  $&&.v/A/AB$%{{m+>v?Q?Q>RRSU  5;4F4F$$V[[1FD)jK0/ 9=T)_f8U$$V__5&!8vN
8B$$V__5 fgklrgsfttuv -	r   inputc                     t        |t              rd}|}n"|j                  dg       x}rd}nt        d      |d   }t        |t              st        d      ||fS )z*Extract the last AIMessage from the input.listmessagesdictzNo message found in inputz Last message is not an AIMessage)r/   r<   getr1   r   )r7   r:   output_typer=   messages        r   _get_messagezValidationNode._get_message   si     eT" K"H:r22X2 K899&rl'9-?@@G##r   configc                       j                  |      \  }}dt        dt        f fd}t        |      5 }g |j	                  ||j
                        }|dk(  r|cddd       S d|icddd       S # 1 sw Y   yxY w)z*Validate and run tool calls synchronously.r   r   c           
         j                   | d      }	 t        |t              r%|j                  | d         }|j	                         }nMt        |t
              r%|j                  | d         }|j                         }nt        dt        |       d      t        || d   t        t        | d               S # t        t        f$ r@}t        j                  || |      | d   t        t        | d         ddi	      cY d }~S d }~ww xY w)
Nr#   argszUnsupported schema type: z$. Expected BaseModel or BaseModelV1.id)contentr#   tool_call_idis_errorT)rI   r#   rJ   additional_kwargs)r.   r3   r   model_validatemodel_dump_jsonr4   validatejsonr1   r2   r
   r   strr   ValidationErrorV1r-   )r   r   outputrI   er7   s        r   run_onez%ValidationNode._func.<locals>.run_one   s   ))$v,7Ffi0#224<@F$446G4#__T&\:F$kkmG$3DL>Aef  ##f!%c4:!6 
 $%67 " ..q$?f!%c4:!6'14&8	 s   B#B9 9D5D=DDr<   Nr=   )rC   r	   r
   r   map
tool_calls)r7   r:   rD   rA   rB   rU   executoroutputss   `       r   r,   zValidationNode._func   s      $007W	( 	{ 	4 %V, 	-BWg.@.@ABGf$	- 	-
 #G,	- 	- 	-s   %A/"A//A8)r5   
__module____qualname____doc__r   r   r2   r   r   BaseExceptionr	   rQ   r<   r+   r   r>   r   tupler   rC   r   r,   __classcell__)r9   s   @r   r    r    +   s    
BR  !%2(T)_4x?@2 xiI3NO
	2 2 3i$2 
2h$*%S#X6$	sI~	$ %-*%S#X6%-@N%-	%-r   r    N)&r\   collections.abcr   r   typingr   r   langchain_core.messagesr   r   r	   r
   langchain_core.runnablesr   langchain_core.runnables.configr   langchain_core.toolsr   r   langchain_core.utils.pydanticr   langgraph._internal._runnabler   langgraph.warningsr   pydanticr   r   pydantic.v1r4   rR   typing_extensionsr   r]   r2   rQ   r   r     r   r   <module>rm      s    /
  D F ? : : / 0 < (KK
K Od;//K 		K v(n-% n-	n-r   