Ë
    áß²jw]  ã                  ó¢   — d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	m
Z
 ddlmZmZ  ej                  d«      Zd„ Zdd„Zdd	„Z G d
„ d«      Zy)a  Micro-compaction mixin for ContextCompressor.

Rolling per-exchange summarization that folds old user/assistant exchanges into a single
summary marker between turns. OFF by default: every pass rewrites the prompt prefix and
breaks the provider prompt cache.
é    )ÚannotationsN)ÚAnyÚDictÚListÚOptional)Úestimate_messages_tokens_roughÚestimate_tokens_roughzagent.context_compressorc                 ó   — ddl m}  | S )z§The origin module, resolved lazily: avoids the import cycle and keeps tests that patch
    ``agent.context_compressor.X`` effective (attributes are read at call time).r   ©Úcontext_compressor)Úagentr   r   s    ú;/home/ubuntu/.hermes/hermes-agent/agent/micro_compaction.pyÚ_ccr      s   € õ )ØÐó    c                ó~   — t        | t        «      xr, t        | j                  t	        «       j
                  «      «      S ©N)Ú
isinstanceÚdictÚboolÚgetr   ÚCOMPRESSED_SUMMARY_METADATA_KEY©Úentrys    r   Ú_is_summary_markerr      s*   € Ü�eœTÓ"Ò]¤t¨E¯I©I´c³e×6[Ñ6[Ó,\Ó']Ð]r   c                ót   — t        | «      xr, t        | j                  t        «       j                  «      «      S )zXTrue for a summary marker provably absorbed into the rolling summary (micro, not batch).)r   r   r   r   ÚMICRO_COMPACT_MARKER_KEYr   s    r   Ú_is_micro_markerr      s(   € ä˜eÓ$ÒX¬¨e¯i©i¼»×8VÑ8VÓ.WÓ)XÐXr   c                  óø   — e Zd ZdZdd„Z	 	 	 	 	 	 	 	 dd„Zdd„Zdd„Zdd„Zdd„Z	dd„Z
dd	„Zdd
„Zdd„Zedd„«       Zd d„Zdddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d!d„Zd"d„Z	 d#	 	 	 	 	 	 	 	 	 d$d„Zed%d„«       Zd&d„Zy)'ÚMicroCompactionMixinz?Rolling micro-compaction; host must be a ``ContextCompressor``.c                óÆ  ‡ ‡— |‰ j                   cxk  r|k  r‰ j                   S  ˆˆ fd„t        ||«      D «       }t        |d¬«      }||k\  r|dz   n|}||k\  r�‰ j                  j	                  «       rdn"‰ j                  ‰|   j                  d«      «      }|r@|‰ _        d‰|   t        «       j                  <   t        j                  dt        |«      «       |‰ _         |S )	z–Index of the first message not yet absorbed into the rolling summary: the in-memory
        cursor when valid, else just past the last summary marker.c              3  óL   •K  — | ]  }‰j                  ‰|   «      sŒ|–— Œ y ­wr   )Ú_is_context_summary_message)Ú.0ÚiÚmessagesÚselfs     €€r   ú	<genexpr>z?MicroCompactionMixin._resolve_compact_cursor.<locals>.<genexpr>,   s%   øè ø€ Òm˜1¸t×?_Ñ?_Ð`hÐijÑ`kÕ?l”QÑmùs   ƒ$�$éÿÿÿÿ)Údefaulté   Ú ÚcontentTzFMicro-compaction: recovered rolling summary from transcript (%d chars))Ú_micro_compact_cursorÚrangeÚmaxÚ_micro_compact_rolling_summaryÚstripÚ_rolling_summary_from_markerr   r   r   ÚloggerÚinfoÚlen)r&   r%   Úhead_endÚ
