
    `gj                    6   d Z ddlZddlZddlZddlZddlZddlZddlmZ ddl	m
Z
mZmZmZmZ ddlmZmZ ddlmZ ddlmZmZ ddlZddlmZmZmZ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'  e#       Z( ee)      jT                  dz  Z+ e'e(e+       	 d&de,de-dee,   dee-   fdZ.e G d d             Z/e G d d             Z0e G d d             Z1 G d d      Z2	 	 	 	 	 	 	 d'de,de,de,de3d e,d!e-d"e3d#e4fd$Z5e6d%k(  r ejn                  e5       yy)(a  
Trajectory Compressor

Post-processes completed agent trajectories to compress them within a target
token budget while preserving training signal quality.

Compression Strategy:
1. Protect first turns (system, human, first gpt, first tool)
2. Protect last N turns (final actions and conclusions)
3. Compress MIDDLE turns only, starting from 2nd tool response
4. Compress only as much as needed to fit under target
5. Replace compressed region with a single human summary message
6. Keep remaining tool calls intact (model continues working after summary)

Usage:
    # Compress a directory of JSONL files
    python trajectory_compressor.py --input=data/my_run
    
    # Compress a single JSONL file
    python trajectory_compressor.py --input=data/trajectories.jsonl
    
    # Compress 15% sample of a file
    python trajectory_compressor.py --input=data/trajectories.jsonl --sample_percent=15
    
    # Compress with custom output and token target
    python trajectory_compressor.py --input=data/trajectories.jsonl --output=compressed.jsonl --target_max_tokens=16000
    
    # Compress 10% sample from a directory
    python trajectory_compressor.py --input=data/my_run --sample_percent=10
    N)Path)ListDictAnyOptionalTuple)	dataclassfield)datetime)base_url_host_matchesbase_url_hostname)ProgressSpinnerColumn
TextColumn	BarColumnTaskProgressColumnTimeElapsedColumnTimeRemainingColumn)Console)OPENROUTER_BASE_URLget_hermes_home)jittered_backoff)load_hermes_dotenvz.env)hermes_homeproject_envmodelrequested_temperaturebase_urlreturnc                 ^    	 ddl m}m}  || |      }||u ry||S |S # t        $ r |cY S w xY w)zApply fixed model temperature contracts to direct client calls.

    Returns ``None`` when the model manages temperature server-side (Kimi);
    callers must omit the ``temperature`` kwarg entirely in that case.
    r   )_fixed_temperature_for_modelOMIT_TEMPERATUREN)agent.auxiliary_clientr!   r"   	Exception)r   r   r   r!   r"   fixed_temperatures         H/root/.hermes/venv/lib/python3.12/site-packages/trajectory_compressor.py _effective_temperature_for_modelr'   ;   sN    %Y 5UHE,,$      %$$%s    ,,c                      e Zd ZU dZdZeed<   dZeed<   dZ	e
ed<   dZe
ed	<   dZeed
<   dZeed<   dZeed<   dZeed<   dZe
ed<   dZeed<   eZeed<   dZeed<   dZeed<   dZe
ed<   dZe
ed<   dZeed<   dZeed<   dZeed<   dZe
ed <   d!Ze
ed"<   dZeed#<   dZeed$<   d%Z e
ed&<   dZ!eed'<   dZ"eed(<   d)Z#eed*<   e$d+ed,d fd-       Z%y.)/CompressionConfigz)Configuration for trajectory compression.zmoonshotai/Kimi-K2-Thinkingtokenizer_nameTtrust_remote_codei;  target_max_tokensi  summary_target_tokensprotect_first_systemprotect_first_humanprotect_first_gptprotect_first_tool   protect_last_n_turnszgoogle/gemini-3-flash-previewsummarization_modelr   OPENROUTER_API_KEYapi_key_envg333333?temperature   max_retries   retry_delayadd_summary_noticezM

Some of your previous tool responses may be summarized to preserve context.summary_notice_text_compressedoutput_suffixnum_workers2   max_concurrent_requestsskip_under_targetsave_over_limiti,  per_trajectory_timeoutmetrics_enabledmetrics_per_trajectoryzcompression_metrics.jsonmetrics_output_file	yaml_pathr   c                    t        |dd      5 }t        j                  |      xs i }ddd        |        }dv rH|d   j                  d|j                        |_        |d   j                  d|j
                        |_        d|v rH|d   j                  d	|j                        |_        |d   j                  d
|j                        |_        d|v r|d   j                  d|j                        |_        |d   j                  d|j                        |_	        |d   j                  d|j                        |_
        |d   j                  d|j                        |_        |d   j                  d|j                        |_        d|v r|d   j                  d|j                        |_        |d   j                  d      xs |j                  |_        |d   j                  d|j                        |_        |d   j                  d|j                         |_        |d   j                  d|j"                        |_        |d   j                  d|j$                        |_        d|v rl|d   j                  d|j&                        |_        |d   j                  d|j(                        |_        |d   j                  d|j*                        |_        d|v r|d   j                  d|j,                        |_        |d   j                  d|j.                        |_        |d   j                  d|j0                        |_        |d   j                  d |j2                        |_        d!|v rl|d!   j                  d"|j4                        |_        |d!   j                  d#|j6                        |_        |d!   j                  d$|j8                        |_        |S # 1 sw Y   xY w)%z"Load configuration from YAML file.rutf-8encodingN	tokenizernamer+   compressionr,   r-   protected_turnsfirst_systemfirst_human	first_gpt
first_toollast_n_turnssummarizationr   r   r6   r7   r9   r;   outputr<   r=   r?   
processingr@   rB   rC   rD   metricsenabledper_trajectoryoutput_file)openyaml	safe_loadgetr*   r+   r,   r-   r.   r/   r0   r1   r3   r4   r   r6   r7   r9   r;   r<   r=   r?   r@   rB   rC   rD   rF   rG   rH   )clsrI   fdataconfigs        r&   	from_yamlzCompressionConfig.from_yaml}   s    )S73 	+q>>!$*D	+  $$($5$9$9&&BWBW$XF!'+K'8'<'<=PRXRjRj'kF$ D '+M':'>'>?RTZTlTl'mF$+/+>+B+BCZ\b\x\x+yF( $*./@*A*E*EnV\VqVq*rF')-.?)@)D)D]TZTnTn)oF&'+,='>'B'B;PVPhPh'iF$(,->(?(C(CLRXRkRk(lF%*./@*A*E*EnV\VqVq*rF' d")-o)>)B)B7FLfLf)gF&"?377
CVvFO!%o!6!:!:=&J\J\!]F!%o!6!:!:=&J\J\!]F!%o!6!:!:=&J\J\!]F!%o!6!:!:=&J\J\!]F t(,X(:(:;OQWQjQj(kF%)-h););<QSYSmSm)nF&#'>#5#5ovG[G[#\F  4!%l!3!7!7vGYGY!ZF-1,-?-C-CD]_e_}_}-~F*'+L'9'='=>QSYSkSk'lF$%),%7%;%;<MvOeOe%fF" %))_%8%8FDZDZ%[F",0O,?,?@PRXRoRo,pF))-i)<)<]FLfLf)gF&g	+ 	+s   OO'N)&__name__
__module____qualname____doc__r*   str__annotations__r+   boolr,   intr-   r.   r/   r0   r1   r3   r4   r   r   r6   r7   floatr9   r;   r<   r=   r?   r@   rB   rC   rD   rE   rF   rG   rH   classmethodrg        r&   r)   r)   R   sF   37NC7"t" #s"!$3$ "&$% $$"t"## !#!  ?>'Hc'+K+KKK  $#pp&M3& K#%S%"t" OT "%C% !OT #'D'995# 5*= 5 5rs   r)   c                       e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	e
ed<   dZeed<   dZeed	<   dZeed
<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   deeef   fdZy)TrajectoryMetricsz,Metrics for a single trajectory compression.r   original_tokenscompressed_tokenstokens_saved      ?compression_ratiooriginal_turnscompressed_turnsturns_removedturns_compressed_start_idxturns_compressed_end_idxturns_in_compressed_regionFwas_compressedstill_over_limitskipped_under_targetsummarization_api_callssummarization_errorsr   c                 j   | j                   | j                  | j                  t        | j                  d      | j
                  | j                  | j                  | j                  | j                  | j                  d| j                  | j                  | j                  | j                  | j                  dS )Nr2   )	start_idxend_idxturns_count)rv   rw   rx   rz   r{   r|   r}   compression_regionr   r   r   r   r   )rv   rw   rx   roundrz   r{   r|   r}   r   r   r   r   r   r   r   r   )selfs    r&   to_dictzTrajectoryMetrics.to_dict   s    #33!%!7!7 --!&t'='=q!A"11 $ 5 5!//!<<88#>>#
 #11 $ 5 5$($=$='+'C'C$($=$=#
 	
rs   N)rh   ri   rj   rk   rv   ro   rm   rw   rx   rz   rp   r{   r|   r}   r   r   r   r   rn   r   r   r   r   r   rl   r   r   rr   rs   r&   ru   ru      s    6OSsL#"u"NCcM3&(($&c&&'' ND "d"!&$&#$S$ !#!
c3h 
rs   ru   c                   z   e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	eed<   dZ
eed<   dZeed<   dZeed	<   dZeed
<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<    ee      Zee   ed<    ee      Zee   ed<    ee      Zee   ed<   dZeed<   dZeed<   dZeed<   defdZde ee!f   fdZ"y)AggregateMetricsz*Aggregate metrics across all trajectories.r   total_trajectoriestrajectories_compressed!trajectories_skipped_under_targettrajectories_still_over_limittrajectories_failedtotal_tokens_beforetotal_tokens_aftertotal_tokens_savedtotal_turns_beforetotal_turns_aftertotal_turns_removedtotal_summarization_callstotal_summarization_errors)default_factorycompression_ratiostokens_saved_listturns_removed_list processing_start_timeprocessing_end_timeg        processing_duration_secondsr[   c                    | xj                   dz  c_         | xj                  |j                  z  c_        | xj                  |j                  z  c_        | xj
                  |j                  z  c_        | xj                  |j                  z  c_        | xj                  |j                  z  c_	        | xj                  |j                  z  c_        | xj                  |j                  z  c_        | xj                  |j                   z  c_        |j"                  r| xj$                  dz  c_        | j&                  j)                  |j*                         | j,                  j)                  |j                         | j.                  j)                  |j                         |j0                  r| xj2                  dz  c_        |j4                  r| xj6                  dz  c_        yy)z,Add a trajectory's metrics to the aggregate.   N)r   r   rv   r   rw   r   rx   r   r{   r   r|   r   r}   r   r   r   r   r   r   r   appendrz   r   r   r   r   r   r   )r   r[   s     r&   add_trajectory_metricsz'AggregateMetrics.add_trajectory_metrics   sl   1$  G$;$;; 7#<#<<7#7#777#9#99'":"::  G$9$99 &&'*I*II&''7+G+GG'!!((A-(##**7+D+DE""))'*>*>?##**7+@+@A''22a72##..!3. $rs   r   c                 :   | j                   r+t        | j                         t        | j                         z  nd}| j                  r+t        | j                        t        | j                        z  nd}| j                  r+t        | j                        t        | j                        z  nd}| j
                  | j                  | j                  | j                  | j                  t        | j                  t        | j
                  d      z  d      d| j                  | j                  | j                  t        | j                  t        | j                  d      z  d      d| j                  | j                   | j"                  dt        |d      t        |d      t        |d      d	| j$                  | j&                  t        d| j&                  t        | j$                  d      z  z
  d      d
| j(                  | j*                  t        | j,                  d      ddS )Nry   r   r   r2   )r   r   r   r   r   compression_rate)total_beforetotal_aftertotal_savedoverall_compression_ratio)r   r   total_removedr:   )avg_compression_ratioavg_tokens_saved_per_compressed avg_turns_removed_per_compressed)total_api_callstotal_errorssuccess_rate)
start_timeend_timeduration_seconds)summarytokensturnsaveragesrX   rZ   )r   sumlenr   r   r   r   r   r   r   r   maxr   r   r   r   r   r   r   r   r   r   r   )r   r   avg_tokens_savedavg_turns_removeds       r&   r   zAggregateMetrics.to_dict  s    && ''(3t/F/F+GG,/ 	 %% &&'#d.D.D*EE+, 	 && ''(3t/F/F+GG,- 	 '+&=&=+/+G+G595[5[151S1S'+'?'?$)$*F*FTMdMdfgIh*hjk$l !% 8 8#66#66-243J3JSQUQiQiklMm3mop-q	 !% 7 7#55!%!9!9 *//Da)H389I13M49:KQ4O $(#A#A $ ? ? %a4+J+JSQUQoQoqrMs+s&tvw x #88 44$)$*J*JA$N=#
 #	
rs   N)#rh   ri   rj   rk   r   ro   rm   r   r   r   r   r   r   r   r   r   r   r   r   r
   listr   r   rp   r   r   r   rl   r   r   ru   r   r   r   r   rr   rs   r&   r   r      s   4#$S$-.%s.)*!3*    s  %&s&&'' ',D&AUA#(#>tCy>$)$$?S	?!#3#!!),,4.? 401
c3h 1
rs   r   c                      e Zd ZdZdefdZd Zd Zd Zde	fdZ
d	e	defd
Zdeee	e	f      defdZdeee	e	f      dee   fdZdeee	e	f      deeeef   fdZedeee	e	f      dedefd       Zedeee	e	f      dedededef
d       Zdeee	e	f      dedede	fdZedede	fd       Zede	de	fd       Zde	dede	fdZde	dede	fdZdeee	e	f      deeee	e	f      ef   fdZ deee	e	f      deeee	e	f      ef   fdZ!d ee	ef   deee	ef   ef   fd!Z"d ee	ef   deee	ef   ef   fd"Z#d#e$d$e$fd%Z%d#e$d$e$fd&Z&d' Z'y())TrajectoryCompressora  
    Compresses agent trajectories to fit within a target token budget.
    
    Compression strategy:
    1. Keep protected head turns (system, human, first gpt+tool)
    2. Keep protected tail turns (last N turns)
    3. From the compressible middle region, compress only as much as needed
    4. Replace compressed turns with a single human summary message
    5. Keep remaining middle turns intact (model continues with tools)
    rf   c                     || _         t               | _        | j                          | j	                          t        j                  t              | _        y)zInitialize the compressor.N)	rf   r   aggregate_metrics_init_tokenizer_init_summarizerlogging	getLoggerrh   logger)r   rf   s     r&   __init__zTrajectoryCompressor.__init__X  sB    !1!3 	 	''1rs   c                 B   	 ddl m} |j                  | j                  j                  | j                  j
                        | _        t        d| j                  j                          y# t        $ r*}t        d| j                  j                   d|       d}~ww xY w)z4Initialize HuggingFace tokenizer for token counting.r   )AutoTokenizer)r+   u   ✅ Loaded tokenizer: zFailed to load tokenizer 'z': N)
transformersr   from_pretrainedrf   r*   r+   rO   printr$   RuntimeError)r   r   es      r&   r   z$TrajectoryCompressor._init_tokenizere  s    	`2*::**"&++"?"? ; DN *4;;+E+E*FGH 	`!;DKK<V<V;WWZ[\Z]^__	`s   A(A+ +	B4%BBc                    | j                         }|rU|| _        d| _        ddlm}  ||| j
                  j                        \  }}|t        d| d      d| _        d| _	        nd| _        t        j                  | j
                  j                        }|s#t        d	| j
                  j                   d
      ddlm} ddlm}  || || j
                  j                               | _        d| _	        || _        t%        d| j
                  j                          t%        d| j
                  j&                          y)a  Initialize LLM routing for summarization (sync and async).

        Uses call_llm/async_call_llm from the centralized provider router
        which handles auth, headers, and provider detection internally.
        For custom endpoints, falls back to raw client construction.
        Tr   )resolve_provider_client)r   Nz
