
    i"                       S r SSKJr  SSKJrJrJrJr  SSK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  SSKJr  SS	KJrJrJrJr  S
r\\\   /\4   r " S S\5      r\	" SS9 " S S\5      5       r " S S\5      r SS/r!g)a$  Context editing middleware.

This 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)	dataclass)Literal)	AIMessage
AnyMessageBaseMessageSystemMessageToolMessagecount_tokens_approximately)Protocol)AgentMiddlewareModelCallResultModelRequestModelResponsez	[cleared]c                  .    \ rS rSrSr      SS jrSrg)ContextEdit)   z/Protocol describing a context editing strategy.c                   g)z+Apply an edit to the message list in place.N )selfmessagescount_tokenss      e/home/james-whalen/.local/lib/python3.13/site-packages/langchain/agents/middleware/context_editing.pyapplyContextEdit.apply,   s     	    r   Nr   zlist[AnyMessage]r   TokenCounterreturnNone)__name__
__module____qualname____firstlineno____doc__r   __static_attributes__r   r!   r   r   r   )   s&    9" #	
 
r!   r   T)slotsc                      \ rS rSr% SrSrS\S'    SrS\S'    SrS\S	'    S
r	S\S'    Sr
S\S'    \rS\S'          SS jr      SS jrSrg)ClearToolUsesEdit6   zGConfiguration 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          
       ^ U" U5      nX0R                   ::  a  g[        U5       VVs/ s H  u  pE[        U[        5      (       d  M  XE4PM!     nnnU R                  [        U5      :  a  / nO!U R                  (       a  USU R                  *  nSn[        U R                  5      nU GHJ  u  nmTR                  R                  S0 5      R                  S5      (       a  M9  [        S [        USU 5       5       S5      n	U	c  M]  [        U4S jU	R                   5       S5      n
U
c  M  TR                  =(       d    U
S   U;   a  M  TR                  SU R                  0 TR                  ESSS	S
.0ES.S9X'   U R                   (       a-  U R#                  U	TR$                  5      XR'                  U	5      '   U R(                  S:  d  GM#  U" U5      n[+        SX;-
  5      nXpR(                  :  d  GMK    g   gs  snnf )z#Apply the clear-tool-uses strategy.Nr   context_editingclearedc              3  T   #    U  H  n[        U[        5      (       d  M  Uv   M      g 7fN)
isinstancer
   ).0ms     r   	<genexpr>*ClearToolUsesEdit.apply.<locals>.<genexpr>i   s     Q4q
1i8P4s   (	(c              3  j   >#    U  H(  nUR                  S 5      TR                  :X  d  M$  Uv   M*     g7f)idN)gettool_call_id)r@   calltool_messages     r   rB   rC   p   s0       5xx~)B)BB D 5s   #3	3nameTclear_tool_uses)r<   strategy)artifactcontentresponse_metadataupdate)r1   	enumerater?   r   r4   lensetr7   rO   rF   nextreversed
tool_callsrJ   
model_copyr9   r6   !_build_cleared_tool_input_messagerG   indexr2   max)r   r   r   tokensidxmsg
candidatescleared_tokensexcluded_tools
ai_message	tool_callnew_token_countrI   s               @r   r   ClearToolUsesEdit.applyL   s    h'\\! (1':
':83jk>ZJSJ': 	 
 99J'JYY#Ltyyj1JT//0!+C--112CRHLLYWWQHXds^4QSWJ ! * 5 5
 I  !!6Yv%6>I(33 $#//*&88*)'+(9,*
 4 HM %%7;7]7] --8
34
 ""Q&".x"8!$Q(@!A!%8%88i ",h 	A
s   G7G7c                   / nSnUR                    H;  n[        U5      nUR                  S5      U:X  a  0 US'   SnUR                  U5        M=     [        [	        US0 5      5      n[        UR                  S0 5      5      nU(       a>  [        UR                  S/ 5      5      n	U	R                  U5        [        U	5      US'   XS'   UR                  UUS.S	9$ )
NFrE   argsTrO   r;   cleared_tool_inputs)rW   rO   rP   )	rW   dictrF   appendgetattrrT   addsortedrX   )
r   messagerG   updated_tool_callscleared_anyrc   updated_callmetadatacontext_entrycleared_idss
             r   rY   3ClearToolUsesEdit._build_cleared_tool_input_message   s    
   ++I	?L%5')V$"%%l3 , )<bABX\\*;R@Am//0ErJKKOOL)39+3FM/0*7&'!!0%- " 
 	
