
    Si&                        d Z ddlmZ ddlZddlZddlmZ ddl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  ee      Zej*                  j-                  dd      ZddZ G d d      Zy)u  
utils/session_auto_compress.py — 세션 자동 압축 모듈

두 가지 기능을 제공합니다:
1. 자동 압축 훅: CRITICAL 감지 시 ContextCompressor를 통해 메시지 압축
2. 세션 요약 + 재시작 파일 저장: 90% 초과 시 세션 요약을 마크다운으로 저장

Usage:
    from utils.session_auto_compress import SessionAutoCompress
    from utils.session_monitor import SessionMonitor

    monitor = SessionMonitor(context_limit=200_000)
    sac = SessionAutoCompress(monitor=monitor)
    sac.setup_auto_hooks()

    compressed, event = sac.auto_compress(messages)
    path = sac.save_session_summary(messages, task_id="task-100.1", team_id="dev6-team")
    )annotationsN)datetime)Path)Any)ContextCompressor_estimate_tokens)generate_summary)
get_logger)SessionMonitorWORKSPACE_ROOTz/home/jay/workspacec                
   d}| D ]K  }|j                  d      xs d}||z  }|j                  d      }|s1	 |t        j                  |d      z  }M |rt        |      S dS # t        t        f$ r |t        |      z  }Y |w xY w)u6   메시지 리스트의 총 토큰 수를 추정한다. content
tool_callsF)ensure_asciir   )getjsondumps	TypeError
ValueErrorstrr   )messages
total_textmsgr   r   s        L/home/jay/workspace/.worktrees/task-2117-dev1/utils/session_auto_compress.py_estimate_tokens_for_messagesr   '   s    J .'')$*g
WW\*
.djj%HH
. ,6J'<1< z* .c*o-
.s   A""BBc                      e Zd ZdZ	 	 	 d	 	 	 	 	 	 	 	 	 ddZddZ	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZddZ	 	 	 	 	 	 	 	 	 	 ddZ	dd	Z
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd
Zy)SessionAutoCompressu  세션 자동 압축 및 요약 저장 클래스.

    Args:
        monitor: SessionMonitor 인스턴스
        context_limit: 컨텍스트 최대 토큰 수 (기본값: 200,000)
        events_dir: 이벤트 파일 저장 디렉토리 (기본값: WORKSPACE/memory/events/)
        sessions_dir: 세션 요약 파일 저장 디렉토리 (기본값: WORKSPACE/memory/sessions/)
    Nc                    || _         || _        t        t              }|t        |      n|dz  dz  | _        |t        |      n|dz  dz  | _        t        j                  d|| j                  | j
                         y )NmemoryeventssessionsuO   SessionAutoCompress 초기화: context_limit=%d, events_dir=%s, sessions_dir=%s)monitorcontext_limitr   _WORKSPACE_ROOT
events_dirsessions_dirloggerdebug)selfr#   r$   r&   r'   	workspaces         r   __init__zSessionAutoCompress.__init__@   s     *)	4>4JZ 0PY\dPdgoPo8D8P$|"4V_bjVjmwVw]OO		
    c                   t        |      }t        |      }|s*| j                  dddd      }| j                  |       g |fS t	        | j
                        }|j                  |      }t        |      }t        |      }| j                  j                  |       t        j                  d||||       | j                  ||||      }| j                  |       ||fS )uO  압축 수행.

        ContextCompressor를 사용해 메시지를 압축하고, 이벤트 파일을 저장하며
        monitor의 토큰 카운터를 리셋한다.

        Args:
            messages: 압축할 메시지 리스트

        Returns:
            (압축된 메시지 리스트, 이벤트 정보 dict) 튜플
        r   )before_countafter_counttokens_beforetokens_after)r$   )	new_totalu3   auto_compress: %d → %d messages, tokens %d → %d)lenr   _build_event_info_save_eventr   r$   compressr#   resetr(   info)	r*   r   r/   r1   
event_info
compressor
compressedr0   r2   s	            r   auto_compressz!SessionAutoCompress.auto_compressY   s     8}5h?//	 0 J Z(z>!&T5G5GH
((2
*o4Z@ 	\2A	
 ++%#'%	 , 

 	$:%%r-   c           
     \   t        j                         j                  d      }t        |d      xs d}	| j	                  ||||	||||      }
| j
                  j                  dd       d| d| d	}| j
                  |z  }|j                  |
d
       t        j                  d|       |S )u{  세션 요약을 마크다운 파일로 저장하고 경로를 반환한다.

        generate_summary()를 호출하여 기본 요약 텍스트를 생성하고,
        추가 정보와 함께 마크다운 형식으로 저장한다.

        Args:
            messages: 요약할 메시지 리스트
            task_id: 작업 ID
            team_id: 팀 ID
            modified_files: 수정한 파일 목록
            remaining_tasks: 남은 작업 목록
            last_success_step: 마지막 성공 단계 설명
            errors: 에러/실패 목록

        Returns:
            저장된 파일의 Path 객체
        z%Y%m%dT%H%M%ST)use_llmu   (요약 없음))task_idteam_id	timestampsummary_textmodified_filesremaining_taskslast_success_steperrorsparentsexist_okzsummary--z.mdutf-8encodingu   세션 요약 저장: %s)