Provider 'z<' is not configured. Check your API key or run: hermes setupFzMissing API key. Set z environment variable.)OpenAI_to_openai_base_urlapi_keyr   u#   ✅ Initialized summarizer client: z   Max concurrent requests: )_detect_provider_llm_provider_use_call_llmr#   r   rf   r4   r   clientasync_clientosgetenvr6   openair   r   r   _async_client_api_keyr   rB   )r   providerr   r   _r   r   r   s           r&   r   z%TrajectoryCompressor._init_summarizerq  s=    ((*!)D!%DF/ ? ?AIFA~" 
 +> ?@ @ DK $D "'Dii 7 78G"+DKK,C,C+D E, -. . &B *=dkk>R>R*SUDK !%D)0D&3DKK4S4S3TUV,T[[-P-P,QRSrs   c                     ddl m} ddlm}  || j                   || j
                  j                              | _        | j                  S )a  Return an AsyncOpenAI client bound to the current event loop.

        Created lazily so that each ``asyncio.run()`` call in
        ``process_directory()`` gets a client tied to its own loop,
        avoiding "Event loop is closed" errors on repeated calls.
        r   )AsyncOpenAIr   r   )r   r   r#   r   r   rf   r   r   )r   r   r   s      r&   _get_async_clientz&TrajectoryCompressor._get_async_client  s@     	'>'..()=)=>
    rs   r   c                 `   | j                   j                  xs d}t        |d      ryt        |d      ryt        |      dk(  rd|j	                         v ryt        |d	      ry
t        |d      st        |d      st        |d      ryt        |d      ryt        |d      ryt        |d      ryy)z6Detect the provider name from the configured base_url.r   zopenrouter.ai
openrouterznousresearch.comnouszchatgpt.comz/backend-api/codexcodexzz.aizaizmoonshot.aizmoonshot.cnzapi.kimi.comzkimi-codingzarcee.aiarceezminimaxi.comz
minimax-cnz
minimax.iominimax)rf   r   r   r   lower)r   urls     r&   r   z%TrajectoryCompressor._detect_provider  s    kk""(b o6 &89c"m3$		3 f-!#}5$S-8$S.9  j1 n5 l3rs   textc                     |sy	 t        | j                  j                  |            S # t        $ r t        |      dz  cY S w xY w)z4Count tokens in text using the configured tokenizer.r   r2   )r   rO   encoder$   )r   r   s     r&   count_tokensz!TrajectoryCompressor.count_tokens  sD    	"t~~,,T233 	"t9>!	"s   #) AA
trajectoryc                 ,     t         fd|D              S )z#Count total tokens in a trajectory.c              3   `   K   | ]%  }j                  |j                  d d             ' yw)valuer   Nr   rb   ).0turnr   s     r&   	<genexpr>z?TrajectoryCompressor.count_trajectory_tokens.<locals>.<genexpr>  s'     S4$$TXXgr%:;Ss   +.)r   )r   r   s   ` r&   count_trajectory_tokensz,TrajectoryCompressor.count_trajectory_tokens  s    S
SSSrs   c           	      j    |D cg c]#  }| j                  |j                  dd            % c}S c c}w )z+Count tokens for each turn in a trajectory.r   r   r   )r   r   r   s      r&   count_turn_tokensz&TrajectoryCompressor.count_turn_tokens  s,    EOPT!!$((7B"78PPPs   (0c                 f   t        |      }t               }dx}x}x}}t        |      D ]@  \  }}	|	j                  dd      }
|
dk(  r||}"|
dk(  r||},|
dk(  r||}6|
dk(  s<|?|}B | j                  j
                  r||j                  |       | j                  j                  r||j                  |       | j                  j                  r||j                  |       | j                  j                  r||j                  |       t        t        d|| j                  j                  z
        |      D ]  }|j                  |        |D cg c]  }||d	z  k  s| }}|D cg c]  }||d	z  k\  s| }}|rt        |      d
z   nd}|rt        |      n|}|||fS c c}w c c}w )z
        Find indices of protected turns.
        
        Returns:
            Tuple of (protected_set, compressible_start, compressible_end)
        Nfromr   systemhumangpttoolr   r:   r   )r   set	enumeraterb   rf   r.   addr/   r0   r1   ranger   r3   min)r   r   n	protectedrS   rT   rU   rV   ir   rolehead_protectedtail_protectedcompressible_startcompressible_ends                  r&   _find_protected_indicesz,TrajectoryCompressor._find_protected_indices  s    
OE	 ?CBB{BY , 		GAt88FB'DxL$8 [%89#4	J$6
		 ;;++0HMM,';;**{/FMM+&;;((Y-BMM)$;;))j.DMM*% s1a$++"B"BBCQG 	AMM!	
 &/=!a1f*!==%.>!qAv+!>>8FS014A2@3~.a,.>>> >>s   F)%F)/F.=F.idxc                 P    |t        |       k\  xs | |   j                  d      dk7  S )a  Return True if a region boundary at ``idx`` does not split a turn pair.

        In the from/value trajectory format a ``tool`` turn (carrying
        ``<tool_response>`` markers) is always emitted immediately after the
        ``gpt`` turn whose ``<tool_call>`` it answers. A compression boundary
        that lands *on* a ``tool`` turn therefore cuts between a tool call and
        its response. A boundary is only clean when it sits at the very end of
        the trajectory or on a non-``tool`` turn.
        r  r  )r   rb   )r   r  s     r&   _is_boundary_cleanz'TrajectoryCompressor._is_boundary_clean  s,     c*o%NC)<)<V)D)NNrs   min_idxmax_idxc                    |}||k  r/| j                  ||      s|dz  }||k  r| j                  ||      s| j                  ||      r|S |}||kD  r/| j                  ||      s|dz  }||kD  r| j                  ||      s|S )a  Move a compression boundary onto the nearest clean turn boundary.

        Moving forward is preferred so that an orphaned ``tool`` turn is folded
        into the region that already holds its ``gpt`` turn; if no clean
        boundary exists ahead (for example the protected tail itself begins on a
        ``tool`` turn) the boundary is moved backward instead. The result is
        clamped to ``[min_idx, max_idx]``.
        r   )r  )rc   r   r  r  r  forwardbackwards          r&   _snap_boundaryz#TrajectoryCompressor._snap_boundary  s      (>(>z7(SqLG (>(>z7(S!!*g6N )?)?
H)UMH  )?)?
H)Urs   startendc           	      $   g }t        ||      D ]o  }||   }|j                  dd      }|j                  dd      }t        |      dkD  r|dd dz   |d	d z   }|j                  d
| d|j	                          d|        q dj                  |      S )a-  
        Extract content from turns to be summarized.
        
        Args:
            trajectory: Full trajectory
            start: Start index (inclusive)
            end: End index (exclusive)
            
        Returns:
            Formatted string of turn contents for summarization
        r  unknownr   r   i  Ni  z
...[truncated]...
iz[Turn z - z]:
z

)r  rb   r   r   upperjoin)	r   r   r  r   partsr  r   r  r   s	            r&   !_extract_turn_content_for_summaryz6TrajectoryCompressor._extract_turn_content_for_summary4  s     uc" 		CAa=D88FI.DHHWb)E 5zD et'>>tuMLL6!C

~T%AB		C {{5!!rs   contentc                 `    t        | t              s| rt        |       nd} | j                         S )z0Normalize summary-model output to a safe string.r   )
isinstancerl   strip)r'  s    r&   _coerce_summary_contentz,TrajectoryCompressor._coerce_summary_contentN  s'     '3'&-c'l2G}}rs   r   c                 b    | xs dj                         }|j                  d      r|S |sdS d| S )zCNormalize summary text to include the expected prefix exactly once.r   z[CONTEXT SUMMARY]:z[CONTEXT SUMMARY]: )r*  
startswith)r   r   s     r&   _ensure_summary_prefixz+TrajectoryCompressor._ensure_summary_prefixU  s>     2$$&??/0K+/#Q7J4&5QQrs   r[   c           	         d| j                   j                   d| d}t        | j                   j                        D ]k  }	 |xj                  dz  c_        t        | j                   j                  | j                   j                  | j                   j                        }t        | dd      rMddl
m}  || j                  | j                   j                  d	|d
g|| j                   j                  dz        }nl| j                   j                  d	|d
g| j                   j                  dz  d}|||d<    | j                  j                  j                  j                   di |}| j#                  |j$                  d   j&                  j(                        }	| j+                  |	      c S  y# t,        $ r}
|xj.                  dz  c_        | j0                  j3                  d|dz    d|
        || j                   j                  dz
  k  r9t5        j6                  t9        |dz   | j                   j:                  d             nY d}
