
    iN/              	       z   d dl Z d dlZd dlmZmZmZmZ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Z e	e      ZdZdZ eeez        Zd	Zed
fdedededefdZdee   defdZdee   dee   fdZdee   defdZdee   dee   fdZdedeeeef      fdZdZ dedefdZ!	 	 ddedeeeegef      fdZ"y)    N)ToolMessageBaseMessageHumanMessage	AIMessageSystemMessage   )
get_logger)ListOptionalTupleCallable)get_llmi  gffffff?i'   text	max_charsquery_labelreturnc                 x    t        |       |k  r| S dt        |        d}|rd| d}| d|t        |      z
   |z   S )z
    Truncates result text to max_chars and appends advice for context safety.
    Used for multi-query batch: each (query, answer) message is capped so no single result fills context.
    u   
... [TRUNCATED – original z> chars. Consider smaller window_days or TOP N to reduce rows.]u   
... [TRUNCATED – z3; consider DATEADD/DATEDIFF or TOP to reduce rows.]N)len)r   r   r   suffixs       C/var/www/html/userprofiledev.eatanceapp.com/core/context_manager.pycap_result_contentr      sV    
 4yI-c$i[8vwF(5hi))c&k)*V33    messagesc           	      4   	 t        j                  d      }d}| D ]7  }|t        |j                  t	        |j
                                    z  }|dz  }9 |S # t        $ r7}t        j                  d|        t        d | D              dz  cY d}~S d}~ww xY w)zF
    Estimates token count for a list of messages using tiktoken.
    cl100k_baser      zError counting tokens: c              3   X   K   | ]"  }t        t        |j                               $ y w)N)r   strcontent).0ms     r   	<genexpr>zcount_tokens.<locals>.<genexpr>.   s     913s199~&s   (*N)
tiktokenget_encodingr   encoder   r    	Exceptionloggererrorsum)r   encoding
num_tokensmsges        r   count_tokensr/      s    ?((7
C#hooc#++.>?@@J!OJ	 
  ?.qc23999Q>>?s   AA 	B ,BBBc                 v   t        |       }|t        k  r| S t        j                  d| dt         d       g }| D ]  }t	        |t
              rt        t        |j                              t        kD  r~t        |j                        dt         dt        t        |j                               dz   }t        ||j                  |j                  |j                        }|j                  |       |j                  |        t        |      }t        j                  d|        |t        k  r|S t        j                  d	       |D cg c]  }t	        |t              s| }}|D cg c]  }t	        |t              r| }}t        |      d
k  rt        j                  d       |S |dd }	|dd }
	 t!        |	      }t        d|       }||gz   |
z   }t        j                  dt        |              |S c c}w c c}w # t"        $ r(}t        j%                  d| d       ||
z   cY d}~S d}~ww xY w)z
    Proactively prunes messages if they exceed the SAFE_THRESHOLD.
    Strategy:
    1. Truncate large ToolOutputs first (they are usually the culprit).
    2. If still over, drop oldest history (excluding System Prompt).
    zContext Usage High (z tokens). Pruning to target ...Nz&
... [TRUNCATED SYSTEM: Original size z chars])r    tool_call_idnameidz,Pruning successful (Truncation). New count: z3Truncation insufficient. Summarizing older history.   z:Not enough history to summarize. Returning truncated list.zPREVIOUS CONTEXT SUMMARY: r    z-Summarization complete. Final message count: zSummarization failed: z'. Falling back to drop-oldest strategy.)r/   TARGET_TOKENSr(   warning
isinstancer   r   r   r    MAX_CHARS_PER_RESULTr2   r3   r4   appendinfor   summarize_historyr'   r)   )r   current_tokenspruned_messagesr-   truncated_contentnew_msgr"   system_msgs
non_systemto_summarizerecent_historysummary_textsummary_msgfinal_messagesr.   s                  r   prune_messagesrJ   0   s.    "(+N%
NN).)99UVcUddghi Oc;'CCKK0@,ADX,XCKK !6"67;CCKK@P<Q;RRYZ[  "*;#JZJZadaiainqntntuG""7+""3'  "/2N
KK>~>NOP% NNHI .NoA}1M1oKN,Q_Jq-4P!_JQ
:!ST cr?L_N,(6 $.H,WX$}4~ECCDWCXYZ' OQ(  ,-aS0WXY^++,s7   G=!G=+HH7AH 	H8H3-H83H8c                    | syt        d      }d}| D ]R  }|j                  j                         }t        |j                        }t        |      dkD  r|dd dz   }|| d| d	z  }T d
| d}	 |j                  t        |      g      }|j                  S # t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)zP
    Uses the LLM to summarize a list of messages into a concise narrative.
    zNo history.        temperaturer   i  Nr1   : 
z
    Summarize the following conversation history into a concise paragraph. 
    Focus on the SQL queries run and the key insights found. 
    Ignore detailed JSON data, just capture the high-level findings.
    
    HISTORY:
    z
    r7   zError calling LLM for summary: zError generating summary.)r   typeupperr   r    r   invoker   r'   r(   r)   )	r   llmconversation_textr"   roler    promptresponser.   s	            r   r>   r>   q   s     
c
"C vv||~aii.w<#dsme+GvRy33   F+::|F;<= +6qc:;*+s   0'B 	C!B>>Cc           	         | sg S | d   }t               }t        |d      r(|j                  r|j                  D ch c]  }|d   	 }}g }| D ]  }t        |t              s|j
                  |vs#t        t        |j                              dkD  sEt        j                  d|j
                   d       |j                  t	        d|j
                  |j                  |j                                |S c c}w )	z
    Identifies 'old' ToolMessages that are no longer part of the active tool call batch
    and returns placeholder updates to wipe their content (Volatile Memory).
    
    Usage: Call this when entering a NEW tool execution phase.
    