tail_startÚ	summariesÚlastÚcursorÚ	recovereds   ``      r   Ú_resolve_compact_cursorz,MicroCompactionMixin._resolve_compact_cursor'   sâ   ù€ ð �d×0Ñ0Ô=°:Ò=Ø×-Ñ-Ð-ð >äm¤ h°
Ó ;Ômˆ	Ü�9 bÔ)ˆØ! XÒ-�˜’°8ˆØ�8Òð #×AÑA×GÑGÔI™Ø×1Ñ1°(¸4±.×2DÑ2DÀYÓ2OÓPð ñ Ø6?�Ô3ð BF�˜‘œs›u×=Ñ=Ñ>Ü—‘ÐdÔfiÐjsÓftÔuØ%+ˆÔ"Øˆr   c                ó^  ‡ ‡— t        |t        ‰«      «      }dˆˆ fd„}|}||k  r ||d«      s|dz  }||k  r
 ||d«      sŒ||k\  ry|}|dz  }||k  r ||d«      r|dz  }||k  r
 ||d«      rŒ|t        ‰«      k  r‰|   nd}t        |t        «      r|j	                  d«      dv ry||fS )a  Find the next complete exchange (full agent turn) starting at *start*; returns
        ``(exchange_start, exchange_end)`` or ``None``. Spans assistant+tool rows up to the next
        user message; user turns are never absorbed (alternation safety, verbatim user text).c                ó^   •— ‰|    j                  d«      |v xr ‰j                  ‰|    «       S )NÚrole)r   r"   )ÚidxÚrolesr%   r&   s     €€r   Ú	_turn_rowz:MicroCompactionMixin._find_one_exchange.<locals>._turn_rowF   s7   ø€ Ø˜C‘=×$Ñ$ VÓ,°Ð5Òm¸d×>^Ñ>^Ð_gÐhkÑ_lÓ>mÐ:mÐmr   )Ú	assistantr*   N)rC   Útoolr?   )r@   ÚintrA   ÚtupleÚreturnr   )Úminr5   r   r   r   )	r&   r%   Ústartr7   ÚlimitrB   r@   Úexchange_startÚboundarys	   ``       r   Ú_find_one_exchangez'MicroCompactionMixin._find_one_exchange>   sÓ   ù€ ô �J¤ H£Ó.ˆö	nð
 ˆØ�EŠk¡)¨C°Ô"@Ø�1‰HˆCð �EŠk¡)¨C°Õ"@à�%Š<ØØˆØˆq‰ˆØ�EŠk™i¨Ð-BÔCØ�1‰HˆCð �EŠk™i¨Ð-BÕCð
 %(¬#¨h«-Ò$7�8˜C’=¸TˆÜ˜(¤DÔ)¨X¯\©\¸&Ó-AÐEZÑ-ZØØ Ð$Ð$r   c                óP   — |j                  «       r|nd}d|› d|› d�}dddœd|dœgS )	z>Build the prompt messages for a single-exchange micro-summary.z(No previous summary yet.)uA  You are a summarization agent creating a compact record of an ongoing conversation.  You are given a running summary and the next exchange from the conversation.  Merge the exchange's key decisions, requirements, file paths, and open questions into the summary.  Preserve the summary's structure.  Drop resolved details that are no longer relevant.  Add new decisions, file paths, and open questions.

NEVER include API keys, tokens, passwords, secrets, credentials, or connection strings in the summary â€” replace any that appear with [REDACTED].

## Current Running Summary
z

## Next Exchange to Merge
zy

Return ONLY the updated summary text, no preamble or explanation. Do not include this instruction block in your output.Úsystemz/You are a conversation summarization assistant.)r?   r,   Úuser)r1   )r&   Úexisting_summaryÚexchange_textÚsummary_blockÚuser_prompts        r   Ú_build_micro_summary_promptz0MicroCompactionMixin._build_micro_summary_prompt\   sZ   € à,<×,BÑ,BÔ,DÑ(ÐJfˆð
+ð ,9¨/ð :*Ø*7¨ð 9DðDð 	ð" Ð*[Ñ\Ø¨Ñ4ð
ð 	
r   c                óJ  — ddl m}m} d| j                  | j                  |«      t        d| j                  xs d«      ddœ}| j                  r| j                  |d<   | j                  r[|j                  d| j                  | j                  xs d	| j                  xs d	| j                  xs d	t        | d
d	«      xs d	dœ«       	  |«       5   |di |¤Ž}ddd«       t#        «       j%                  «      dk(  rt        j'                  d«       y|j(                  d   j*                  }t-        |t.        «      r|j1                  d«      nt        |d|«      }t-        |t2        «      r|n|rt3        |«      nd	j5                  «       }ddlm}	  |	d|«      j5                  «       }|st        j!                  d«       yt#        «       j;                  ||«      rt        j'                  d«       y|S # 1 sw Y   �ŒxY w# t        $ r }t        j!                  d|«       Y d}~yd}~ww xY w)zXMicro-summarize one exchange into the rolling summary via the aux LLM (None on failure).r   )Úaux_interrupt_protectionÚcall_llmÚcompressioniÜ  gš™™™™™¹?)Útaskr%   Ú
max_tokensÚtemperatureÚmodelÚmain_runtimer+   Úapi_mode)r]   ÚproviderÚbase_urlÚapi_keyr_   Nz#micro-summarization call failed: %sÚlengthub   micro-summarization output hit the token cap (finish_reason=length) â€” discarding partial summaryr,   )Ústrip_think_blocksz*micro-summarization returned empty contentuL   micro-summarization returned refusal content â€” discarding unusable summary© )Úagent.auxiliary_clientrW   rX   rU   r0   rH   Úmax_summary_tokensÚsummary_modelr]   Ú
setdefaultr`   ra   rb   ÚgetattrÚ	Exceptionr3   r4   r   Ú_response_finish_reasonÚwarningÚchoicesÚmessager   r   r   Ústrr1   Úagent.agent_runtime_helpersrd   Ú_is_refusal_response)
r&   rR   rW   rX   Úcall_kwargsÚresponseÚexcro   r,   rd   s
             r   Ú_micro_summarize_onez)MicroCompactionMixin._micro_summarize_onet   sÞ  € çMð "Ø×8Ñ8¸×9\Ñ9\Ð^kÓlÜ˜d D×$;Ñ$;Ò$C¸tÓDØñ	
ˆð ×ÒØ#'×#5Ñ#5ˆK˜Ñ Ø�:Š:Ø×"Ñ" >ØŸ™°·±Ò1DÀ"ÐRV×R_ÑR_ÒReÐceØŸ<™<Ò-¨2¼7À4ÈÐUWÓ;XÒ;^Ð\^ñ4ô ð
	Ù)Ó+ñ 3Ù#Ñ2 kÑ2�÷3ô ‹5×(Ñ(¨Ó2°hÒ>Ü�N‰NØtôð à×"Ñ" 1Ñ%×-Ñ-ˆÜ,6°wÄÔ,E�'—+‘+˜iÔ(Ì7ÐSZÐ\eÐgnÓKoˆÜ(¨´#Ô6‘7ÉG¼CÀ¼LÐY[×bÑbÓdˆåBÙ$ T¨7Ó3×9Ñ9Ó;ˆÙÜ�K‰KÐDÔEØÜ‹5×%Ñ% h°Ô8Ü�N‰NÐiÔjØØˆ÷33ñ 3ûäò 	Ü�K‰KÐ=¸sÔCÜûð	ús0   ÃG9 Ã	G,ÃG9 Ç,G6Ç1G9 Ç9	H"ÈHÈH"c                óF   — t        | j                  «      | j                  k\  S )z?Return True when the rolling summary is large enough to defrag.)r	   r0   Ú&_micro_compact_defrag_threshold_tokens©r&   s    r   Ú_needs_defragz"MicroCompactionMixin._needs_defrag¢   s   € ä$ T×%HÑ%HÓIÈT×MxÑMxÑxÐxr   c                ó–  — | j                   }|j                  «       syd| _         | j                  |«      }|xs || _         |syt        d„ t	        |«      D «       d«      }|�?| j                  |«      |d<   |j                  t        «       j                  d«       d| _	        t        j                  dt        |«      t        |«      «       y)z¢Re-summarize the rolling summary text and rewrite the marker in place.
        Transcript-shape-neutral (no splice, no cursor move). Returns True when it rewrote.Fr+   c              3  ó8   K  — | ]  }t        |«      sŒ|–— Œ y ­wr   )r   )r#   Úes     r   r'   z?MicroCompactionMixin._defrag_rolling_summary.<locals>.<genexpr>´   s   è ø€ ÒK˜AÔ7GÈÕ7J”aÑKùs   ‚“Nr,   TzGMicro-compaction defrag: rolling summary re-summarized (%d -> %d chars))r0   r1   rv   ÚnextÚreversedÚ_render_micro_marker_contentÚpopr   Ú_DB_PERSISTED_MARKERÚ_flush_scan_cursor_invalidatedr3   r4   r5   )r&   r%   Úold_summaryÚfresh_summaryr   s        r   Ú_defrag_rolling_summaryz,MicroCompactionMixin._defrag_rolling_summary¦   sÂ   € ð ×9Ñ9ˆØ× Ñ Ô"Øà.0ˆÔ+Ø×1Ñ1°+Ó>ˆØ.;Ò.J¸{ˆÔ+ÙØô ÑK¤¨(Ó!3ÔKÈTÓRˆØÐØ#×@Ñ@ÀÓOˆE�)Ñð �I‰I”c“e×0Ñ0°$Ô7ð 37ˆDÔ/Ü�‰ØUÜ�Óœc -Ó0ô	
ð r   c                ó    — d| _         d| _        y )Nr   r(   )Ú#_micro_compact_consecutive_failuresÚ"_micro_compact_last_failure_cursorry   s    r   Ú_reset_micro_failure_trackingz2MicroCompactionMixin._reset_micro_failure_trackingÇ   s   € Ø34ˆÔ0Ø24ˆÕ/r   c                ó  ‡ ‡‡‡— ‰ j                   s|S t        dt        ‰ j                  xs d«      «      }|dkD  r-‰ xj                  dz  c_        ‰ j                  |k  r|S d‰ _        t        |«      Š‰dk\  r‰ j                  |«      nd}|€|S |\  }}t        j                  «       Št        |«      Šdˆˆˆˆ fd„}‰ j                  «       rP‰ j                  |«      }|r!‰ j                  |«       ‰ j                  «        |rdnd} |||t        |«      ¬«       |S t        ‰ j                  j!                  «       «      }	‰ j#                  ||| «      }
t%        |
«      }‰ j'                  |
«      }|€ ‰ j)                  ||«      } |||‰|¬	«       |S |‰ _        |‰ _        ‰ j                  «        ‰ j-                  ||||	¬
«      }‰ j/                  ||dz   «      ‰ _        ‰ j                  |«        |d|t        |«      |¬	«       |S )zîRun one round of micro-compaction (entry point from ``finalize_turn()``). Returns the
        (possibly modified) list and syncs the session DB via ``archive_and_compact`` (the
        append-only flush alone would double-load on resume).r*   r   é   Nc                óŠ   •—  ‰j                   d| ‰t        |«      ‰t        t        j                  «       ‰z
  dz  «      dœ|¤Ž y )Niè  )ÚoutcomeÚmessages_beforeÚmessages_afterÚtokens_beforeÚduration_msre   )Ú _emit_micro_compaction_telemetryr5   rE   ÚtimeÚ	monotonic)rŽ   ÚresultÚextraÚ_started_atÚ_tokens_beforeÚ
n_messagesr&   s      €€€€r   Ú
_telemetryz7MicroCompactionMixin._micro_compact.<locals>._telemetryå   sI   ø€ Ø1ˆD×1Ñ1ð Ø°ÌCÐPVËKØ,¼#¼t¿~¹~Ó?OÐR]Ñ?]ÐaeÑ>eÓ:fñàjoór   ÚdefragÚdefrag_failed)Útokens_after)rž   Úexchange_tokens)Ú	supersedeÚabsorbed)rŽ   rp   r–   úList[Dict[str, Any]]r—   r   rG   ÚNone)Ú_micro_compact_enabledr/   rE   Ú_micro_compact_every_n_turnsÚ_micro_compact_turns_since_passr5   Ú_next_exchanger”   r•   r   rz   r†   Ú_sync_micro_compact_to_dbrŠ   r   r0   r1   Ú_serialize_for_summaryr	   rv   Ú_record_micro_failurer-   Ú_splice_micro_compact_resultÚ_cursor_after_splice)r&   r%   Úevery_nÚexchangerK   Úexchange_endr›   Ú	defraggedrŽ   Ú_cumulativerR   Ú_exchange_tokensÚupdated_summaryÚ_outcomer–   r˜   r™   rš   s   `              @@@r   Ú_micro_compactz#MicroCompactionMixin._micro_compactË   s  û€ ð ×*Ò*ØˆOô �aœ˜T×>Ñ>ÒCÀ!ÓDÓEˆØ�QŠ;Ø×0Ò0°AÑ5Õ0Ø×3Ñ3°gÒ=Ø�Ø34ˆDÔ0ä˜“]ˆ
Ø4>À!²O�4×&Ñ& xÔ0ÈˆØÐØˆOØ'/Ñ$ˆ˜ô —n‘nÓ&ˆÜ7¸ÓAˆ÷	ð 	ð ×ÑÔØ×4Ñ4°XÓ>ˆIÙØ×.Ñ.¨xÔ8Ø×2Ñ2Ô4Ù"+‘h°ˆGÙ�w Ô7UÐV^Ó7_Õ`ØˆOô ˜4×>Ñ>×DÑDÓFÓGˆà×3Ñ3°H¸^ÈLÐ4YÓZˆÜ0°Ó?ÐØ×3Ñ3°MÓBˆØÐ"Ø×1Ñ1°.À,ÓOˆHÙ�x ¸ÐXhÕiØˆOà.=ˆÔ+Ø%1ˆÔ"Ø×*Ñ*Ô,à×2Ñ2°8¸^È\ÐepÐ2ÓqˆØ%)×%>Ñ%>¸vÀ~ÐXYÑGYÓ%ZˆÔ"Ø×&Ñ& vÔ.ÙØ˜Ô-KÈFÓ-SÐeuõ	
ð ˆr   c                ó  — || j                   k(  }|r| j                  dz   nd| _        || _         | j                  t        «       j                  k  ryt        j                  d|| j                  «       || _        | j                  «        y)zTCount a summarize failure at this cursor; skip the exchange after too many in a row.r*   Úsummarize_failedzNMicro-compaction: skipping exchange at cursor %d after %d consecutive failuresÚexchange_skipped)r‰   rˆ   r   Ú'_MICRO_COMPACT_MAX_CONSECUTIVE_FAILURESr3   r4   r-   rŠ   )r&   rK   r¯   Úsame_cursors       r   rª   z*MicroCompactionMixin._record_micro_failure  s�   € ð %¨×(OÑ(OÑOˆÙcn°4×3[Ñ3[Ð^_Ò3_ÐtuˆÔ0Ø2@ˆÔ/Ø×3Ñ3´c³e×6cÑ6cÒcØ%Ü�‰Ø\Ø˜D×DÑDô	
ð
 &2ˆÔ"Ø×*Ñ*Ô,Ø!r   c                óÒ   — | j                  || j                  |«      «      }| j                  ||d¬«      }||k\  ry| j                  |||«      }||k\  rdS | j	                  |||«      S )zFThe next un-absorbed exchange inside the compressible window, or None.F)Úallow_split_turnN)Ú_align_boundary_forwardÚ_protect_head_sizeÚ_find_tail_cut_by_tokensr<   rM   )r&   r%   Úcompress_startÚcompress_endr:   s        r   r§   z#MicroCompactionMixin._next_exchange  sz   € à×5Ñ5°hÀ×@WÑ@WÐX`Ó@aÓbˆØ×4Ñ4°X¸~Ð`eÐ4ÓfˆØ˜\Ò)ØØ×-Ñ-¨h¸ÈÓUˆØ Ò-ˆtÐj°4×3JÑ3JÈ8ÐU[Ð]iÓ3jÐjr   c                óX  — t        «       }t        | t        «      r| j                  «       sy| j	                  |j
                  «      }|dk7  r| |t        |j
                  «      z   d n| }|j                  |j                  «      }|dk7  r|d| j                  «       S |j                  «       S )zLRecover the rolling-summary text from a summary marker (resume rehydration).r+   r(   N)	r   r   rp   r1   ÚrfindÚHISTORICAL_TASK_HEADINGr5   ÚfindÚ_SUMMARY_END_MARKER)r,   Úccr@   ÚbodyÚends        r   r2   z1MicroCompactionMixin._rolling_summary_from_marker'  s—   € ô ‹UˆÜ˜'¤3Ô'¨w¯}©}¬Øà�m‰m˜B×6Ñ6Ó7ˆØBEÈÂ)ˆw�sœS ×!;Ñ!;Ó<Ñ<Ð=Ñ>ÐQXˆØ�i‰i˜×.Ñ.Ó/ˆØ! Rši��T�c�
×8Ñ8Ó:Ð:¨T×8Ñ8Ó:Ð:r   c                ó\   ‡— t        ˆfd„t        t        ‰«      dz
  dd«      D «       |«      S )a  Cursor position just past the summary marker in *result*. Must derive from the SPLICED
        list: a splice collapses several rows into one marker (and may drop a superseded one), so
        pre-splice indices land inside a later exchange and silently skip it.c              3  óF   •K  — | ]  }t        ‰|   «      sŒ|d z   –— Œ y­w)r*   N)r   )r#   r@   r–   s     €r   r'   z<MicroCompactionMixin._cursor_after_splice.<locals>.<genexpr>7  s$   øè ø€ Òj ÔJ\Ð]cÐdgÑ]hÕJi�S˜1•WÑjùs   ƒ!—
!r*   r(   )r~   r.   r5   )r&   r–   Úfallbacks    ` r   r¬   z)MicroCompactionMixin._cursor_after_splice3  s*   ø€ ô Ój¬¬c°&«k¸A©o¸rÀ2Ó(FÔjÐltÓuÐur   N)rŸ   r’   c               óR  — t        «       j                  }	 |�|�||z
  nd}	| xj                  |	xs dz  c_        | xj                  dz  c_        | j                  }
|
xr |duxr |
dkD  }|rt        ||
z  dz  d«      nd}i dd“dt        | dd	«      xs d	“d
|“d|“d|“d ||«      “d ||«      “d ||	«      “d ||«      “dt        | j                  «      “d || j                  «      “d| j                  “d| j                  “d ||«      “d ||
«      “d || j                  «      “d|“| j                  xs d	| j                  xs d	dœ¥}t        j                  dt        j                   |dd¬«      «       y# t"        $ r }t        j%                  d|«       Y d}~yd}~ww xY w)z¢Emit one content-free JSON log line for a micro-compaction pass.
        ``tokens_delta`` < 0 means the pass shrank the transcript; ``*_total`` fields accumulate.Nr   r*   éd   ÚeventÚmicro_compactionÚ
session_idÚ_session_idr+   rŽ   r�   r�   r‘   rž   Útokens_deltarŸ   Úrolling_summary_tokensr:   Úpasses_totalÚtokens_saved_totalr’   Úthreshold_tokensÚcontext_limitÚoccupancy_pct)Ú
main_modelÚ	aux_modelzmicro compaction telemetry: %sT)ú,ú:)Ú	sort_keysÚ
separatorsz-failed to emit micro-compaction telemetry: %s)r   Ú	_safe_intÚ!_micro_compact_tokens_saved_totalÚ_micro_compact_passesÚ_threshold_tokensÚroundrj   r	   r0   r-   Ú_resolved_context_lengthr]   rh   r3   r4   ÚjsonÚdumpsrk   Údebug)r&   rŽ   r�   r�   r‘   rž   rŸ   r’   rà   ÚdeltaÚ	thresholdÚhas_occupancyÚ	occupancyÚpayloadru   s                  r   r“   z5MicroCompactionMixin._emit_micro_compaction_telemetry9  s-  € ô “E—O‘Oˆ	ð	OØ4AÐ4MÐR^ÐRj�L =Ò0ÐptˆEØ×2Ò2°e²j¸qÑ@Õ2Ø×&Ò&¨!Ñ+Õ&ð
 ×.Ñ.ˆIØ%ÒT¨,¸dÐ*BÒTÀyÐSTÁ}ˆMÙDQœ˜l¨YÑ6¸Ñ<¸aÔ@ÐW[ˆIðØÐ+ðØ-9¼7À4ÈÐXZÓ;[Ò;aÐ_aðØclÐnuðà! ?ðà4DÀnðð  ¡¨=Ó!9ðð <JÉ9ÐUaÓKbðð ¡	¨%Ó 0ð	ð 3DÁYÈÓE_ð	ð
 )Ô*?À×@cÑ@cÓ*dðð ™) D×$>Ñ$>Ó?ðð BPÐQU×QkÑQkðð % d×&LÑ&Lðð O\Ñ]fÐgrÓ]sðð #¡I¨iÓ$8ðð ;JÉ9ÐUY×UrÑUrÓKsðð   ðð ;?¿*¹*Ò:JÈÐY]×YkÑYkÒYqÐoqòˆGô �K‰KÐ8¼$¿*¹*ÀWÐX\ÐisÔ:tÕuøÜò 	OÜ�L‰LÐHÈ#×NÑNûð	Oús   –E&E= Å=	F&ÆF!Æ!F&c           
     ó  — t        | dd«      t        | dd«      }}|r|sy	 |j                  ||t        dt        |«      dz
  «      ¬«       t	        «       j                  |«       y# t        $ r t        j                  d«       Y yw xY w)	zÙPersist the micro-compacted set to the session DB atomically and stamp rows persisted.
        Without this the old exchange rows stay ``active=1`` and a resume double-loads both the
        summary and the originals.Ú_session_dbNrÒ   r+   r   r*   )Ú
tail_countuo   Micro-compaction DB sync failed â€” resume will double-load compacted messages until the next batch compression)	rj   Úarchive_and_compactr/   r5   r   Ústamp_db_persisted_markersrk   r3   r4   )r&   Úcompacted_messagesÚ
session_dbrÑ   s       r   r¨   z.MicroCompactionMixin._sync_micro_compact_to_db[  sŽ   € ô ")¨¨}¸dÓ!CÄWÈTÐS`ÐbdÓEe�Jˆ
Ù¡Øð
	à×*Ñ*¨:Ð7IÔVYÐZ[Ô]`ÐasÓ]tÐwxÑ]xÓVyÐ*Ôzô ‹E×,Ñ,Ð-?Õ@øÜò 	Ü�K‰KðFöð	ús   ¡AA% Á%BÂBc           
     óÈ  — t        «       }| j                  }|j                  «       s|S ddd| j                  |«      |j                  d|j
                  d|j                  di}|d| |gz   ||d z   }|r-t        |«      D �	�
cg c]  \  }	}
t        |
«      sŒ|	‘Œ c}
}	dd ng }|r2| j                  t        |«      D �	�
cg c]  \  }	}
|	|vsŒ|
‘Œ c}
}	«      }|S c c}
}	w c c}
}	w )zµReplace *messages[splice_start:splice_end]* with an assistant-role summary marker.
        Merges user turns left adjacent by a superseded marker so the result is alternation-valid.r?   rC   r,   TFNr(   )
r   r0   r1   r€   r   r   Ú$COMPRESSED_SUMMARY_HAS_USER_TURN_KEYÚ	enumerater   Ú_merge_adjacent_user_turns)r&   r%   Úsplice_startÚ
splice_endr    rÇ   Úsummary_textÚsummary_msgr–   r$   ÚmÚstales               r   r«   z1MicroCompactionMixin._splice_micro_compact_resultn  s÷   € ô
 ‹UˆØ×:Ñ:ˆØ×!Ñ!Ô#ØˆOð �K ¨D×,MÑ,MÈlÓ,[Ø×.Ñ.°à×'Ñ'¨à×3Ñ3°Uð
ˆð ˜-˜<Ð(¨K¨=Ñ8¸8ÀJÀKÐ;PÑPˆñ R[œy¨Ó0×H‘t�q˜!Ô4DÀQÕ4G’ÓHÈÈ"ÑMÐ`bˆÙØ×4Ñ4ÄIÈfÓDU×5h¹D¸A¸qÐYZÐbgÒYg²aÓ5hÓiˆFð ˆùó Iùã5hs   ÂCÂCÂ=C
Ã
C
c                óˆ   — t        «       }|j                  › d|j                  › d| j                  «       › d|j                  › �S )z:Assemble the marker content wrapper around *summary_text*.ú