~
 yY d}
~
d}
~
ww xY w)z
        Generate a summary of the compressed turns using OpenRouter.
        
        Args:
            content: The content to summarize
            metrics: Metrics object to update
            
        Returns:
            Summary string
          Summarize the following agent conversation turns concisely. This summary will replace these turns in the conversation history.

Write the summary from a neutral perspective describing what the assistant did and learned. Include:
1. What actions the assistant took (tool calls, searches, file operations)
2. Key information or results obtained
3. Any important decisions or findings
4. Relevant data, file names, values, or outputs

Keep the summary factual and informative. Target approximately " tokens.

---
TURNS TO SUMMARIZE:
H
---

Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix.r   r   Fr   )call_llmuserr  r'  r:   r   r   messagesr7   
max_tokensr   r7  r8  Nr7   Summarization attempt 	 failed:       >@
base_delay	max_delay[CONTEXT SUMMARY]: [Summary generation failed - previous turns contained tool calls and responses that have been compressed to save context space.]rr   )rf   r-   r  r9   r   r'   r4   r7   r   getattrr#   r3  r   r   chatcompletionscreater+  choicesmessager'  r.  r$   r   r   warningtimesleepr   r;   )r   r'  r[   promptattemptsummary_temperaturer3  response_create_kwargsr   r   s              r&   _generate_summaryz&TrajectoryCompressor._generate_summary]  s(   @ AE@a@a?b c 		 
CF" T[[445 '	qG&q//14/&FKK33KK++KK(('# 4%8?'!%!3!3"kk==+1f"E!F$7#';;#D#Dq#H H "&!@!@.4%H$I&*kk&G&G!&K&N
 +68K}5Bt{{//;;BBT^TH66x7G7G7J7R7R7Z7Z[227;;;'	q>  q,,1,##&<Wq[MSTRU$VWT[[44q88JJ/!H_H_kopq q rqs   E&F--	I6BIIc           	        K   d| j                   j                   d| d}t        | j                   j                        D ]  }	 |xj                  dz  c_        t        | j                   j                  | j                   j                  | j                   j                        }t        | dd      rUddl
m}  || j                  | j                   j                  d	|d
g|| j                   j                  dz         d{   }nx| j                   j                  d	|d
g| j                   j                  dz  d}|||d<    | j                         j                  j                  j                   di | d{   }| j#                  |j$                  d   j&                  j(                        }	| j+                  |	      c S  y7 7 M# t,        $ r}
|xj.                  dz  c_        | j0                  j3                  d|dz    d|
        || j                   j                  dz
  k  rBt5        j6                  t9        |dz   | j                   j:                  d             d{  7   nY d}