tool_callsr4   d   z$Volatile Memory: Wiping ToolMessage z (Data processed)z'[Data Processed & Removed from History])r    r2   r4   r3   )sethasattrr[   r:   r   r2   r   r   r    r(   r=   r<   r4   r3   )r   last_msgcurrent_tool_call_idstccleanup_updatesr"   s         r   get_volatile_cleanup_updatesrc      s      |H  Ex&8+>+>4<4G4G H4GbD4G HOa%!..@U*UC		N#c)CANNCSSdef ''F"#..&&	)   ! !Is   C4r    c                    | rd| vsd| vry| j                  dd      }t        |      dk7  ry|d   j                         }d|v r^d|v rZ|j                  dd      d   j                  dd      j                         }|j                  dd      d   j                         }||fS d|v r'|j                  dd      d   j                         }d|fS y)	z
    Parse ToolMessage content (hypothesis: ...\nquery: ...\nanswer: ...) into (hypothesis, query).
    Returns None if the format is not recognized.
    zquery:zanswer:Nr      r   zhypothesis:r   )splitr   stripreplace)r    partsheadh_partq_parts        r   _parse_tool_message_contentrm      s    
 hg-'1IMM)Q'E
5zQ8>>DT!1Ha(+33M2FLLNHa(+1134Ha(+113F|r   a  This SQL query returned too much data and caused a context limit error.
Return the SAME query with a STRICTER date filter (e.g. last 30 days or 7 days) to reduce rows.
Change only the date range; do not change other logic.
Output ONLY the SQL statement, no explanation or markdown.queryc                    | xs dj                         s| xs dS 	 t        d      }t         d|  }|j                  t	        |      g      }t        |dd      xs dj                         }|r=d|v r7t        j                  d	|      }|r|j                  d
      j                         }|S 	 | S # t        $ r$}t        j                  d| d       Y d}~| S d}~ww xY w)z
    Calls the LLM to return the same query with a reduced date window.
    On failure returns the original query so the pipeline can continue.
    r   rL   rM   z	

Query:
r7   r    Nz```z```(?:\w*)\s*([\s\S]*?)```r   z%rewrite_query_reduced_window failed: z; using original query.)rg   r   REDUCE_WINDOW_PROMPTrS   r   getattrresearchgroupr'   r(   r9   )rn   rT   rW   rX   new_sqlr"   r.   s          r   rewrite_query_reduced_windowrv      s    
 KR {[#&()eW=::|F;<=8Y5;BBDII;WEggaj..0GN  L  [>qcAXYZZL[s   BB0 0	C9CCmax_retriesexecute_sql_fnc                    t        |      }t        |dz         D ]  }	 | j                  |      c S  y# t        j                  t        j
                  t        f$ r}d}t        |t        j                        r9dt        |      j                         v xs dt        |      j                         v }nqt        |t        j
                        r|j                  dk(  }nGdt        |      j                         v xs* dt        |      j                         v xs dt        |      v }|r||k  st        j                  d|        |t        j                  d|dz    d	|        |rt        |d
   t              s||d
   }t        |j                  xs d      }	t!        |	      }
d}|ra|
r_|
\  }}t#        |      }	  |||      }t        j%                  d       n/# t        $ r#}t        j                  d| d       Y d}~nd}~ww xY w|dt'        |	       d}t        ||j(                  |j*                        |d
<   Y d}~(d}~ww xY w)a  
    Invokes the model with retry logic for context overflow (400) or payload too large (413).
    When the last message is a ToolMessage and execute_sql_fn is provided: parses the query,
    asks the LLM for a reduced-date-window version, runs it via execute_sql_fn, replaces the
    ToolMessage content with the smaller result, and retries. Otherwise replaces with a short
    error message and retries.
    r   Fcontexttokeni  413zUnrecoverable LLM error: z!Context/Payload error on attempt rO   rZ   r   NzGRe-ran query with reduced date window and replaced ToolMessage content.zexecute_sql_fn failed: z ; falling back to error message.zdSYSTEM ERROR: The tool output was too large and exceeded the model's context limit. Result size was zY chars. PLEASE RE-TRY with a DATE FILTER (e.g., last 30 or 7 days) to reduce data volume.)r    r2   r3   )listrangerS   openaiBadRequestErrorAPIStatusErrorr'   r:   r   lowerstatus_coder(   r)   r9   r   r    rm   rv   r=   r   r2   r3   )modelr   rw   rx   current_messagesattemptr.   is_context_413	last_toolr    parsednew_content
hypothesisrn   	new_queryrun_errs                   r   invoke_with_retryr      s,    H~q).	<< 011 * &&(=(=yI ,	"N!V334!*c!flln!<!Y3q6<<>@YAv445!"#!5!*c!flln!<!l3q6<<>@Y!l]bfijkfl]l"w'<8<=NN>w{m2aSQR#:6Fr6JK+X(,I)++1r2G09FK&$*!
E8?	h"0Y"GKKK ij  hNN%<WIEe#fggh "''*7|n 5hi  $/#&33^^$R 
 Y,	s@   3)IEI8GI	H G>9I>H9II)   N)#rr   r$   langchain_core.messagesr   r   r   r   r   logger_configr	   typingr
   r   r   r   llm_providerr   r   __name__r(   
MAX_TOKENSSAFE_THRESHOLDintr8   r;   r   r   r/   rJ   r>   rc   rm   rp   rv   r    r   r   <module>r      sO   	  d d % 2 2 ! 	H	 
J/0 3G\^ 
4S 
4S 
4VY 
4cf 
4?4, ? ?$?,T+. ?,43D ?,B!+[ 1 !+c !+H!4+< !kAR !H %S/1J *>   4 :>	> > XsCj#o67	>r   