
    9iQ                     X   d Z ddlZddlZddlmZmZmZ ddlmZ ddl	m
Z
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mZ dd	lmZ dd
lmZ ddlmZmZ ddlmZm Z  eee   ge!f   Z"dZ#dZ$dZ%dZ&e'ed   e(f   Z)	 e'ed   e!f   Z*	 e'ed   e!f   Z+	 e)e*z  e+z  Z,	 dede"fdZ- G d de      Z.y)zSummarization middleware.    N)CallableIterableMapping)partial)AnyLiteralcast)
AnyMessageMessageLikeRepresentationRemoveMessageToolMessageHumanMessage)count_tokens_approximatelytrim_messages)REMOVE_ALL_MESSAGES)Runtime)AgentMiddleware
AgentState)BaseChatModelinit_chat_modela  <role>
Context Extraction Assistant
</role>

<primary_objective>
Your sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.
</primary_objective>

<objective_information>
You're nearing the total number of input tokens you can accept, so you must extract the highest quality/most relevant pieces of information from your conversation history.
This context will then overwrite the conversation history presented below. Because of this, ensure the context you extract is only the most important information to your overall goal.
</objective_information>

<instructions>
The conversation history below will be replaced with the context you extract in this step. Because of this, you must do your very best to extract and record all of the most important context from the conversation history.
You want to ensure that you don't repeat any actions you've already completed, so the context you extract from the conversation history should be focused on the most important information to your overall goal.
</instructions>

The user will message you with the full message history you'll be extracting context from, to then replace. Carefully read over it all, and think deeply about what information is most important to your overall goal that should be saved:

With all of this in mind, please carefully read over the entire conversation history, and extract the most important and relevant context to replace it so that you can free up space in the conversation history.
Respond ONLY with the extracted context. Do not include any additional information, or text before or after the extracted context.

<messages>
Messages to summarize:
{messages}
</messages>   i     fractiontokensmessagesmodelreturnc                 N    | j                   dk(  rt        t        d      S t        S )zATune parameters of approximate token counter based on model type.zanthropic-chatgffffff
@)chars_per_token)	_llm_typer   r   )r   s    s/var/www/html/backtest/airagagent/rag_env/lib/python3.12/site-packages/langchain/agents/middleware/summarization.py_get_approximate_token_counterr#   y   s%    ** 13GG%%    c                       e Zd ZdZddefeeeddee	z  de
ee
   z  dz  de
ded	ed
edz  deddf fdZdededeeef   dz  fdZdededeeef   dz  fdZdee   dedefdZdee   defdZdee   dedz  fdZdedz  fdZde
dede
fdZdedee   fdZdee   ddfdZdee   dedeee   ee   f   fdZ dee   d edefd!Z!dee   dedefd"Z"d#ee   defd$Z#d#ee   defd%Z$dee   dee   fd&Z% xZ&S )'SummarizationMiddlewarea;  Summarizes conversation history when token limits are approached.

    This middleware monitors message token counts and automatically summarizes older
    messages when a threshold is reached, preserving recent messages and maintaining
    context continuity by ensuring AI/Tool message pairs remain together.
    Nr   )triggerkeeptoken_countersummary_prompttrim_tokens_to_summarizer   r'   r(   r)   r*   r+   deprecated_kwargsr   c                @   d|v r)|d   }t        j                  dt        d       ||d|f}d|v r0|d   }t        j                  dt        d       |d	t        fk(  rd	|f}t        |           t        |t              rt        |      }|| _	        |
d| _
        g }	nUt        |t              r)|D 
cg c]  }
| j                  |
d
       }}
|| _
        |}	n| j                  |d
      }|| _
        |g}	|	| _        | j                  |d      | _        |t        u rt!        | j                        | _        n|| _        || _        || _        t)        d | j                  D              }| j                  d   dk(  rd}|r| j+                         d}t-        |      yyc c}
