
    OKi3                    T   S r SSKJr  SSKrSSKJr  SSKJrJrJ	r	J
r
Jr  SSKJr  SSKJrJ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Jr  SSKJr  \(       a  SSKJ r J!r!  SSK"J#r#  \RH                  " \%5      r&Sr'\ " S S5      5       r(SS jr)SS jr* " S S\\\   \\4   5      r+g)z#LLM-based tool selector middleware.    )annotationsN)	dataclass)TYPE_CHECKING	AnnotatedAnyLiteralUnion)BaseChatModel)	AIMessageHumanMessage)FieldTypeAdapter)	TypedDict)AgentMiddleware
AgentStateContextTModelRequestModelResponse	ResponseT)init_chat_model)	AwaitableCallable)BaseToolzNYour goal is to select the most relevant tools for answering the user's query.c                  L    \ rS rSr% SrS\S'   S\S'   S\S'   S	\S
'   S\S'   Srg)_SelectionRequest$   z#Prepared inputs for tool selection.list[BaseTool]available_toolsstrsystem_messager   last_user_messager
   model	list[str]valid_tool_names N__name__
__module____qualname____firstlineno____doc____annotations____static_attributes__r%       l/var/www/html/dynamic-report/venv/lib/python3.13/site-packages/langchain/agents/middleware/tool_selection.pyr   r   $   s#    -####r.   r   c           	     
   U (       d  Sn[        U5      eU  Vs/ s H0  n[        [        UR                     [	        UR
                  S94   PM2     nn[        [        U5         nSn " S S[        5      n[        U5      $ s  snf )a  Create a structured output schema for tool selection.

Args:
    tools: Available tools to include in the schema.

Returns:
    `TypeAdapter` for a schema where each tool name is a `Literal` with its
        description.

Raises:
    AssertionError: If `tools` is empty.
z&Invalid usage: tools must be non-empty)descriptionz2Tools to use. Place the most relevant tools first.c                  $    \ rS rSr% SrS\S'   Srg)>_create_tool_selection_response.<locals>.ToolSelectionResponseI   zUse to select relevant tools.zCAnnotated[list[selected_tool_type], Field(description=description)]toolsr%   Nr&   r%   r.   r/   ToolSelectionResponser3   I   s    +RRr.   r6   )
AssertionErrorr   r   namer   r1   r	   tupler   r   )r5   msgtoolliteralsselected_tool_typer1   r6   s          r/   _create_tool_selection_responser>   /   s     6S!!
 X]W\t	'$))$e8H8H&IIJW\   uX/FKS	 S
 ,--s   7B c                2    SR                  S U  5       5      $ )z~Format tools as markdown list.

Args:
    tools: Tools to format.

Returns:
    Markdown string with each tool on a new line.

c              3  Z   #    U  H!  nS UR                    SUR                   3v   M#     g7f)z- z: N)r8   r1   ).0r;   s     r/   	<genexpr>$_render_tool_list.<locals>.<genexpr>Z   s(     Ledr$))Bt'7'7&89es   )+)joinr5   s    r/   _render_tool_listrG   Q   s     99LeLLLr.   c                     ^  \ rS rSrSrS\SSS.         SU 4S jjjr    SS jr          SS jr      SS jr	      SS	 jr
S
rU =r$ )LLMToolSelectorMiddleware]   a8  Uses an LLM to select relevant tools before calling the main model.

When an agent has many tools available, this middleware filters them down
to only the most relevant ones for the user's query. This reduces token usage
and helps the main model focus on the right tools.

Examples:
    !!! example "Limit to 3 tools"

        ```python
        from langchain.agents.middleware import LLMToolSelectorMiddleware

        middleware = LLMToolSelectorMiddleware(max_tools=3)

        agent = create_agent(
            model="openai:gpt-4o",
            tools=[tool1, tool2, tool3, tool4, tool5],
            middleware=[middleware],
        )
        ```

    !!! example "Use a smaller model for selection"

        ```python
        middleware = LLMToolSelectorMiddleware(model="openai:gpt-4o-mini", max_tools=2)
        ```
N)r"   system_prompt	max_toolsalways_includec                  > [         TU ]  5         X l        X0l        U=(       d    / U l        [        U[        [        S5      45      (       a  Xl        g[        U5      U l        g)a5  Initialize the tool selector.

