
    g3fi"                       d Z ddl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 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mZmZ dZeee   gef   Z G d de      Z ed       G d de             Z  G d de      Z!ddgZ"y)a  Context editing middleware.

Mirrors Anthropic's context editing capabilities by clearing older tool results once the
conversation grows beyond a configurable token threshold.

The implementation is intentionally model-agnostic so it can be used with any LangChain
chat model.
    )annotations)	AwaitableCallableIterableSequence)deepcopy)	dataclass)Literal)	AIMessage
AnyMessageBaseMessageToolMessagecount_tokens_approximately)Protocol)AgentMiddlewareModelCallResultModelRequestModelResponsez	[cleared]c                  $    e Zd ZdZ	 	 	 	 	 	 ddZy)ContextEditz/Protocol describing a context editing strategy.c                    y)z+Apply an edit to the message list in place.N )selfmessagescount_tokenss      i/var/www/auto_recruiter/arenv/lib/python3.12/site-packages/langchain/agents/middleware/context_editing.pyapplyzContextEdit.apply-   s     	    Nr   zlist[AnyMessage]r   TokenCounterreturnNone)__name__
__module____qualname____doc__r   r   r   r   r   r   *   s&    9" #	
 
r   r   T)slotsc                      e Zd ZU dZdZded<   	 dZded<   	 dZded<   	 d	Zd
ed<   	 dZ	ded<   	 e
Zded<   	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 ddZy)ClearToolUsesEditzGConfiguration for clearing tool outputs when token limits are exceeded.i inttriggerr   clear_at_least   keepFboolclear_tool_inputsr   zSequence[str]exclude_toolsstrplaceholderc          
         ||      }|| j                   k  ryt        |      D cg c]  \  }}t        |t              s||f }}}| j                  t        |      k\  rg }n| j                  r|d| j                    }d}t        | j                        }|D ]5  \  }j                  j                  di       j                  d      r3t        d t        |d|       D        d      }	|	Ut        fd|	j                  D        d      }
|
wj                  xs |
d   |v rj                  d| j                  i j                  ddd	d
id      ||<   | j                   r.| j#                  |	j$                        ||j'                  |	      <   | j(                  dkD  s ||      }t+        d||z
        }|| j(                  k\  s6 y yc c}}w )z#Apply the clear-tool-uses strategy.Nr   context_editingclearedc              3  B   K   | ]  }t        |t              s|  y wN)
isinstancer   ).0ms     r   	<genexpr>z*ClearToolUsesEdit.apply.<locals>.<genexpr>j   s     Qq
1i8PQs   c              3  ^   K   | ]$  }|j                  d       j                  k(  r| & yw)idN)gettool_call_id)r;   calltool_messages     r   r=   z*ClearToolUsesEdit.apply.<locals>.<genexpr>q   s/      xx~)B)BB s   *-nameTclear_tool_uses)r7   strategy)artifactcontentresponse_metadataupdate)r,   	enumerater:   r   r/   lensetr2   rI   r@   nextreversed
tool_callsrD   
model_copyr4   r1   !_build_cleared_tool_input_messagerA   indexr-   max)r   r   r   tokensidxmsg
candidatescleared_tokensexcluded_tools
ai_message	tool_callnew_token_countrC   s               @r   r   zClearToolUsesEdit.applyM   s    h'T\\! (1':
#3jk>ZS#J

 
 99J'JYY#Ltyyj1JT//0!+ 2	C--112CRHLLYWQHXds^4QSWJ ! * 5 5
 I  !!6Yv%6>I(33 $#//*&88*)'+(9,*
 4 HSM %%7;7]7] --8
34
 ""Q&".x"8!$Q(@!A!T%8%88i2	h 	A
s   GGc                   g }d}|j                   D ]9  }t        |      }|j                  d      |k(  ri |d<   d}|j                  |       ; t        t	        |di             }t        |j                  di             }|r?t        |j                  dg             }	|	j                  |       t        |	      |d<   ||d<   |j                  ||d	      S )
NFr?   argsTrI   r6   cleared_tool_inputs)rQ   rI   rJ   )	rQ   dictr@   appendgetattrrN   addsortedrR   )
r   messagerA   updated_tool_callscleared_anyr]   updated_callmetadatacontext_entrycleared_idss
             r   rS   z3ClearToolUsesEdit._build_cleared_tool_input_message   s    
   ++ 	4I	?L%5')V$"%%l3	4 )<bABX\\*;R@Am//0ErJKKOOL)39+3FM/0*7H&'!!0%- " 
 	