Ú
)r   ÚSUMMARY_PREFIXrÄ   r1   rÆ   )rû   rÇ   s     r   r€   z1MicroCompactionMixin._render_micro_marker_contentŒ  sI   € ô ‹UˆØ×#Ñ#Ð$ D¨×)CÑ)CÐ(DÀBÀ|×GYÑGYÓG[ÐF\Ð\`Ðac×awÑawÐ`xÐyÐyr   c                ó.  — ddl m} d
d„}g }|D ]ƒ  }|r|d   nd} ||«      r_ ||«      rWdj                  d„ |d   |d   fD «       «      |d<    ||«       |j                  t	        «       j
                  d«       d	| _        Œs|j                  |«       Œ… |S )zõMerge consecutive plain-text real user turns left by a supersede. Same ``\n\n`` join as
        ``repair_message_sequence`` pass 2, done here so the marker and cursor are never collateral
        damage of the downstream repair. Lists untouched.r   )Údrop_stale_api_contentc                ó¬   — t        | t        «      xrC | j                  d«      dk(  xr- t        | «       xr t        | j                  d«      t        «      S )Nr?   rP   r,   )r   r   r   r   rp   )rý   s    r   Ú_plain_userzDMicroCompactionMixin._merge_adjacent_user_turns.<locals>._plain_user˜  sN   € ä˜1œdÓ#ò 6¨¯©¨f«¸Ñ(?ò 6ÔHZÐ[\ÓH]ÐD]ò 6Ü˜qŸu™u YÓ/´Ó5ðr   r(   Nr   c              3  ó&   K  — | ]	  }|sŒ|–— Œ y ­wr   re   )r#   Úcs     r   r'   zBMicroCompactionMixin._merge_adjacent_user_turns.<locals>.<genexpr>¢  s   è ø€ Ò-`°AÒ^_¬aÑ-`ùs   ‚Šr,   T)rý   r   rG   r   )Úagent.turn_contextr  Újoinr�   r   r‚   rƒ   Úappend)r&   r–   r  r  ÚmergedÚmsgÚprevs          r   rø   z/MicroCompactionMixin._merge_adjacent_user_turns’  sž   € õ 	>ó	ð (*ˆØò 	#ˆCÙ!'�6˜"’:¨TˆDÙ˜3Ô¡K°Ô$5Ø"(§+¡+Ñ-`¸$¸y¹/È3ÈyÉ>Ð9ZÔ-`Ó"`��Y‘Ù& tÔ,ð
 —‘œ›×3Ñ3°TÔ:Ø6:�Õ3à—‘˜cÕ"ð	#ð ˆr   )r%   r¢   r6   rE   r7   rE   rG   rE   )r%   r¢   rI   rE   r7   rE   rG   úOptional[tuple[int, int]])rQ   rp   rR   rp   rG   zList[Dict[str, str]])rR   rp   rG   zOptional[str])rG   r   )r%   r¢   rG   r   )rG   r£   )r%   r¢   rG   r¢   )rK   rE   r¯   rE   rG   rp   )r%   r¢   rG   r  )r,   r   rG   rp   )r–   r¢   rÌ   rE   rG   rE   )rŽ   rp   r�   rE   r�   rE   r‘   ú