w )a  Initialize summarization middleware.

        Args:
            model: The language model to use for generating summaries.
            trigger: One or more thresholds that trigger summarization.

                Provide a single
                [`ContextSize`][langchain.agents.middleware.summarization.ContextSize]
                tuple or a list of tuples, in which case summarization runs when any
                threshold is met.

                !!! example

                    ```python
                    # Trigger summarization when 50 messages is reached
                    ("messages", 50)

                    # Trigger summarization when 3000 tokens is reached
                    ("tokens", 3000)

                    # Trigger summarization either when 80% of model's max input tokens
                    # is reached or when 100 messages is reached (whichever comes first)
                    [("fraction", 0.8), ("messages", 100)]
                    ```

                    See [`ContextSize`][langchain.agents.middleware.summarization.ContextSize]
                    for more details.
            keep: Context retention policy applied after summarization.

                Provide a [`ContextSize`][langchain.agents.middleware.summarization.ContextSize]
                tuple to specify how much history to preserve.

                Defaults to keeping the most recent `20` messages.

                Does not support multiple values like `trigger`.

                !!! example

                    ```python
                    # Keep the most recent 20 messages
                    ("messages", 20)

                    # Keep the most recent 3000 tokens
                    ("tokens", 3000)

                    # Keep the most recent 30% of the model's max input tokens
                    ("fraction", 0.3)
                    ```
            token_counter: Function to count tokens in messages.
            summary_prompt: Prompt template for generating summaries.
            trim_tokens_to_summarize: Maximum tokens to keep when preparing messages for
                the summarization call.

                Pass `None` to skip trimming entirely.
        max_tokens_before_summaryzOmax_tokens_before_summary is deprecated. Use trigger=('tokens', value) instead.   )
stacklevelNr   messages_to_keepzEmessages_to_keep is deprecated. Use keep=('messages', value) instead.r   r'   r(   c              3   ,   K   | ]  }|d    dk(    yw)r   r   N ).0	conditions     r"   	<genexpr>z3SummarizationMiddleware.__init__.<locals>.<genexpr>   s     diy|z9ds   r   r   Ta  Model profile information is required to use fractional token limits, and is unavailable for the specified model. Please use absolute token counts instead, or pass `

ChatModel(..., profile={"max_input_tokens": ...})`.

with a desired integer value of the model's maximum input tokens.)warningswarnDeprecationWarning_DEFAULT_MESSAGES_TO_KEEPsuper__init__
isinstancestrr   r   r'   list_validate_context_size_trigger_conditionsr(   r   r#   r)   r*   r+   any_get_profile_limits
ValueError)selfr   r'   r(   r)   r*   r+   r,   valuetrigger_conditionsitemvalidated_list	validatedrequires_profilemsg	__class__s                  r"   r<   z SummarizationMiddleware.__init__   s   F '*;;%&ABEMMa"
 5#4#U+!22%&89EMMW"
 
$=>>"E*eS!#E*E
?CGDL46&W^_td99$	J_N_)DL!/33GYGI$DL"+#5 //f=	66!?

!KD!.D,(@%d4KcKcdd99Q<:%# 8 8 : BT  S/! !C) `s   3Fstateruntimec                 @   |d   }| j                  |       | j                  |      }| j                  ||      sy| j                  |      }|dk  ry| j	                  ||      \  }}| j                  |      }| j                  |      }	dt        t              g|	|iS zOProcess messages before model invocation, potentially triggering summarization.r   Nr   )id)	_ensure_message_idsr)   _should_summarize_determine_cutoff_index_partition_messages_create_summary_build_new_messagesr   r   
rE   rN   rO   r   total_tokenscutoff_indexmessages_to_summarizepreserved_messagessummarynew_messagess
             r"   before_modelz$SummarizationMiddleware.before_model	  s    $  *))(3%%h=33H=1484L4LXWc4d11&&'<=//8 !45 $
 	