~
 yY d}
~
4d}
~
ww xY ww)a
  
        Generate a summary of the compressed turns using OpenRouter (async version).
        
        Args:
            content: The content to summarize
            metrics: Metrics object to update
            
        Returns:
            Summary string
        r0  r1  r2  r   r   Fr   )async_call_llmr4  r5  r:   r6  Nr9  r7   r:  r;  r<  r=  r@  rr   )rf   r-   r  r9   r   r'   r4   r7   r   rA  r#   rQ  r   r   rB  rC  rD  r+  rE  rF  r'  r.  r$   r   r   rG  asynciorI  r   r;   )r   r'  r[   rJ  rK  rL  rQ  rM  rN  r   r   s              r&   _generate_summary_asyncz,TrajectoryCompressor._generate_summary_async  sN    @ AE@a@a?b c 		 
CF" T[[445 '	qG&q//14/&FKK33KK++KK(('# 4%8E%3!%!3!3"kk==+1f"E!F$7#';;#D#Dq#H&  H "&!@!@.4%H$I&*kk&G&G!&K&N
 +68K}5%UT%;%;%=%B%B%N%N%U%U%gXf%ggH66x7G7G7J7R7R7Z7Z[227;;;'	q   h
  q,,1,##&<Wq[MSTRU$VWT[[44q88!--(81QUQ\Q\QhQhtx(yzzz q {qsd   AI;B:G>G?A8G7G8AG>I;GG	I8BI3 I#!I3'I;3I88I;c                    t               }t        |      |_        | j                  |      }t	        |      }||_        || j                  j                  k  r)d|_        ||_	        t        |      |_
        d|_        ||fS | j                  |      \  }}}| j                  ||||      }||k\  r9||_	        t        |      |_
        || j                  j                  kD  |_        ||fS || j                  j                  z
  }|| j                  j                  z   }	d}