r   Nr    )rg   r   rA   r3   r"   r   )r$   r%   r&   r'   r,   __annotations__r-   r/   r1   r2   DEFAULT_TOOL_PLACEHOLDERr4   r   rS   r   r   r   r*   r*   7   s    QGS-NCAD#MD#t#R#%M=%6/K/=L"L #	L
 
L\

 
 
	
r   r*   c                  t     e Zd ZU dZded<   ded<   ddd	 	 	 	 	 d fd	Z	 	 	 	 	 	 dd
Z	 	 	 	 	 	 ddZ xZS )ContextEditingMiddlewarea  Automatically prune tool results to manage context size.

    The middleware applies a sequence of edits when the total input token count exceeds
    configured thresholds.

    Currently the `ClearToolUsesEdit` strategy is supported, aligning with Anthropic's
    `clear_tool_uses_20250919` behavior [(read more)](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool).
    zlist[ContextEdit]editsLiteral['approximate', 'model']token_count_methodNapproximate)rr   rt   c               j    t         |           t        |xs t               f      | _        || _        y)a  Initialize an instance of context editing middleware.

        Args:
            edits: Sequence of edit strategies to apply.

                Defaults to a single `ClearToolUsesEdit` mirroring Anthropic defaults.
            token_count_method: Whether to use approximate token counting
                (faster, less accurate) or exact counting implemented by the
                chat model (potentially slower, more accurate).
        N)super__init__listr*   rr   rt   )r   rr   rt   	__class__s      r   rx   z!ContextEditingMiddleware.__init__   s0      	%9$5$7#9:
"4r   c                N   j                   s |      S | j                  dk(  rdd}n"j                  rj                  gng dfd}t        t	        j                               }| j
                  D ]  }|j                  ||         |j                  |            S )z:Apply context edits before invoking the model via handler.ru   c                    t        |       S r9   r   r   s    r   r   z>ContextEditingMiddleware.wrap_model_call.<locals>.count_tokens       1(;;r   c                h    j                   j                  t        |       z   j                        S r9   modelget_num_tokens_from_messagesry   toolsr   request
system_msgs    r   r   z>ContextEditingMiddleware.wrap_model_call.<locals>.count_tokens   ,    }}AAh/ r   r   r}   r   zSequence[BaseMessage]r"   r+   r   rt   system_messager   ry   rr   r   overrider   r   handlerr   edited_messageseditr   s    `    @r   wrap_model_callz(ContextEditingMiddleware.wrap_model_call   s     7##""m3< 6=5K5K'001QSJ
 #4(8(8#9:JJ 	CDJJ\JB	C w'''ABBr   c                ~  K   j                   s |       d{   S | j                  dk(  rdd}n"j                  rj                  gng dfd}t        t	        j                               }| j
                  D ]  }|j                  ||         |j                  |             d{   S 7 7 w)zJApply context edits before invoking the model via handler (async version).Nru   c                    t        |       S r9   r   r}   s    r   r   z?ContextEditingMiddleware.awrap_model_call.<locals>.count_tokens  r~   r   c                h    j                   j                  t        |       z   j                        S r9   r   r   s    r   r   z?ContextEditingMiddleware.awrap_model_call.<locals>.count_tokens  r   r   r   r}   r   r   r   s    `    @r   awrap_model_callz)ContextEditingMiddleware.awrap_model_call   s       )))""m3< 6=5K5K'001QSJ
 #4(8(8#9:JJ 	CDJJ\JB	C W---GHHH' *& Is"   B=B9BB=4B;5B=;B=)rr   zIterable[ContextEdit] | Nonert   rs   r"   r#   )r   r   r   z'Callable[[ModelRequest], ModelResponse]r"   r   )r   r   r   z2Callable[[ModelRequest], Awaitable[ModelResponse]]r"   r   )	r$   r%   r&   r'   rn   rx   r   r   __classcell__)rz   s   @r   rq   rq      s     77
 /3>K	5 ,5 <	5
 
5(CC 9C 
	C8II DI 
	Ir   rq   N)#r'   
__future__r   collections.abcr   r   r   r   copyr   dataclassesr	   typingr
   langchain_core.messagesr   r   r   r   langchain_core.messages.utilsr   typing_extensionsr   !langchain.agents.middleware.typesr   r   r   r   ro   r+   r!   r   r*   rq   __all__r   r   r   <module>r      s    # C C  !   E &  '  k	
( 
 ~
 ~
 ~
BWI WIv r   