int | Nonerž   r  rŸ   r  r’   r  rG   r£   )ró   r¢   rG   r£   )T)
r%   r¢   rù   rE   rú   rE   r    r   rG   r¢   )rû   rp   rG   rp   )r–   r¢   rG   r¢   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r<   rM   rU   rv   rz   r†   rŠ   rµ   rª   r§   Ústaticmethodr2   r¬   r“   r¨   r«   r€   rø   re   r   r   r   r   $   s&  „ ÙIóð.%Ø,ð%Ø58ð%ØFIð%à	"ó%ó<
ó0,ó\yóóB5ó@óD"ó"kð ò	;ó ð	;óvð AEÐ`dñ OØð OØ03ð OØEHð OØYcð Oà ð Oà3=ð OàS]ð Oð 
ó OóDð( eiðØ,ðØ<?ðØMPðØ]aðà	óð< òzó ðzô
r   r   )r   r   rG   r   )r  Ú
__future__r   ræ   Úloggingr”   Útypingr   r   r   r   Úagent.model_metadatar   r	   Ú	getLoggerr3   r   r   r   r   re   r   r   ú<module>r     sS   ðñõ #ã Û Û ß ,Ó ,ç Vð 
ˆ×	Ñ	Ð5Ó	6€òó^óY÷
Hò Hr   