r!   Nr"   )rn   r
   rG   r8   r$   r
   )r&   r'   r(   r)   r*   r1   __annotations__r2   r4   r6   r7   DEFAULT_TOOL_PLACEHOLDERr9   r   rY   r+   r   r!   r   r.   r.   6   s    QGS-NCAD#MD#t#R#%M=%6/K/=L"L #	L
 
L\

 
 
	
r!   r.   c                     ^  \ rS rSr% SrS\S'   S\S'   SSS	.     SU 4S
 jjjr      SS jr      SS jrS	r	U =r
$ )ContextEditingMiddleware   a  Automatically prunes 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` behaviour.
zlist[ContextEdit]editsLiteral['approximate', 'model']token_count_methodNapproximate)r{   r}   c               r   > [         TU ]  5         [        U=(       d    [        5       45      U l        X l        g)ay  Initializes a context editing middleware instance.

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.   r{   r}   )r   r{   r}   	__class__s      r   r   !ContextEditingMiddleware.__init__   s.     	%9$5$7#9:
"4r!   c                .  ^^ TR                   (       d  U" T5      $ U R                  S:X  a  SS jnO0TR                  (       a  [        TR                  S9/O/ mSUU4S jjnU R                   H  nUR                  TR                   US9  M     U" T5      $ )z:Apply context edits before invoking the model via handler.r~   c                    [        U 5      $ r>   r   r   s    r   r   >ContextEditingMiddleware.wrap_model_call.<locals>.count_tokens       1(;;r!   rN   c                h   > TR                   R                  T[        U 5      -   TR                  5      $ r>   modelget_num_tokens_from_messagesr   toolsr   request
system_msgs    r   r   r      ,    }}AAh/ r!   r   r   zSequence[BaseMessage]r$   r0   r   r}   system_promptr   r{   r   r   r   handlerr   editr   s    `   @r   wrap_model_call(ContextEditingMiddleware.wrap_model_call   s     7##""m3< CJBWBWw'<'<=>]_  
 JJDJJw''lJC  wr!   c                ^  ^^#    TR                   (       d  U" T5      I Sh  vN $ U R                  S:X  a  SS jnO0TR                  (       a  [        TR                  S9/O/ mSUU4S jjnU R                   H  nUR                  TR                   US9  M     U" T5      I Sh  vN $  N N7f)zJApply context edits before invoking the model via handler (async version).Nr~   c                    [        U 5      $ r>   r   r   s    r   r   ?ContextEditingMiddleware.awrap_model_call.<locals>.count_tokens   r   r!   r   c                h   > TR                   R                  T[        U 5      -   TR                  5      $ r>   r   r   s    r   r   r     r   r!   r   r   r   r   s    `   @r   awrap_model_call)ContextEditingMiddleware.awrap_model_call   s       )))""m3< CJBWBWw'<'<=>]_  
 JJDJJw''lJC  W%%%' *& &s"   B-B)BB-$B+%B-+B-)r{   zIterable[ContextEdit] | Noner}   r|   r$   r%   )r   r   r   z'Callable[[ModelRequest], ModelResponse]r$   r   )r   r   r   z2Callable[[ModelRequest], Awaitable[ModelResponse]]r$   r   )r&   r'   r(   r)   r*   rv   r   r   r   r+   __classcell__)r   s   @r   ry   ry      s     77
 /3>K	5 ,5 <	5
 
5 5&   9  
	 8&& D& 
	& &r!   ry   N)"r*   
__future__r   collections.abcr   r   r   r   dataclassesr   typingr	   langchain_core.messagesr
   r   r   r   r   langchain_core.messages.utilsr   typing_extensionsr   !langchain.agents.middleware.typesr   r   r   r   rw   r0   r#   r   r.   ry   __all__r   r!   r   <module>r      s    # C C !   E &  '  k	
( 
 ~
 ~
 ~
BT& T&p r!   