|}t!        ||      D ]  }|
||   z  }
|dz   }|
|	k\  s n |
|	k  r||k  r|}t	        |||       }
| j                  ||||      }||k  r9||_	        t        |      |_
        || j                  j                  kD  |_        ||fS ||_        ||_        ||z
  |_        | j)                  |||      }| j+                  ||      }g }t!        |      D ]o  }||   j-                         }|j/                  d      dk(  r5| j                  j0                  r|d   | j                  j2                  z   |d<   |j5                  |       q |j5                  d|d	       t!        |t        |            D ]$  }|j5                  ||   j-                                & t        |      |_
        | j7                  |      |_	        |j                  |j                  z
  |_        |j
                  |j                  z
  |_        |j                  t=        |j
                  d      z  |_        d|_        |j                  | j                  j                  kD  |_        ||fS )
a|  
        Compress a single trajectory to fit within target token budget.
        
        Algorithm:
        1. Count total tokens
        2. If under target, skip
        3. Find compressible region (between protected head and tail)
        4. Calculate how many tokens need to be saved
        5. Accumulate turns from start of compressible region until savings met
        6. Replace accumulated turns with single human summary
        7. Keep remaining turns intact
        
        Args:
            trajectory: List of conversation turns
            
        Returns:
            Tuple of (compressed_trajectory, metrics)
        Try   r   r   r  r  r   r  r  r   ) ru   r   r{   r  r   rv   rf   r,   r   rw   r|   rz   r  r  r   r-   r  r   r   r   r&  rO  copyrb   r<   r=   r   r   r}   rx   r   r   r   r   r[   turn_tokenstotal_tokensr  compress_startcompress_endtokens_to_savetarget_tokens_to_compressaccumulated_tokenscompress_untilr  content_to_summarizer   
compressedr   s                    r&   compress_trajectoryz(TrajectoryCompressor.compress_trajectory  s   , $%!$Z ,,Z8;'". 4;;888+/G((4G%'*:G$(+G%w&& 372N2Nz2Z/	>< ,,ZYef \)(4G%'*:G$'3dkk6S6S'SG$w&& &(E(EE %3T[[5V5V$V! '~|4 	A+a.0UN "%>>	  99n|>[)N!$[%M!N ,,ZYef^+(4G%'*:G$'3dkk6S6S'SG$w&& .<*+9(-;n-L*  $EE 

 (()=wG 
 ~& 	$Aa=%%'Dxx8+0N0N $W0O0O OWd#	$ 	
 	 ~s:7 	4Ajm0023	4 $'z? $($@$@$L! ' 6 69Q9Q Q&669R9RR$+$=$=GD[D[]^@_$_!!%#*#<#<t{{?\?\#\ 7""rs   c                   K   t               }t        |      |_        | j                  |      }t	        |      }||_        || j                  j                  k  r)d|_        ||_	        t        |      |_
        d|_        ||fS | j                  |      \  }}}| j                  ||||      }||k\  r9||_	        t        |      |_
        || j                  j                  kD  |_        ||fS || j                  j                  z
  }|| j                  j                  z   }	d}
|}t!        ||      D ]  }|
||   z  }
|dz   }|
|	k\  s n |
|	k  r||k  r|}t	        |||       }
| j                  ||||      }||k  r9||_	        t        |      |_
        || j                  j                  kD  |_        ||fS ||_        ||_        ||z
  |_        | j)                  |||      }| j+                  ||       d{   }g }t!        |      D ]o  }||   j-                         }|j/                  d      dk(  r5| j                  j0                  r|d   | j                  j2                  z   |d<   |j5                  |       q |j5                  d	|d
       t!        |t        |            D ]$  }|j5                  ||   j-                                & t        |      |_
        | j7                  |      |_	        |j                  |j                  z
  |_        |j
                  |j                  z
  |_        |j                  t=        |j
                  d      z  |_        d|_        |j                  | j                  j                  kD  |_        ||fS 7 w)z
        Compress a single trajectory to fit within target token budget (async version).
        
        Same algorithm as compress_trajectory but uses async API calls for summarization.
        Try   r   r   Nr  r  r   r  rU  ) ru   r   r{   r  r   rv   rf   r,   r   rw   r|   rz   r  r  r   r-   r  r   r   r   r&  rS  rV  rb   r<   r=   r   r   r}   rx   r   r   rW  s                    r&   compress_trajectory_asyncz.TrajectoryCompressor.compress_trajectory_asynco  s     $%!$Z ,,Z8;'". 4;;888+/G((4G%'*:G$(+G%w&& 372N2Nz2Z/	>< ,,ZYef \)(4G%'*:G$'3dkk6S6S'SG$w&& &(E(EE$2T[[5V5V$V! '~|4 	A+a.0UN!%>>		  99n|>[)N!$[%M!N ,,ZYef^+(4G%'*:G$'3dkk6S6S'SG$w&& .<*+9(-;n-L*  $EE 

 445I7SS 
 ~& 	$Aa=%%'Dxx8+0N0N $W0O0O OWd#		$ 	
 	 ~s:7 	4Ajm0023	4 $'z? $($@$@$L! ' 6 69Q9Q Q&669R9RR$+$=$=GD[D[]^@_$_!!%#*#<#<t{{?\?\#\ 7""? Ts   D>NB/N0N1FNentryc                   K   d|vrt               }||fS |d   }| j                  |       d{   \  }}|j                         }||d<   | j                  j                  r|j
                  r|j                         |d<   ||fS 7 Uw)z?
        Process a single JSONL entry (async version).
        conversationsNcompression_metrics)ru   rd  rV  rf   rG   r   r   r   re  r[   r   compressed_trajectoryresults         r&   process_entry_asyncz(TrajectoryCompressor.process_entry_async  s      %'')G'>!?+
/3/M/Mj/Y)Y&w "7 ;;--'2H2H,3OO,=F()w *Zs   ,BBABc                     d|vrt               }||fS |d   }| j                  |      \  }}|j                         }||d<   | j                  j                  r|j
                  r|j                         |d<   ||fS )z
        Process a single JSONL entry.
        
        Args:
            entry: JSONL entry containing 'conversations' field
            
        Returns:
            Tuple of (processed_entry, metrics)
        rg  rh  )ru   rb  rV  rf   rG   r   r   ri  s         r&   process_entryz"TrajectoryCompressor.process_entry  s     %'')G'>!?+
)-)A)A*)M&w "7 ;;--'2H2H,3OO,=F()wrs   	input_dir
output_dirc                 N    t        j                  | j                  ||             y)z
        Process all JSONL files in a directory using async parallel processing.
        
        Args:
            input_dir: Input directory containing JSONL files
            output_dir: Output directory for compressed files
        N)rR  run_process_directory_async)r   ro  rp  s      r&   process_directoryz&TrajectoryCompressor.process_directory  s     	D11)ZHIrs   c                 P    K   t               }t        j                         j                          j                  _        t        j                         }t        |j                  d            }|s j                  j                  d|        y|j                  d       g }|D ]j  }t        |dd      5 }t        |      D ]B  \  }	}