r   nowstrftimer	   _build_markdownr'   mkdir
write_textr(   r9   )r*   r   r@   rA   rD   rE   rF   rG   rB   rC   r   filenamepaths                r   save_session_summaryz(SessionAutoCompress.save_session_summary   s    6 LLN++O<	'$?TCT&&%)+/ ' 	
 	t<gYa	{#6  8+'2.5r-   c                z    | j                   j                  d| j                         t        j	                  d       y)uG   모니터에 CRITICAL 콜백으로 _on_critical을 자동 등록한다.criticalu/   setup_auto_hooks: critical 콜백 등록 완료N)r#   register_callback_on_criticalr(   r)   )r*   s    r   setup_auto_hooksz$SessionAutoCompress.setup_auto_hooks   s)    &&z43D3DEFGr-   c                r    t         j                  d|j                  dd      |j                  dd             y)uK   CRITICAL 레벨 도달 시 호출되는 내부 콜백. 로그만 남긴다.uh   CRITICAL 레벨 감지: total_tokens=%d, usage_pct=%.1f%% — 외부에서 auto_compress() 호출 필요total_tokensr   	usage_pctg        N)r(   warningr   )r*   statuss     r   rZ   z SessionAutoCompress._on_critical   s-    vJJ~q)JJ{C(	
r-   c                T    dt        j                         j                         ||||dS )u&   이벤트 정보 dict를 생성한다.session_compressed)eventrB   r/   r0   r1   r2   )r   rO   	isoformat)r*   r/   r0   r1   r2   s        r   r5   z%SessionAutoCompress._build_event_info   s/     *!113(&*(
 	
r-   c                R   | j                   j                  dd       t        j                         j	                  d      }d| d}| j                   |z  }t        |dd      5 }t        j                  ||d	d
       ddd       t        j                  d|       y# 1 sw Y    xY w)u0   이벤트 정보를 JSON 파일로 저장한다.TrH   z%Y%m%dT%H%M%S%fzsession-compressed-z.jsonwrL   rM   F   )r   indentNu   이벤트 파일 저장: %s)
r&   rR   r   rO   rP   openr   dumpr(   r)   )r*   r:   timestamp_strrT   rU   fs         r   r6   zSessionAutoCompress._save_event   s    dT: //0AB(u=)$g. 	C!IIj!%B	C2D9	C 	Cs   $BB&c	                   d| ddd| d| d| dd|ddg}	|r|D ]  }
|	j                  d	|
         n|	j                  d
       |	ddgz  }	|r|D ]  }|	j                  d|         n|	j                  d
       |	dd|r|nd
ddgz  }	|r|D ]  }|	j                  d	|         n|	j                  d
       dj                  |	      dz   S )u5   세션 요약 마크다운 문자열을 생성한다.u   # 세션 요약: r   u   ## 기본 정보u   - 작업 ID: u   - 팀: u   - 생성 시각: u   ## 자동 요약u   ## 수정한 파일z- u   (없음)u   ## 남은 작업z- [ ] u   ## 마지막 성공 단계u   ## 에러/실패
)appendjoin)r*   r@   rA   rB   rC   rD   rE   rF   rG   linesrl   taskerrors                r   rQ   z#SessionAutoCompress._build_markdown   s0     y)G9%gY	{+!
 # 'r!X&' LL$
 	

 ' .vdV_-. LL$(!2

 	
  +r%\*+ LL$yy$&&r-   )i@ NN)
r#   r   r$   intr&   str | Path | Noner'   ru   returnNone)r   
list[dict]rv   ztuple[list[dict], dict])NNNN)r   rx   r@   r   rA   r   rD   list[str] | NonerE   ry   rF   
str | NonerG   ry   rv   r   )rv   rw   )r`   dictrv   rw   )
r/   rt   r0   rt   r1   rt   r2   rt   rv   r{   )r:   r{   rv   rw   )r@   r   rA   r   rB   r   rC   r   rD   ry   rE   ry   rF   rz   rG   ry   rv   r   )__name__
__module____qualname____doc__r,   r=   rV   r[   rZ   r5   r6   rQ    r-   r   r   r   6   sQ    %(,*.

 
 &	

 (
 

21&p ,0,0(,#'// / 	/
 )/ */ &/ !/ 
/bH


 
 	

 
 

":9'9' 9' 	9'
 9' )9' *9' &9' !9' 
9'r-   r   )r   zlist[dict[str, Any]]rv   rt   )r   
__future__r   r   osr   pathlibr   typingr   utils.context_compressorr   r   utils.context_summarizerr	   utils.loggerr
   utils.session_monitorr   r|   r(   environr   r%   r   r   r   r-   r   <module>r      s[   & #  	    H 5 # 0	H	**..!13HI=l' l'r-   