r$   c                 \  K   |d   }| j                  |       | j                  |      }| j                  ||      sy| j                  |      }|dk  ry| j	                  ||      \  }}| j                  |       d{   }| j                  |      }	dt        t              g|	|iS 7 ,wrQ   )	rS   r)   rT   rU   rV   _acreate_summaryrX   r   r   rY   s
             r"   abefore_modelz%SummarizationMiddleware.abefore_model$  s     $  *))(3%%h=33H=1484L4LXWc4d11--.CDD//8 !45 $
 	
 Es   A;B,=B*>-B,rZ   c                     | j                   sy| j                   D ][  \  }}|dk(  rt        |      |k\  r y|dk(  r||k\  r y|dk(  s-| j                         }|@t        ||z        }|dk  rd}||k\  s[ y y)zGDetermine whether summarization should run for the current token usage.Fr   Tr   r   r      )rA   lenrC   int)rE   r   rZ   kindrF   max_input_tokens	thresholds          r"   rT   z)SummarizationMiddleware._should_summarize?  s    ''33 	 KD%z!c(mu&<xLE$9z!#'#;#;#= #+ 05 89	> !I9,	  r$   c                     | j                   \  }}|dv r+| j                  |      }||S | j                  |t              S | j                  |t	        d|            S )z7Choose cutoff index respecting retention configuration.>   r   r   rg   )r(   _find_token_based_cutoff_find_safe_cutoffr:   r	   )rE   r   rh   rF   token_based_cutoffs        r"   rU   z/SummarizationMiddleware._determine_cutoff_indexT  se    iie))!%!>!>x!H!-)) ))(4MNN%%hUE0BCCr$   c                 R   |sy| j                   \  }}|dk(  r"| j                         }|yt        ||z        }n|dk(  rt        |      }ny|dk  rd}| j                  |      |k  rydt	        |      }}t	        |      }t	        |      j                         dz   }	t        |	      D ]2  }
||k\  r n+||z   dz  }| j                  ||d       |k  r|}|}.|dz   }4 |t	        |      k(  r|}|t	        |      k\  rt	        |      dk(  ryt	        |      dz
  }| j                  ||      S )z2Find cutoff index based on target token retention.r   r   Nr   re   r/   )r(   rC   rg   r)   rf   
bit_lengthrange_find_safe_cutoff_point)rE   r   rh   rF   ri   target_token_countleftrightcutoff_candidatemax_iterations_mids               r"   rl   z0SummarizationMiddleware._find_token_based_cutoff`  s^   iie:#779'!$%5%=!>X!$U"!"h'+== Xex=X113a7~& 		Au}%<A%C!!(34.15GG#& Qw		 s8},#s8},8}!"8}q0 ++H6FGGr$   c                     	 | j                   j                  }t        |t              sy|j                  d      }t        |t              sy|S # t        $ r Y yw xY w)z6Retrieve max input token limit from the model profile.Nri   )r   profileAttributeErrorr=   r   getrg   )rE   r{   ri   s      r"   rC   z+SummarizationMiddleware._get_profile_limits  s]    	jj((G '7+";;'9:*C0  		s   A 	AAcontextparameter_namec                     |\  }}|dk(  r#d|cxk  rdk  sn d| d| d}t        |      |S |dv r|dk  r| d| d}t        |      |S d	| d
| d}t        |      )z&Validate context configuration tuples.r   r   re   zFractional z% values must be between 0 and 1, got .>   r   r   z( thresholds must be greater than 0, got zUnsupported context size type z for )rD   )rE   r~   r   rh   rF   rL   s         r"   r@   z.SummarizationMiddleware._validate_context_size  s    e:u>>#N#33XY^X__`a o%  ++z'((PQVPWWXY o%  34&n=MQOCS/!r$   r^   c                 "    t        d|       gS )Nz0Here is a summary of the conversation to date:

)contentr   )rE   r^   s     r"   rX   z+SummarizationMiddleware._build_new_messages  s    #UV]U^!_`
 	