|
j                         }
|
s	 t        j                   |
      }|j#                  ||	|f       D 	 ddd       l t'        |      }|j                  dd        |j                  d|        |j                  d|        |j                  dt'        |              |j                  d|d       |j                  d j(                  j*                  d       |j                  d j(                  j,                          |j                  d j(                  j.                          |j                  d d       t1        j2                   j(                  j.                        t1        j4                         dddd|D ci c]  }|i  c}d dt6        dt8        dt:        f  f	d}t=        t?               tA        d      tC               tE               tA        d      tG               tA        d      tI               |d
      5 }|jK                  d|dd|       }|jK                  d!d       }|D cg c]  \  }}} |||||||       }}}}t1        jL                  |  d{    |jO                  |       ddd       |j                  d"       |jQ                  d#d#$       |D ]  }||jR                  z  }|   }t        |jU                               D cg c]  }||   ||   d    }}t        |d%d      5 }|D ]+  }|jW                  t        jX                  |d&'      dz          - 	 ddd        t        j                         j                          j                  _-        t        j                         |z
   j                  _.         j_                           j(                  j`                  ru| j(                  jb                  z  }t        |d%d      5 }t        jd                   j                  jg                         |d()       ddd       |j                  d*|        yy# t        j$                  $ r/} j                  j                  d| d	|	 d
|        Y d}~d}~ww xY w# 1 sw Y   xY wc c}w c c}}}w 7 '# 1 sw Y   xY wc c}w # 1 sw Y   xY w# 1 sw Y   xY ww)+zW
        Async implementation of directory processing with parallel API calls.
        *.jsonlzNo JSONL files found in Nz"
[dim]Loading all entries...[/dim]rK   rL   rM   zSkipping invalid JSON at :: 
<============================================================u   📂 Input: u   📂 Output: u   📄 Files to process: u   📊 Total trajectories: ,u   🎯 Target max tokens: u   📝 Summary target tokens: u   ⚡ Max concurrent API calls: r   	file_path	entry_idxre  c                 >  	K   4 d{    4 d{    dz  ddd      d{    	 t        j                  j                  |      j                  j                         d{   \  }}||f|    |<   4 d{    j
                  j                  |       |j                  r
dz  
	|j                  z  	|j                  rdz  dz  |j                  |       |j                  |d
 d d d	 d d	
       ddd      d{    ddd      d{    y7 &7 7 # 1 d{  7  sw Y   xY w7 7 7 8# 1 d{  7  sw Y   HxY w# t         j                  $ r j                  j                  d|  d| dj                  j                   d       4 d{  7   j
                  xj                  dz  c_        dz  dz  |j                  |       |j                  |d
 d d d	 d d	
       ddd      d{  7   n# 1 d{  7  sw Y   nxY wd|    |<   Y 2t         $ r}j                  j#                  d|  d| d|        4 d{  7   j
                  xj                  dz  c_        dz  |j                  |       ddd      d{  7   n# 1 d{  7  sw Y   nxY w|t%               f|    |<   Y d}~d}~ww xY w7 # 1 d{  7  sw Y   yxY ww)z@Process a single entry with semaphore rate limiting and timeout.Nr   )timeoutu	   [dim]✅ u    compressed | ⏭️ u    skipped | ⏱️ u    timeout | 🔄 u    API calls | ⚡ z in-flight[/dim])descriptionzTimeout processing entry from rw  z (>zs)zError processing entry from rx  )rR  wait_forrl  rf   rE   r   r   r   r   r   advanceupdateTimeoutErrorr   rG  r   r$   errorru   )r|  r}  re  progress	main_taskstatus_taskprocessed_entryr[   r   	api_callscompressed_count	in_flightprogress_lockresultsr   	semaphoreskipped_counttimeout_counts            r&   process_singlezETrajectoryCompressor._process_directory_async.<locals>.process_singleX  s    
 ! :Q :Q( # #NI# #5Q5<5E5E007 $ B B6 0,OW 6Eg4NGI&y1  -  ..EEgN #11,1,%)H)HHI"77)Q.M!Q	 !((3 '*34D3EEZ[hZii{  }J  |K  K[  \e  [f  fw  xA  wB  BR  )S (  :Q :Q :Q# # # # #
0    & ++ 9KK''*HSTU^T__bcgcncn  dF  dF  cG  GI  )J  K,  ..BBaGB%*!Q	 ((3 '*34D3EEZ[hZii{  }J  |K  K[  \e  [f  fw  xA  wB  BR  )S (      59GI&y1  	QKK%%(DYKqQZP[[]^_]`&ab, 4 4..BBaGB!Q	 ((34 4 4 4 4 6;<M<O4PGI&y1	Qc:Q :Q :Q :Qs  LD0LLD3LD9LD6L=E*-E.E*EE*	BEE*EE*L*L+L3L6L9E	?E E	LE*E*E*E'	EE'	#E**AL<F?
=LAH1L*H-+L1I7H:8I?LLL*K=J
K=6K>K=	K
K=K"KK"K=7L=LLLLLLLz([progress.description]{task.description}u   •
   )consolerefresh_per_secondz[cyan]Compressing  trajectories)totalz[dim]Starting...[/dim]z#
[dim]Writing output files...[/dim]Tparentsexist_okwFensure_asciir:   )indentu   
💾 Metrics saved to )4r   r   now	isoformatr   r   rH  sortedglobr   rG  r   r_   r	  r*  jsonloadsr   JSONDecodeErrorr   rf   r,   r-   rB   rR  	SemaphoreLockr   ro   r   r   r   r   r   r   r   r   add_taskgatherremove_taskmkdirrP   keyswritedumpsr   r   _print_summaryrF   rH   dumpr   )!r   ro  rp  r  r   jsonl_filesall_entriesr|  rd   line_numlinere  r   total_entriesr  r  r  r  r}  tasksoutput_pathfile_resultsr  sorted_entriesmetrics_pathr  r  r  r  r  r  r  r  s!   `                        @@@@@@@@r&   rs  z-TrajectoryCompressor._process_directory_async  s     ) 8@||~7O7O7Q4YY[
 Y^^I67KK":9+ FG 	;<$ 		iIiw7 i1&/l iNHd::<Di$(JJt$4E'..	8U/KLii i		i K(6(m$YK01j\23/K0@/ABC1-1BCD01N1Nq0QRS4T[[5V5V4WXY6t{{7Z7Z6[\]m$ %%dkk&I&IJ	  		 #..Q1b5. ?	QD ?	QS ?	Q ?	Q ?	QD OABK uu!!
 "	.  ))$]1$5]C# * I #++( , K 4? /Iy% y)UHiQ\]E  ..%(((   -E"	.J 	<=5$ 	JI$y~~5K"9-L
 ","3"3"56$0 S!!$N  k39 JQ+ JEGGDJJu5ADHIJJ J	J  6>\\^5M5M5O2=AYY[:=U: 	 ;;&&%(G(GGLlC': Ia		$0088:AaHIMM4\NCD	 'A  $33 i KK//2KI;VWX`Waacdecf0ghhii iB /@ )?"	. "	.ZJ JI Is   B1V&<$U")TUEV&'
U,1A=V&.2U; U1
8U;U8U;'A V&VV&+1VB.V&1V<V&U	-$U	UU	UU)	$V&1U;;V V&V	V&V#V&c                 
   | j                   j                         }|d   d   }|d   d   }|d   d   }|d   d   }|d   d   }|d   d   }|d   d	   }|d   d
   }	|t        |d      z  dz  }
