Ë
    áß²j  ã                  ó„   — d Z ddlmZ ddlZddlmZmZmZmZ ddl	m
Z
 dd„Z	 	 	 	 	 	 	 	 	 	 	 	 dd„Zdd„Zdd	„Zdd
lmZ y)zæTranscript repair for SessionDB batch appends: reconcile in-memory assistant rows with committed SQLite
rows (blank-row in-place update, concurrent-winner adoption, watermark-compaction clone lookup) and sync
markers after commit.é    )ÚannotationsN)ÚAnyÚCallableÚDictÚList)Ú_DB_PERSISTED_MARKERc                óº   — | €yt        | t        «      r| j                  «        S t        | t        «      r'dj	                  d„ | D «       «      j                  «        S y)zYTrue when decoded message content is None, whitespace-only, or has no visible text parts.TÚ c              3  óŒ   K  — | ]<  }t        |t        «      sŒ|j                  d «      dk(  sŒ)|j                  dd«      –— Œ> y­w)ÚtypeÚtextr
   N)Ú
isinstanceÚdictÚget)Ú.0Úps     ú</home/ubuntu/.hermes/hermes-agent/agent/transcript_repair.pyú	<genexpr>z#is_content_blank.<locals>.<genexpr>   s9   è ø€ Òq°ÄÈAÌtÕATÐYZ×Y^ÑY^Ð_eÓYfÐjpÓYp˜1Ÿ5™5 ¨×,Ñqùs   ‚A˜A­AF)r   ÚstrÚstripÚlistÚjoin)Úcontents    r   Úis_content_blankr      sQ   € à€ØÜ�'œ3ÔØ—=‘=“?Ð"Ð"Ü�'œ4Ô Ø—7‘7Ñq°gÔqÓq×wÑwÓyÐyÐyØó    c           	     ó   — g }|D ]Æ  }t        |t        «      r|j                  d«      nd}d}t        |t        «      r"|j                  dd«      dk(  rt	        | ||«      }|€|j                  |«       Œnt        |d   «      }	 ||d   «      }
|	|d<   t        |
«      r+| j                  d ||j                  d«      «      |	|f«       ŒÂ|
|d	<   ŒÈ |S )
a’  Partition a message batch within an active write transaction. An assistant message carrying an
    existing integer ``_row_id`` targets its active SQLite row (or the active clone a watermark compaction
    made of it): a blank row is updated in place; a non-blank one (concurrent winner) has its canonical
    content adopted without overwrite. Returns the messages that must be inserted as fresh rows.Ú_row_idNÚroleÚunknownÚ	assistantÚidr   zNUPDATE messages SET content = ? WHERE id = ? AND session_id = ? AND active = 1Ú_canonical_content)r   r   r   ÚintÚ_active_assistant_rowÚappendr   Úexecute)ÚconnÚ
session_idÚmessagesÚencode_content_fnÚdecode_content_fnÚinserted_rowsÚmsgÚexisting_row_idÚ
target_rowÚ	target_idÚdecodeds              r   Ú#resolve_and_repair_transcript_batchr2      så   € ð +-€MØò 0ˆÜ0:¸3ÄÔ0E˜#Ÿ'™' )Ô,È4ˆØˆ
Ü�o¤sÔ+°·±¸À	Ó0JÈkÒ0YÜ.¨t°ZÀÓQˆJØÐØ× Ñ  Ô%ØÜ˜
 4Ñ(Ó)ˆ	Ù# J¨yÑ$9Ó:ˆØ"ˆˆI‰Ü˜GÔ$Ø�L‰LðAá" 3§7¡7¨9Ó#5Ó6¸	À:ÐNõð )0ˆCÐ$Ò%ð%0ð& Ðr   c                óÜ   — | j                  d||f«      j                  «       }|�|d   dk7  ryt        |d   xs d«      dk(  r|S | j                  d||d	   |d
   f«      j                  «       S )z_The active assistant row for ``row_id``, or the active clone a watermark compaction made of it.zYSELECT id, role, active, timestamp, content FROM messages WHERE id = ? AND session_id = ?Nr   r    Úactiver   é   z¬SELECT id, role, active, timestamp, content FROM messages WHERE session_id = ? AND active = 1 AND role = 'assistant' AND timestamp IS ? AND id != ? ORDER BY id DESC LIMIT 1Ú	timestampr!   )r&   Úfetchoner#   )r'   r(   Úrow_idÚrows       r   r$   r$   :   s�   € à
�,‰,ð	*à	�Ðó÷ �hƒjð	 ð
 €{�c˜&‘k [Ò0ØÜ
ˆ3ˆx‰=Ò˜AÓ !Ò#Øˆ
à�<‰<ð	#ð 
�S˜Ñ% s¨4¡yÐ1ó÷ �hƒjðr   c                ó   — t        | |«      D ]o  \  }}d|t        <   t        |j                  d«      t        «      r|d   |d<   t        |j                  d«      t        t
        f«      r|d   |d<   d|v sŒh|d   |d<   Œq y)zZStamp _DB_PERSISTED_MARKER and sync canonical durable fields onto live dicts after commit.Tr   r6   r"   r   N)Úzipr   r   r   r#   Úfloat)Ú
batch_msgsÚ
batch_rowsÚwrittenr9   s       r   Úsync_flushed_message_markersr@   O   s†   € ä˜J¨
Ó3ò ;‰ˆ�Ø(,ˆÔ$Ñ%Ü�c—g‘g˜iÓ(¬#Ô.Ø!$ Y¡ˆG�IÑÜ�c—g‘g˜kÓ*¬S´%¨LÔ9Ø#& {Ñ#3ˆG�KÑ Ø 3Ò&Ø!$Ð%9Ñ!:ˆG�IÒñ;r   )ÚOptional)r   r   ÚreturnÚbool)r'   úsqlite3.Connectionr(   r   r)   úList[Dict[str, Any]]r*   úCallable[[Any], Any]r+   rF   rB   rE   )r'   rD   r(   r   r8   r#   )r=   rE   r>   rE   rB   ÚNone)Ú__doc__Ú
__future__r   Úsqlite3Útypingr   r   r   r   Úagent.context_compressorr   r   r2   r$   r@   rA   © r   r   ú<module>rN      sm   ðñõ #ã ß ,Ó ,å 9óðØ
ðàðð #ðð ,ð	ð
 ,ðð óóDó*	;ö  r   