r$   c                 p    |D ]1  }|j                   t        t        j                               |_         3 y)zAEnsure all messages have unique IDs for the add_messages reducer.N)rR   r>   uuiduuid4)rE   r   rL   s      r"   rS   z+SummarizationMiddleware._ensure_message_ids  s,     	+Cvv~TZZ\*	+r$   conversation_messagesr[   c                     |d| }||d }||fS )zAPartition messages into those to summarize and those to preserve.Nr3   )rE   r   r[   r\   r]   s        r"   rV   z+SummarizationMiddleware._partition_messages  s*     !6m| D2<=A$&888r$   r1   c                 `    t        |      |k  ryt        |      |z
  }| j                  ||      S )a  Find safe cutoff point that preserves AI/Tool message pairs.

        Returns the index where messages can be safely cut without separating
        related AI and Tool messages. Returns `0` if no safe cutoff is found.

        This is aggressive with summarization - if the target cutoff lands in the
        middle of tool messages, we advance past all of them (summarizing more).
        r   )rf   rr   )rE   r   r1   target_cutoffs       r"   rm   z)SummarizationMiddleware._find_safe_cutoff  s6     x=,,H(88++HmDDr$   c                     |t        |      k  r:t        ||   t              r'|dz  }|t        |      k  rt        ||   t              r'|S )a  Find a safe cutoff point that doesn't split AI/Tool message pairs.

        If the message at cutoff_index is a ToolMessage, advance until we find
        a non-ToolMessage. This ensures we never cut in the middle of parallel
        tool call responses.
        re   )rf   r=   r   )rE   r   r[   s      r"   rr   z/SummarizationMiddleware._find_safe_cutoff_point  sL     S]*z(<:PR]/^AL S]*z(<:PR]/^r$   r\   c                    |sy| j                  |      }|sy	 | j                  j                  | j                  j	                  |            }|j
                  j                         S # t        $ r}d|cY d}~S d}~ww xY w)(Generate summary for the given messages.!No previous conversation history.0Previous conversation was too long to summarize.r   Error generating summary: N)_trim_messages_for_summaryr   invoker*   formattextstrip	ExceptionrE   r\   trimmed_messagesresponsees        r"   rW   z'SummarizationMiddleware._create_summary  s~    $6::;PQE	6zz(()<)<)C)CM])C)^_H==&&(( 	6/u55	6s   AA( (	B 1A;5B ;B c                 "  K   |sy| j                  |      }|sy	 | j                  j                  | j                  j	                  |             d{   }|j
                  j                         S 7 # t        $ r}d|cY d}~S d}~ww xY ww)r   r   r   r   Nr   )r   r   ainvoker*   r   r   r   r   r   s        r"   rb   z(SummarizationMiddleware._acreate_summary  s     $6::;PQE	6!ZZ//##**4D*E H ==&&((  	6/u55	6sF   B8A4 A2A4 1B2A4 4	B=BBBBBc                     	 | j                   |S t        dt        || j                   | j                  dddd            S # t        $ r |t
         d cY S w xY w)z6Trim messages to fit within summary generation limits.Nzlist[AnyMessage]humanlastT)
max_tokensr)   start_onstrategyallow_partialinclude_system)r+   r	   r   r)   r   _DEFAULT_FALLBACK_MESSAGE_COUNT)rE   r   s     r"   r   z2SummarizationMiddleware._trim_messages_for_summary  st    	?,,4"#<<"&"4"4$#"&#'   	?<<=>>	?s   A  /A   AA)'__name__
__module____qualname____doc__r:   r   DEFAULT_SUMMARY_PROMPT_DEFAULT_TRIM_TOKEN_LIMITr>   r   ContextSizer?   TokenCounterrg   r   r<   r   r   dictr`   rc   r
   boolrT   rU   rl   rC   r@   r   rX   rS   tuplerV   rm   rr   rW   rb   r   __classcell__)rM   s   @r"   r&   r&      sh    ;?')BC&@4/H}"]"}" tK0047	}"
 }" $}" }" #&*}" !}" 
}"~
* 
w 
4S>TXCX 
6
 
g 
$sTWx.[_J_ 
6$z*: # RV *
DZ0@ 
DS 
D/Hj1A /HcDj /Hb S4Z  "k 3 S^  
3 
43E 

+D,< + +	9#J/	9 	9 
tJj!11	2		9E$z*: Ec EVY E	Z0@ 	PS 	X[ 	6T*5E 6# 66D<L 6QT 6"?4
3C ?ZHX ?r$   r&   )/r   r   r7   collections.abcr   r   r   	functoolsr   typingr   r   r	   langchain_core.messagesr
   r   r   r   langchain_core.messages.humanr   langchain_core.messages.utilsr   r   langgraph.graph.messager   langgraph.runtimer   !langchain.agents.middleware.typesr   r   langchain.chat_modelsr   r   rg   r   r   r:   r   r   r   floatContextFractionContextTokensContextMessagesr   r#   r&   r3   r$   r"   <module>r      s       7 7  % %  7 S & I @";<=sBC 8    "$ 
+U23 gh',- 
+S01 -?8&- &L &R?o R?r$   