Args:
    model: Model to use for selection.

        If not provided, uses the agent's main model.

        Can be a model identifier string or `BaseChatModel` instance.
    system_prompt: Instructions for the selection model.
    max_tools: Maximum number of tools to select.

        If the model selects more, only the first `max_tools` will be used.

        If not specified, there is no limit.
    always_include: Tool names to always include regardless of selection.

        These do not count against the `max_tools` limit.
N)
super__init__rK   rL   rM   
isinstancer
   typer"   r   )selfr"   rK   rL   rM   	__class__s        r/   rP   "LLMToolSelectorMiddleware.__init__z   sO    4 	*",2emT$Z899/4J(/DJr.   c                   UR                   (       a  [        UR                   5      S:X  a  gUR                    Vs/ s H  n[        U[        5      (       a  M  UPM     nnU R                  (       aa  U Vs1 s H  o"R
                  iM     nnU R                   Vs/ s H  oUU;  d  M
  UPM     nnU(       a  SU S[        U5       3n[        U5      eU Vs/ s H   o"R
                  U R                  ;  d  M  UPM"     nnU(       d  gU R                  n	U R                  b  U	SU R                   S3-  n	[        UR                  5       H  n
[        U
[        5      (       d  M  U
n  O   Sn[        U5      eU R                  =(       d    UR                  nU Vs/ s H  o"R
                  PM     nn[        UU	UUUS9$ s  snf s  snf s  snf s  snf s  snf )	aG  Prepare inputs for tool selection.

Args:
    request: the model request.

Returns:
    `SelectionRequest` with prepared inputs, or `None` if no selection is
    needed.

Raises:
    ValueError: If tools in `always_include` are not found in the request.
    AssertionError: If no user message is found in the request messages.
r   Nz.Tools in always_include not found in request: z. Available tools: z
IMPORTANT: List the tool names in order of relevance, with the most relevant first. If you exceed the maximum number of tools, only the first z will be used.z)No user message found in request messages)r   r    r!   r"   r$   )r5   lenrQ   dictrM   r8   sorted
ValueErrorrK   rL   reversedmessagesr   r7   r"   r   )rS   requestr;   
base_toolsavailable_tool_namesr8   missing_toolsr:   r   r    messager!   r"   r$   s                 r/   _prepare_selection_request4LLMToolSelectorMiddleware._prepare_selection_request   s   " }}GMM 2a 7 (/}}S}tJtT<Rd}
S :D#E*$II* #E!%!4!4!4DX8X!4   D]O T((./C(D'EG  !o% -7_JD))4K^K^:^4J_ ++>>%" #'..!1AN   0 01G'<00$+! 2
 >C %%

+gmm2AB/$II/B +)/-
 	
[ T $F `6 Cs/   F;F;4G 	G&GG
6G
Gc                   / n/ nUS    H[  nXs;  a  UR                  U5        M  Xu;  d  M"  U R                  b  [        U5      U R                  :  d  MJ  UR                  U5        M]     U(       a  SU 3n[        U5      eU V	s/ s H  oR                  U;   d  M  U	PM     n
n	UR
                   V	s/ s H8  n	[        U	[        5      (       a  M  U	R                  U R                  ;   d  M6  U	PM:     nn	U
R                  U5        UR
                   V	s/ s H  n	[        U	[        5      (       d  M  U	PM     nn	UR                  / U
QUQS9$ s  sn	f s  sn	f s  sn	f )zBProcess the selection response and return filtered `ModelRequest`.r5   zModel selected invalid tools: rF   )appendrL   rW   rZ   r8   r5   rQ   rX   rM   extendoverride)rS   responser   r$   r]   selected_tool_namesinvalid_tool_selections	tool_namer:   r;   selected_toolsalways_included_toolsprovider_toolss                r/   _process_selection_response5LLMToolSelectorMiddleware._process_selection_response   sV    *,"$!'*I0'..y9 3&#.A*BT^^*S#**95 + #23J2KLCS/! -*
,T		=P0PD_ 	 *

  1
%dD) .2ii4;N;N.N % 	 1

 	34 ,3==S=4JtT<R$=S&H&H&HII*
1
 Ts*   E	E	1EE*EE.Ec                   U R                  U5      nUc  U" U5      $ [        UR                  5      nUR                  5       nUR                  R                  U5      nUR                  SUR                  S.UR                  /5      n[        U[        5      (       d  S[        U5       3n[        U5      eU R                  XsR                  UR                  U5      n	U" U	5      $ )h  Filter tools based on LLM selection before invoking the model via handler.

Args:
    request: Model request to execute (includes state and runtime).
    handler: Async callback that executes the model request and returns
        `ModelResponse`.

Returns:
    The model call result.

Raises:
    AssertionError: If the selection model response is not a dict.
systemrolecontentExpected dict response, got )rb   r>   r   json_schemar"   with_structured_outputinvoker    r!   rQ   rX   rR   r7   ro   r$   
rS   r]   handlerselection_requesttype_adapterschemastructured_modelrh   r:   modified_requests
             r/   wrap_model_call)LLMToolSelectorMiddleware.wrap_model_call  s    $ !;;GD$7## 77H7X7XY))+,22II&Q#**!.?.N.NO!33
 (D))0h0@AC %%;;779J9[9[]d
 '((r.   c                  #    U R                  U5      nUc  U" U5      I Sh  vN $ [        UR                  5      nUR                  5       nUR                  R                  U5      nUR                  SUR                  S.UR                  /5      I Sh  vN n[        U[        5      (       d  S[        U5       3n[        U5      eU R                  XsR                  UR                  U5      n	U" U	5      I Sh  vN $  N Nk N7f)rr   Nrs   rt   rw   )rb   r>   r   rx   r"   ry   ainvoker    r!   rQ   rX   rR   r7   ro   r$   r{   s
             r/   awrap_model_call*LLMToolSelectorMiddleware.awrap_model_call=  s    $ !;;GD$ ))) 77H7X7XY))+,22II&Q)11!.?.N.NO!33
 
 (D))0h0@AC %%;;779J9[9[]d
 -...+ *
 /s5    DC>A1DD A$D9D:D DD)rM   rL   r"   rK   )
r"   zstr | BaseChatModel | NonerK   r   rL   z
int | NonerM   zlist[str] | NonereturnNone)r]   ModelRequest[ContextT]r   z_SelectionRequest | None)
rh   zdict[str, Any]r   r   r$   r#   r]   r   r   r   )r]   r   r|   z<Callable[[ModelRequest[ContextT]], ModelResponse[ResponseT]]r   $ModelResponse[ResponseT] | AIMessage)r]   r   r|   zGCallable[[ModelRequest[ContextT]], Awaitable[ModelResponse[ResponseT]]]r   r   )r'   r(   r)   r*   r+   DEFAULT_SYSTEM_PROMPTrP   rb   ro   r   r   r-   __classcell__)rT   s   @r/   rI   rI   ]   s    > -12 $+/"0 *"0 	"0
 "0 )"0 
"0 "0HH
-H
	!H
T(J (J ((J $	(J
 ((J 
 (JT))')) N)) 
.	))V)/')/ Y)/ 
.	)/ )/r.   rI   )r5   r   r   zTypeAdapter[Any])r5   r   r   r   ),r+   
__future__r   loggingdataclassesr   typingr   r   r   r   r	   *langchain_core.language_models.chat_modelsr
   langchain_core.messagesr   r   pydanticr   r   typing_extensionsr   !langchain.agents.middleware.typesr   r   r   r   r   r   langchain.chat_models.baser   collections.abcr   r   langchain.toolsr   	getLoggerr'   loggerr   r   r>   rG   rI   r%   r.   r/   <module>r      s    ) "  ! @ @ D ; ' '  73(			8	$ U 
      .D	MI/
90ExQZ0Z [ I/r.   