|t        |d      z  dz  }|t        |d      z  dz  }t        d       t        dd d       t        dddd       t        dd d       t        ddddd d       t        dd d       t        dddd|dd d       t        dddd|dd |
d!d"d# d	       t        dddd$|d%d |d!d"d# d	       t        dddd&|dd |d!d"d# d	       t        dddd'|dd d       t        dd d       t        dddd(d) d       t        dd d       t        dddd*|d+d,d- d       t        dddd.|d+d,d- d       t        dddd/|	d+d,d- d       t        dddd0|d   d1   d2d3 d       |d4kD  r|	|z  dz  }t        dddd5|d6d7d3 d       t        dd d       t        dddd8d9 d       t        dd d       t        dddd*|d:   d   d+d;d< d       t        dddd.|d:   d	   d+d;d< d       t        dddd=|d:   d>   d+d;d< d       t        dd d       t        dddd?d@ d       t        dd d       |d4kD  rUt        ddddA|dB   dC   d2d3 d       t        ddddD|dB   dE   dFd3 d       t        ddddG|dB   dH   d6d3 d       nt        ddddIdJ d       t        dd d       t        ddddKdL d       t        dd d       t        ddddM|dN   dO   d+d@ d       t        ddddP|dN   dQ   d+d@ d       t        ddddR|dN   dS   d2d3 d       t        dd d       |dT   dU   }|dVkD  r
|dVz  dWdX}n|dWdY}|t        |dZ      z  }t        dddd[d\ d       t        dd d       t        dddd]|d^d< d       t        dddd_|d`dad# d       t        ddddb|dT   dc   ddde d^d< d       t        ddddf|dT   dg   ddde d^d< d       t        dhd di       | j                   j                  r| j                   j                  }| j                   j
                  }t        dj       t        dkt        |      dldmt        |      dldnt        |      t        |      doz     dl       t        dpt        |      dqdmt        |      dqdnt        |      t        |      doz     dq       ydyd)rz3Print comprehensive compression summary statistics.r   r   r   r   r   r   r   r   r   r   r   d   ry  u   ╔u   ══════════════════════════════════════════════════════════════════════u   ╗u   ║zTRAJECTORY COMPRESSION REPORTz^70u   ╠u   ╣r   2u   📁 TRAJECTORIESz6                                                      u   ──────────────────────────────────────────────────────────────────────4zTotal Processed:        z>10,z                                 u   ├─ Compressed:          z  (z>5.1fz%)z                  u   ├─ Skipped (under limit):z>9,u   ├─ Still over limit:    u   └─ Failed:              u   🔢 TOKENSz<                                                            zBefore Compression:     z>15,z tokensz                     zAfter Compression:      zTotal Saved:            zOverall Compression:    r   z>14.1%z                            r   zSpace Savings:          z>14.1f%u   💬 CONVERSATION TURNSz0                                                r   z turnsz                      zTotal Removed:          r   u,   📈 AVERAGES (Compressed Trajectories Only)z                           zAvg Compression Ratio:  r   r   zAvg Tokens Saved:       r   z>14,.0fzAvg Turns Removed:      r   zNo trajectories were compressedz&                                      u   🤖 SUMMARIZATION APIz1                                                 zAPI Calls Made:         rX   r   zErrors:                 r   zSuccess Rate:           r   rZ   r   <   z.1fz minutesz secondsgMbP?u   ⏱️  PROCESSING TIMEz3                                                   zDuration:               z>20zThroughput:             z>15.1fz	 traj/seczStarted:                r   N   zFinished:               r   u   ╚u   ╝u   
📊 Distribution Summary:z   Compression ratios: min=z.2%z, max=z	, median=r:   z   Tokens saved:       min=r{  )	r   r   r   r   r   r   r  r  r   )r   mr  ra  skipped
over_limitfailedtokens_beforetokens_afterrx   compressed_pctskipped_pctover_limit_pctsavings_pctdurationtime_str
throughputratiosr   s                      r&   r  z#TrajectoryCompressor._print_summary  s   ""**, )12y\";<
I,BCy\"AB
934 (N3{=1{=1 %s5!}4;UA.#5$s5!}4;dH:S!"3C8<=H:S!" 	Bq6*6(#67H:S!"Bq61%fXSIJBq65j5Fc.Y^I__abhaiilmnBq66wsm3{SXFYY[\b[ccfghBq65j5Fc.Y^I__abhaiilmnBq65fT]6(#NOH:S!" 	Bq6VHC01H:S!"Bq61-1EWVHTWXYBq61,t1DGF8SVWXBq61,t1DGF8SVWXBq61!H+>Y2Z[a1bcibjjmno1'-73>KC1v5k&5I6(RUVWH:S!" 	Bq60<=H:S!"Bq61!G*^2LT1RRXY_X``cdeBq61!G*]2KD1QQWX^W__bcdBq61!G*_2Md1SSYZ`YaadefH:S!" 	Bq6EfXSQRH:S!">C1v5a
mD[6\]c5dekdllopqC1v5a
mDe6fgn5opvowwz{|C1v5a
mDf6ghn5opvowwz{|C1v<VHCHIH:S!" 	Bq6/xs;<H:S!"Bq61!O2DEV2WX\1]^d]eehijBq61!O2D^2TUY1Z[aZbbefgBq61!O2D^2TU[1\]c\ddghiH:S!" \?#56b="2+c*(3H"3x0HS511
Bq60<=H:S!"Bq61(3xsKLBq61*V1DIfXUXYZBq61!L/,2OPSQS2TUX1YZ`YaadefBq61!L/*2Mcr2RSV1WX^W__bcdH:S!" !!44++>>F $ 6 6 H H01/FC/@s6{SVFWW`aghnaopstzp{}~p~a  AD  aE  F  G/4E0Fq/IPSTePfghOiirsy  {L  tM  NQ  Rc  Nd  fg  Ng  th  ij  sk  l  m 5rs   N)(rh   ri   rj   rk   r)   r   r   r   r   rl   r   ro   r   r   r   r   r  r   r  r  staticmethodrn   r  rq   r  r&  r   r+  r.  ru   rO  rS  rb  rd  rl  rn  r   rt  rs  r  rr   rs   r&   r   r   L  s!   	20 2
`+TZ! # :" " "T$tCH~2F T3 TQDc3h,@ QT#Y Q.?$tCH~2F .?5QTVY[^Q^K_ .?` 
OtDcN'; 
O# 
O$ 
O 
O c3h(  	
  
 2"Dc3h<P "Y\ "cf "kn "4     R R R RCq Cq7H CqS CqJCqS CqCT CqY\ CqJF#c3h(F# 
tDcN#%66	7F#Pp#c3h(p# 
tDcN#%66	7p#dtCH~ %SRUXXiHiBj *4S> eDcNL]<]6^ 6	J4 	JT 	JAE AE$ AEFjmrs   r   inputrY   rf   r,   rO   sample_percentseeddry_runc                    ddl }ddl}	ddl}
t        d       t        d       t	        |      }|j                         r$t        d|        t        j                  |      }nt        d| d       t               }|r||_        |r||_	        |+|dk  s|dkD  rt        d	|        yt        d
| d| d       t	        |       }|j                         st        d|         y|j                         }|rt        d       |rt	        |      }n)|j                  |j                  |j                  z   dz   z  }g }t        |dd      5 }t        |d      D ]=  \  }}|j!                         }|s	 |j#                  t%        j&                  |             ? 	 ddd       t+        |      }t        d|dd|j,                          |^|j/                  |       t1        dt3        ||z  dz              }|j5                  ||      }t        dt+        |      dd| d|dd       |r3t        d       t        dt+        |      dd       t        d|        y|	j7                         5 }t	        |      d z  }t	        |      d!z  }|j9                          |d"z  }t        |d#d      5 }|D ]+  }|j;                  t%        j<                  |d$%      d&z          - 	 ddd       t?        |      }|jA                  ||       |j                  j9                  d'd'(       t        |d#d      5 }tC        |jE                  d)            D ]2  }t        |dd      5 }|D ]  }|j;                  |        	 ddd       4 	 ddd       ||jF                  z  } | j                         r<|j                  |j                  d*z   z  }!|
jI                  | |!       t        d+|!        ddd       t        d,       t        d-|        yt        d.       |rt	        |      }n&|j                  |j,                  |j                  z   z  }|t        d/| d0       |	j7                         5 }t	        |      d z  }|j9                          |j/                  |       d}"d}#tC        |jE                  d)            D ]  }g }t        |dd      5 }|D ]:  }|j!                         }|s	 |j#                  t%        j&                  |             < 	 ddd       |"t+        |      z  }"t1        dt3        t+        |      |z  dz              }|j5                  |tK        |t+        |                  }$|#t+        |$      z  }#||j,                  z  }%t        |%d#d      5 }|$D ]+  }|j;                  t%        j<                  |d$%      d&z          - 	 ddd        t        d|#dd1|"dd2       |r1t        d       t        d3|        t        d4|        	 ddd       yt?        |      }|jA                  ||       ddd       nG|r(t        d       t        d3|        t        d4|        yt?        |      }|jA                  ||       t        d,       y# t$        j(                  $ r}t        d| d|        Y d}~bd}~ww xY w# 1 sw Y   +xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   kxY w# 1 sw Y   xY w# t$        j(                  $ r Y Nw xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)5a  
    Compress agent trajectories to fit within a target token budget.
    
    Supports both single JSONL files and directories containing multiple JSONL files.
    Optionally sample a percentage of trajectories before compression.
    
    Args:
        input: Path to JSONL file or directory containing JSONL files
        output: Output path (file for file input, directory for dir input)
                Default: adds "_compressed" suffix to input name
        config: Path to YAML configuration file
        target_max_tokens: Override target token count from config
        tokenizer: Override tokenizer name from config
        sample_percent: Sample this percentage of trajectories (1-100) before compression
        seed: Random seed for sampling reproducibility (default: 42)
        dry_run: Analyze without compressing (just show what would happen)
    
    Examples:
        # Compress a directory (original behavior)
        python trajectory_compressor.py --input=data/my_run
        
        # Compress a single file
        python trajectory_compressor.py --input=data/trajectories.jsonl
        
        # Compress 15% sample of a file
        python trajectory_compressor.py --input=data/trajectories.jsonl --sample_percent=15
        
        # Compress 10% sample with custom output
        python trajectory_compressor.py --input=data/trajectories.jsonl --sample_percent=10 --output=data/sampled_compressed.jsonl
    r   Nu   🗜️  Trajectory Compressorrz  u   📋 Loading config from u   ⚠️  Config not found at z, using defaultsr  u2   ❌ sample_percent must be between 1 and 100, got u   🎲 Will sample z% of trajectories (seed=)u   ❌ Input not found: u"   📄 Input mode: Single JSONL filez.jsonlrK   rL   rM   r   u&   ⚠️  Skipping invalid JSON at line rx  z
   Loaded r{  z trajectories from z   Sampled z trajectories (z% of u.   
🔍 DRY RUN MODE - analyzing without writingu   📄 Would process: r  u   📄 Would output to: r  rY   ztrajectories.jsonlr  Fr  ry  Tr  rv  z_metrics.jsonu   💾 Metrics saved to u   
✅ Compression complete!u   📄 Output: u)   📁 Input mode: Directory of JSONL filesu.   
⚠️  Sampling from directory: will sample z% from each filez from z total trajectoriesu   📁 Would process: u   📁 Would output to: )&randomtempfileshutilr   r   existsr)   rg   r,   r*   is_fileparentstemr?   r_   r	  r*  r   r  r  r  r   rP   r  r   ro   sampleTemporaryDirectoryr  r  r  r   rt  r  r  rH   rV  r  )&r  rY   rf   r,   rO   r  r  r  r  r  r  config_pathcompression_config
input_pathis_file_inputr  entriesrd   r  r  r   r  sample_sizetemp_dirtemp_input_dirtemp_output_dirtemp_input_filere  
compressorout_f
jsonl_filein_fmetrics_filemetrics_outputtotal_originaltotal_sampledsampled_entries	temp_files&                                         r&   mainr  L  s   P 	
*+	(O v,K)&23.88@,VH4DEF.0 /@,,5) !Q.3"6F~FVWX!.!11I$qQR eJ%eW-.&&(M23 v,K$++zASAaAa/adl/lmK *cG4 	X"+Aq/ X$zz|Xtzz$'78	X	X G
=++>z>OPQ %KKa]^%Cc%I!JKKmmG[9GKGQ/~>NeTabcSddefgCD(Wa(8FG*;-89 ((* 	Ah!(^g5N"8nx7O  " -/CCOosW= J$ JEGGDJJu5ADHIJJ
 ..@AJ((I $$TD$Ak39 .U"()=)=i)H"I .Jj#@ .D$( .D!KK-.. ... +-?-S-SSL""$!,!3!3{7G7G/7Y!ZL.9.~.>?@9	A< 	+,k]+, 	9:v,K$++zASAaAa/abK %CNCSScde ,,. )J(!%h'!9$$&D!!" ! #))C"D RJ Gj#@ )A$% )D#'::<D#!)$+NN4::d3C$D	)) #c'l2N"%aS\N-JS-P)Q"RK&,mmGScRYl=[&\O!S%99M !/ @Iiw? R1%4 REGGDJJu5$ID$PQRR R%R, M!#4F>!:LL_`aKL00@AB2;-@AK)J )JP 22DE
,,^[IS)J )JV GH,ZL9:.{m<= ..@AJ(([A+,q  // X FxjPRSTRUVWWX	X 	XBJ J. .. .#	A 	A@ (,';'; !)$(!)) ) R R7)J )Js   	%[ 0$Z[ +A [4+1[A[4-,['[	3
['>A#[4$A"\5\ $\\B
\51\(A	\5\5Z=!Z82[ 8Z==[  [
[	[4[$[''[1	,[44[>\\\\\% \5(\2-\55\>__main__)N)Nz#configs/trajectory_compression.yamlNNN*   F)8rk   r  r   rH  r`   r   rR  pathlibr   typingr   r   r   r   r   dataclassesr	   r
   r   utilsr   r   firerich.progressr   r   r   r   r   r   r   rich.consoler   hermes_constantsr   r   agent.retry_utilsr   hermes_cli.env_loaderr   _hermes_home__file__r  _project_envrl   rp   r'   r)   ru   r   r   ro   rn   r  rh   Firerr   rs   r&   <module>r     s  >  	      3 3 (  :  E  E  E   A . 5 H~$$v- | F #!! ! sm! e_	!. ` ` `F )
 )
 )
X e
 e
 e
P}m }mD  7! V-V-V- V- 	V-
 V- V- V- V-r zDIIdO rs   